python 3 argparse call a function

2019-07-31 06:13发布

问题:

I wanted to create a commandline-like / shell-like interface in python3.

Argparse seems to do the job of parsing and displaying the help/error messages. According to the python3 documentation of argparse, there is a func= argument that can be used to get your function called by argparse.

# sub-command functions
def foo(args):
   print(args.x * args.y)
def bar(args):
    print('((%s))' % args.z)
# create the top-level parser
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# create the parser for the "foo" command
parser_foo = subparsers.add_parser('foo')
parser_foo.add_argument('-x', type=int, default=1)
parser_foo.add_argument('y', type=float)
parser_foo.set_defaults(func=foo)
# create the parser for the "bar" command
parser_bar = subparsers.add_parser('bar')
parser_bar.add_argument('z')
parser_bar.set_defaults(func=bar)

But as far as I can tell help_parser.set_defaults(func=foo) does not call my funciton. It would be appreciated if you could help me.

You can reproduce the issue by running the program with python3, typing help and then press [Enter]. It does not print hello as expected. Thanks!

def foo():
    print('hello')


class Console:
    def __init__(self):
        """Console like interface for navigating and interacting with the external file system."""
        parser = argparse.ArgumentParser(
            description='Console like interface for navigating and interacting with the external file system.',
            add_help=False)
        subparsers = parser.add_subparsers(dest='command')
        subparsers.required = True

        help_parser = subparsers.add_parser('help')
        help_parser.add_argument('-x', type=int, default=1)
        help_parser.set_defaults(func=foo)

        setting_parser = subparsers.add_parser('settings')
        setting_subparsers = setting_parser.add_subparsers(dest='settings_command')
        setting_subparsers.required = True

        setting_save_parser = setting_subparsers.add_parser('save', help='Save the current settings in a .json file.')
        setting_save_parser.add_argument('file', type=str, nargs='?', default='settings.json')

        setting_load_parser = setting_subparsers.add_parser('load', description='Load the last settings from a .json file.')
        setting_load_parser.add_argument('file', type=str, nargs='?', help='settings.json')

        setting_set_parser = setting_subparsers.add_parser('set')
        setting_set_parser.add_argument('--host', type=str, required=True)
        setting_set_parser.add_argument('-u', '--username', type=str, required=True)
        setting_set_parser.add_argument('-p', '--password', type=str, required=True)
        setting_set_parser.add_argument('-x', '--proxy', type=str, required=False)

        while True:
            try:
                print('', flush=True, sep='')
                data = input('>>>').split(' ')
                print('your command:', data)
                parser.parse_args(data)
            except SystemExit:
                pass

if __name__ == '__main__':
    """Spawn an commandline like interface."""
    c = Console()

回答1:

Actually argparse won't call the method automatically - you have to do it yourself. All it does it adds the method to the func attribute of the args. So, what you could do is to check if func attribute exists and then invoke it as following:

args = parser.parse_args(data)
if hasattr(args, 'func'):
    args.func()


回答2:

I found out how to make it work: The args.func() will call the function that got selected by argparse.

print('', flush=True, sep='')
data = input('>>>').split(' ')
print('your command:', data)
args = parser.parse_args(data)
print(args)
args.func()

Commandline log:

>>>help
your command: ['help']
Namespace(command='help', func=<function foo at 0x0000023C3737F7B8>, x=1)
hello