How do I return a value when @click.option is used to pass a command line argument to a function?

后端 未结 4 2145
慢半拍i
慢半拍i 2021-02-20 04:31

I am trying to use click python package to pass a command line argument to a function. The example from official documentation works as explained. But nowhere in the documentati

相关标签:
4条回答
  • 2021-02-20 04:45

    Apparently this click package makes your hello() function never return. So the print never happens. If I were you, I would not use this unintuitive package and instead use argparse which is great at command line processing in Python (one of the best in any language, in my opinion).

    Here's a working version of your code using argparse. It works out-of-the-box with Python (any version 2.7 or later), and it's easy to understand.

    def hello(count):
        """Simple program that greets NAME for a total of COUNT times."""
        for x in range(count):
            print('Hello')
        return "hello hi"
    
    if __name__ == '__main__':
        import argparse
        parser = argparse.ArgumentParser(description=__doc__)
        parser.add_argument('--count', default=3, type=int, help='Number of greetings.')
        args = parser.parse_args()
    
        print(hello(args.count))
    
    0 讨论(0)
  • 2021-02-20 04:58

    Unfortunately, what you're trying to do doesn't make sense. Command-line programs can have an exit code, but that's just a small integer; they can't return text, or arbitrary Python objects.

    There's a quasi-standard for what these integers means; the simple version is 0 for success, 1 for most errors, 2 for invalid command-line arguments. click is trying to make your function into a good command-line citizen, so when you exit your function, it calls sys.exit with the appropriate number (0 if you return, 1 if you raise, and 2 if it failed to parse your arguments).

    So, whatever you return has no effect, and whatever you try to do with the return value at the top level doesn't even get run.

    What programs usually do when they need to "return" text is to print it to standard output, which is exactly what click.echo is for.

    0 讨论(0)
  • 2021-02-20 04:59

    After looking through click's source code/reference I stumbled across the main() method of BaseCommand which takes the parameter, standalone_mode, that allows you to return values if disabled (it is True by default). Hope this helps someone in the future.

    Setup code:

    import sys
    import click
    
    @click.group(invoke_without_command=True)
    @click.option('--option1')
    @click.argument('arg1')
    def main(option1, arg1):
        class SpecialObject():
            def __init__(self, option, arg):
                self.option = option
                self.arg = arg
            def __repr__(self):
                return str(self.option)+str(self.arg)
    
        return SpecialObject(option1, arg1)
    
    @main.command()
    def subcmd():
        return [4,5,6]
    

    Test code:

    if __name__ == "__main__":
        commands = (
            ["--help"], 
            ["arg_val",],
            ["--option1","option1_val","arg1_val"],
            ["arg_val","subcmd"],
            ["arg_val","subcmd", "--help",], 
        )
        print(f'Click Version: {click.__version__}')
        print(f'Python Version: {sys.version}')
        for cmd in commands:
            print('-----------')
            print(f'Starting cmd:{cmd}')
            ret_val = main.main(cmd, standalone_mode=False)
            print(f"Returned: {type(ret_val)}, {ret_val}\n"
    

    Output:

    $ python __main__.py
    Click Version: 7.1.2
    Python Version: 3.9.1 (default, Dec 11 2020, 09:29:25) [MSC v.1916 64 bit (AMD64)]
    -----------
    Starting cmd:['--help']
    Usage: __main__.py [OPTIONS] ARG1 COMMAND [ARGS]...
    
    Options:
      --option1 TEXT
      --help          Show this message and exit.
    
    Commands:
      subcmd
    Returned: <class 'int'>, 0
    
    -----------
    Starting cmd:['arg_val']
    Returned: <class '__main__.main.<locals>.SpecialObject'>, Nonearg_val
    
    -----------
    Starting cmd:['--option1', 'option1_val', 'arg1_val']
    Returned: <class '__main__.main.<locals>.SpecialObject'>, option1_valarg1_val
    
    -----------
    Starting cmd:['arg_val', 'subcmd']
    Returned: <class 'list'>, [4, 5, 6]
    
    -----------
    Starting cmd:['arg_val', 'subcmd', '--help']
    Usage: __main__.py subcmd [OPTIONS]
    
    Options:
      --help  Show this message and exit.
    Returned: <class 'int'>, 0
    
    0 讨论(0)
  • 2021-02-20 05:00

    You have to tell click to print to stdout using click.echo(). Here is a working example using the code in your question (without caring about exit code as others have mentioned):

    import click
    
    
    @click.command()
    @click.option('--count', default=3, help='Number of greetings.')
    def hello(count):
        """Simple program that greets NAME for a total of COUNT times."""
        for x in range(count):
            click.echo('Hello')
        return click.echo("hello hi")
    
    if __name__ == '__main__':
        hello()
    
    0 讨论(0)
提交回复
热议问题