Created
October 18, 2017 18:21
-
-
Save dougn/14b043b73b8da0fdab97b554affbd138 to your computer and use it in GitHub Desktop.
Wrapper to argparse which provides decorator interface for command based commandlines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import functools | |
def _call(func, args): | |
# RED_FLAG: add nargs | |
kwds = dict((name, getattr(args, name, None)) for name in func._arguments) | |
return func(**kwds) | |
def _command(subparsers, defaults, passthrough, description, **kwds): | |
def subcommand(parsers, defaults, passthrough, description, kwds, func): | |
name = func.__name__ | |
if '__use_mod_in_name' in defaults: | |
defaults = dict(defaults) | |
usemodname = defaults.pop('__use_mod_in_name', False) | |
name = func.__module__.split('.',1)[-1] + '.' + func.__name__ | |
args = dict(name=name, epilog=func.__doc__) | |
args.update(defaults) | |
args.update(kwds) | |
if description: | |
args['description'] = description | |
if 'help' not in args: | |
args['help'] = description | |
subparser = parsers.add_parser(**args) | |
call_func = functools.partial(_call, func) | |
call_func._func = func | |
call_func._commandname = args['name'] | |
subparser.set_defaults(func=call_func) | |
argnames = list(passthrough) | |
for opts, kwds in reversed(getattr(func, '_arguments', [])): | |
arg = subparser.add_argument(*opts, **kwds) | |
name = arg.dest | |
assert name is not None | |
assert name not in argnames | |
# RED_FLAG: add inspect call to validate arg names. | |
argnames.append(name) | |
for group_name, group_attrs in getattr(func, '_groups', {}).iteritems(): | |
group = None | |
if group_attrs['mutually_exclusive']: | |
group = subparser.add_mutually_exclusive_group(required=group_attrs['required']) | |
else: | |
group = subparser.add_argument_group(group_name, group_attrs['description']) | |
for opts, kwds in reversed(group_attrs['arguments']): | |
arg = group.add_argument(*opts, **kwds) | |
name = arg.dest | |
assert name is not None | |
assert name not in argnames | |
# RED_FLAG: add inspect call to validate arg names. | |
argnames.append(name) | |
# RED_FLAG: add processing for nargs. | |
func._arguments = argnames | |
func._parser = subparser | |
return func | |
return functools.partial(subcommand, subparsers, | |
defaults, passthrough, description, kwds) | |
def _argument(*args, **kwds): | |
def subargument(aargs, akwds, func): | |
if not hasattr(func, '_arguments'): | |
func._arguments = [] | |
func._arguments.append((aargs, akwds)) | |
return func | |
return functools.partial(subargument, args, kwds) | |
def _group(name, mutually_exclusive=False, required=False, description=''): | |
def group(name, mutually_exclusive, required, description, func): | |
if not hasattr(func, '_groups'): | |
func._groups = {} | |
gd = func._groups.setdefault(name, {}) | |
gd['required'] = required | |
gd['mutually_exclusive'] = mutually_exclusive | |
gd['description'] = description | |
gd.setdefault('arguments', []) | |
return func | |
return functools.partial(group, name, mutually_exclusive, required, description) | |
def _group_argument(group_name, *args, **kwds): | |
def group_subargument(group_name, aargs, akwds, func): | |
if not hasattr(func, '_groups'): | |
func._groups = {} | |
gd = func._groups.setdefault(group_name, | |
dict(required=False, | |
mutually_exclusive=False, | |
description='', | |
arguments=list())) | |
gd['arguments'].append((aargs, akwds)) | |
return func | |
return functools.partial(group_subargument, group_name, args, kwds) | |
def _passthrough(name): | |
def passthrough(name, func): | |
func._arguments.append(name) | |
return func | |
return functools.partial(passthrough, name) | |
def _postarg(parser, func): | |
if not hasattr(parser, '_postargs'): | |
parser._postargs = [] | |
parser._postargs.append((func.__name__,func)) | |
return func | |
def _main(parser): | |
args = parser.parse_args() | |
args.args=args | |
for name, func in reversed(getattr(parser, '_postargs', [])): | |
if name not in dir(args): | |
setattr(args, name, func(parser, args)) | |
return args.func(args) | |
def Program(prog='np4admin', | |
formatter_class=argparse.RawDescriptionHelpFormatter, | |
command_default_args={}, | |
command_implicit_args=[], | |
**kwdargs): | |
parser = argparse.ArgumentParser(prog=prog, | |
formatter_class=formatter_class, | |
**kwdargs) | |
subparsers = parser.add_subparsers(title='valid commands', | |
description='Use "<command> -h" for command-specific help.') | |
command_default_args = dict(command_default_args) | |
mod_command_default_args = dict(command_default_args) | |
mod_command_default_args['__use_mod_in_name'] = True | |
command_implicit_args = list(command_implicit_args) | |
parser.command = functools.partial(_command, subparsers, | |
command_default_args, | |
command_implicit_args) | |
parser.mod_command = functools.partial(_command, subparsers, | |
mod_command_default_args, | |
command_implicit_args) | |
parser.postarg = functools.partial(_postarg, parser) | |
parser.argument = _argument | |
parser.group = _group | |
parser.group_argument = _group_argument | |
parser.passthrough = _passthrough | |
parser.main = functools.partial(_main, parser) | |
return parser | |
def command_name(args): | |
if not args.func: | |
return '' | |
return args.func._commandname |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.