-
Notifications
You must be signed in to change notification settings - Fork 1
/
argscript.py
76 lines (64 loc) · 2.78 KB
/
argscript.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import argparse
import sys
import inspect
# customized parser show help message when no positional arguments given
class HelpOnErrorParser(argparse.ArgumentParser):
def error(self, message):
sys.stderr.write('error: %s\n' % message)
self.print_help()
sys.exit(2)
def find_actions(namespace, action_prefix):
"""Find all the actions in the namespace."""
actions = {}
for key, value in namespace.iteritems():
if key.startswith(action_prefix):
actions[key[len(action_prefix):]] = analyse_action(value)
return actions
def analyse_action(func):
"""Analyse a function."""
description = inspect.getdoc(func) or 'undocumented action'
arguments = []
args, varargs, kwargs, defaults = inspect.getargspec(func)
if varargs or kwargs:
raise TypeError('variable length arguments for action not allowed.')
if len(args) != len(defaults or ()):
raise TypeError('not all arguments have proper definitions')
for idx, (arg, definition) in enumerate(zip(args, defaults or ())):
if arg.startswith('_'):
raise TypeError('arguments may not start with an underscore')
if not isinstance(definition, tuple):
shortcut = None
default = definition
else:
shortcut, default = definition
argument_type = type(default)
#if isinstance(default, bool) and default is True:
# arg = 'no-' + arg
arguments.append((arg.replace('_', '-'), shortcut,
default, argument_type))
return func, description, arguments
def run(namespace=None, action_prefix='action_', args=None):
if namespace is None:
namespace = sys._getframe(1).f_locals
if args is None:
args = sys.argv[1:]
actions = find_actions(namespace, action_prefix)
parser = HelpOnErrorParser(description=namespace['__doc__'])
subparsers = parser.add_subparsers(dest='_func')
for name, (func, description, arguments) in actions.items():
doc = description.splitlines()[0]
argument_doc = {}
for line in description.splitlines()[1:]:
r = line.split('--', 1)
if len(r) == 2:
argument_doc[r[0].strip()] = r[1].strip()
subparser = subparsers.add_parser(name , description=doc)
for argname, shortcut, default, argument_type in arguments:
help_msg = argument_doc.get(argname, '')
if shortcut:
subparser.add_argument('-'+shortcut, '--'+argname, default=default, type=argument_type, help=help_msg)
else:
subparser.add_argument('--'+argname, default=default, type=argument_type, help=help_msg)
kwargs = vars(parser.parse_args(args))
func = kwargs.pop('_func')
actions[func][0](**kwargs)