Call another click command from a click command
<p>I want to use some useful functions as commands. For that I am testing the <code>click</code> library. I defined my three original functions then decorated as <code>click.command</code>:</p>

<pre><code>import click
import os, sys

@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_name(content, to_stdout=False):
    if not content:
        content = ''.join(sys.stdin.readlines())
    result = content + "\n\tadded name"
    if to_stdout is True:
        sys.stdout.writelines(result)
    return result


@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_surname(content, to_stdout=False):
    if not content:
        content = ''.join(sys.stdin.readlines())
    result = content + "\n\tadded surname"
    if to_stdout is True:
        sys.stdout.writelines(result)
    return result

@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=False)
def add_name_and_surname(content, to_stdout=False):
    result = add_surname(add_name(content))
    if to_stdout is True:
        sys.stdout.writelines(result)
    return result
</code></pre>

<p>This way I am able to generate the three commands <code>add_name</code>, <code>add_surname</code> and <code>add_name_and_surname</code> using a <code>setup.py</code> file and <code>pip install --editable .</code> Then I am able to pipe:</p>

<pre><code>$ echo "original content" | add_name | add_surname 
original content

    added name
    added surname
</code></pre>

<p>However there is one slight problem I need to solve, when composing with different click commands as functions:</p>

<pre><code>$echo "original content" | add_name_and_surname 
Usage: add_name_and_surname [OPTIONS] [CONTENT]

Error: Got unexpected extra arguments (r i g i n a l   c o n t e n t 
)
</code></pre>

<p>I have no clue why it does not work, I need this <code>add_name_and_surname</code> command to call <code>add_name</code> and <code>add_surname</code> not as command but as functions, else it defeats my original purpose of using functions as both  library functions and commands. </p>

<p>When you call <code>add_name()</code> and <code>add_surname()</code> directly from another function, you actually call the decorated versions of them so the arguments expected may not be as you defined them (see the answers to <a href="http://stackoverflow.com/questions/1166118/how-to-strip-decorators-from-a-function-in-python">How to strip decorators from a function in python</a> for some details on why). </p>

<p>I would suggest modifying your implementation so that you keep the original functions undecorated and create thin click-specific wrappers for them, for example: </p>

<pre><code>def add_name(content, to_stdout=False):
    if not content:
        content = ''.join(sys.stdin.readlines())
    result = content + "\n\tadded name"
    if to_stdout is True:
        sys.stdout.writelines(result)
    return result

@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_name_command(content, to_stdout=False):
    return add_name(content, to_stdout)
</code></pre>

<p>You can then either call these functions directly or invoke them via a CLI wrapper script created by setup.py. </p>

<p>This might seem redundant but in fact is probably the right way to do it: one function represents your business logic, the other (the click command) is a "controller" exposing this logic via command line (there could be, for the sake of example, also a function exposing the same logic via a Web service for example). </p>

<p>In fact, I would even advise to put them in separate Python modules - Your "core" logic and a click-specific implementation which could be replaced for any other interface if needed.</p>

python command-line-arguments stdout piping python-click