Skip to content

Instantly share code, notes, and snippets.

@everilae
Created July 28, 2015 12:38
Show Gist options
  • Save everilae/6c0747b12b0196035493 to your computer and use it in GitHub Desktop.
Save everilae/6c0747b12b0196035493 to your computer and use it in GitHub Desktop.
Create argparse.ArgumentParser for given function and apply parsed arguments
import inspect
import argparse
def _helpfor(param):
if param.annotation is not inspect.Parameter.empty:
if isinstance(param.annotation, type):
return param.annotation.__name__
return str(param.annotation)
return param.name
def parserfor(f, doc=None, paramdocs={}):
if doc is None:
doc = getattr(f, '__doc__', "")
sig = inspect.signature(f)
parser = argparse.ArgumentParser(
prog=getattr(f, '__name__'),
description=doc,
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
for name, param in sig.parameters.items():
kwgs = dict(help=paramdocs.get(name, _helpfor(param)))
if param.annotation is not inspect.Parameter.empty:
kwgs['type'] = param.annotation
if param.default is not inspect.Parameter.empty:
kwgs['default'] = param.default
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD \
and param.default is not inspect.Parameter.empty:
name = "--%s" % name
elif param.kind == inspect.Parameter.VAR_POSITIONAL:
kwgs['nargs'] = '*'
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
name = "--%s" % name
parser.add_argument(name, **kwgs)
return parser
def argsfor(f):
return parserfor(f).parse_args()
def applyto(f, ns):
sig = inspect.signature(f)
args = []
kwargs = {}
# Would love to just use Signature.bind here, but the args namespace
# object has 0 information regarding positional args and bind will not
# accept POSITIONAL_ONLY args as keyword arguments. That and VAR_POSITIONAL
# forces the use of a loop and containers.
for name, param in sig.parameters.items():
if param.kind in {inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD}:
args.append(getattr(ns, name))
elif param.kind == inspect.Parameter.VAR_POSITIONAL:
args.extend(getattr(ns, name))
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
kwargs[name] = getattr(ns, name)
return f(*args, **kwargs)
if __name__ == '__main__':
def foo(a: str, b: int, c: bool, d: int =0, e: bool =True, f: bool =False):
"""
Docs.
"""
print(a, b, c, d, e, f)
args = argsfor(foo)
applyto(foo, args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment