Package: argcat
ArgCat - A cute helper for argparse in Python 3ArgCatis a tiny tool designed to make it more joyful to useargparsemodule in Python 3.As a bridge between developer andargparsemodule, it wrapsargparseand tries to take on all the "dirty works" for you, improving both the ''building" and "handling" parts of anargparseprocess, allowing you to focus more on business logic without worring about creating and configuring parsers and arguments ofargparsein command-line interfaces.InstallationpipinstallargcatOnce installation done, you should get av0.4.xversion in your python package library , as the latest stable version isv0.4.x.FeaturesBuild parsers and arguments ofargparsein a more straightforward and clearer wayA typical code snippet to create a program supports sub-commands usingargparse:(Snippet from "Sub-commands" section inargparse)# Create the top-level parserparser=argparse.ArgumentParser(prog='PROG')parser.add_argument('--foo',action='store_true',help='foo help')subparsers=parser.add_subparsers(help='sub-command help')# Create the parser for the "a" commandparser_a=subparsers.add_parser('a',help='a help')parser_a.add_argument('bar',type=int,help='bar help')# Create the parser for the "b" commandparser_b=subparsers.add_parser('b',help='b help')parser_b.add_argument('--baz',choices='XYZ',help='baz help')# Parse some argument listsparser.parse_args(['a','12'])parser.parse_args(['--foo','b','--baz','Z'])But, using ArgCatargcat=ArgCat()# Build parsers and argumentswithargcat.build()asbuilder:# Set descriptive information of the programbuilder.set_prog_info(prog='PROG')builder.set_subparsers_info(help='sub-command help')# Add an argument to the main parserbuilder.main_parser().add_argument('--foo',action='store_true',help='foo help')# Create the parser for the "a" commandbuilder.add_subparser('a',help='a help')builder.subparser('a').add_argument('bar',type=int,help='bar help')# Create the parser for the "b" commandbuilder.add_subparser('b',help='b help')builder.subparser('b').add_argument('--baz',choices='XYZ',help='baz help')# Parse some argument listsargcat.parse_args(['a','12'])argcat.parse_args(['--foo','b','--baz','Z'])Handle parsed result fromargparsedirectly and easilyA typical code snippet to create a program supports sub-commands and handles the parsed result usingargparse:(Snippet from "Sub-commands" section inargparse)# Sub-command functionsdeffoo(args):print(args.x*args.y)defbar(args):print('((%s))'%args.z)# Create the top-level parserparser=argparse.ArgumentParser()subparsers=parser.add_subparsers()# Create the parser for the "foo" commandparser_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" commandparser_bar=subparsers.add_parser('bar')parser_bar.add_argument('z')parser_bar.set_defaults(func=bar)# Parse the args and call whatever function was selectedargs=parser.parse_args('foo 1 -x 2'.split())args.func(args)# Parse the args and call whatever function was selectedargs=parser.parse_args('bar XYZYX'.split())args.func(args)Instead, using ArgCat# Sub-command handler functions.# Note that the parameters of the functions should be the dests of the arguments for# the parsers. ArgCat helps you to route the argument's inputs from the parsed args into# the parsers' handler functions respectively.deffoo(x,y):print(x*y)defbar(z):print('((%s))'%z)argcat=ArgCat()withargcat.build()asbuilder:# Create the parser for the "foo" command.builder.add_subparser('foo')builder.subparser('foo').add_argument('-x',type=int,default=1)builder.subparser('foo').add_argument('y',type=float)# Create the parser for the "bar" command.builder.add_subparser('bar')builder.subparser('bar').add_argument('z')# Set handler functions for receiving and processing parsed result.argcat.set_parser_handler('foo',foo)argcat.set_parser_handler('bar',bar)# Parse the args and the handler function `foo()` will be called with required# parameters automatically.argcat.parse_args('foo 1 -x 2'.split())# Parse the args and the handler function `bar()` will be called with required# parameters automatically.argcat.parse_args('bar XYZYX'.split())And, if you would like to set all handler functions at once, using ArgCat# Sub-command handler functions, which are decorated for the respective parsers.@ArgCat.handler(parser_name='foo')defdecorated_foo(x,y):print(x*y)@ArgCat.handler(parser_name='bar')defdecorated_bar(z):print('((%s))'%z)argcat=ArgCat()withargcat.build()asbuilder:# Create the parser for the "foo" command.builder.add_subparser('foo')builder.subparser('foo').add_argument('-x',type=int,default=1)builder.subparser('foo').add_argument('y',type=float)# Create the parser for the "bar" command.builder.add_subparser('bar')builder.subparser('bar').add_argument('z')# Set handler functions all at once from a handler provider# Supposed this code snippet is in a __main__ module, taking the module as the provider.# ArgCat will try to find all functions decorated by @ArgCat.handler() and set them as# the the handlers for the parsers according to the `parser_name` set in the decorator# respectively.argcat.add_main_module_as_handler_provider()# The above function call is a convenient way for below:# argcat.add_handler_provider(sys.modules['__main__'])# Parse the args and the handler function `foo()` will be called with required# parameters automatically.argcat.parse_args('foo 1 -x 2'.split())# Parse the args and the handler function `bar()` will be called with required# parameters automatically.argcat.parse_args('bar XYZYX'.split())A Few Further Explanations: (You may be curious about)Handler ProviderA handler provider can be any object owns any functions decorated by@ArgCat.handler()with a parameter as a parser name.When setting a handler provider, ArgCat tries to find all handler functions of the provider at first. Then it collects all the parsers of the specified names from the decorated functions. In the end, it tries to link the functions to each parser picked respectively.Handler FunctionsArgCat supports all kinds of functions to be handler functions, such as instance methods, @staticmethod, @classmethod and the other callables.When decorating a callable to be a handler function, please make sure to place@ArgCat.handler()in the nearest place to the function definition, like below:@classmethod@ArgCat.handler(parser_name='foo')deffoo(cls):...A handler function's signature must match arguments' dests of its parsers. For example, if a parser has two arguments ['--x'] and ['-y'], its handler function should have a signature contains the exact two parameters:(x, y). By contrast, the name of the function is arbitary. So, eitherfoo(x, y)orgo(x, y)can be the parser's handler function.Note:There is a scenario which you may need to be aware of. Supposed you have one argument ['verbose'] for the main parser and also have a ['--file'] argument for the subparser 'load'. Then the handler function for the subparser should be in a form asfoo(verbose, file)instead offoo(file). Becase the subparser's handler function will also take the arguments from the main parser by default, unless the argument added to the main handler is throughadd_exlusive_argument(). Nevertheless, don't panic. Bothset_parser_handler()andadd_handler_provider()will check the signature for you and let you know what is the correct one.LicenseMIT License