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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
# coding: utf-8
# < from ruamel.util.new import _convert_version
def _convert_version(tup):
"""create a PEP 386 pseudo-format conformant string from tuple tup"""
ret_val = str(tup[0]) # first is always digit
next_sep = "." # separator for next extension, can be "" or "."
for x in tup[1:]:
if isinstance(x, int):
ret_val += next_sep + str(x)
next_sep = '.'
continue
first_letter = x[0].lower()
next_sep = ''
if first_letter in 'abcr':
ret_val += 'rc' if first_letter == 'r' else first_letter
elif first_letter in 'pd':
ret_val += '.post' if first_letter == 'p' else '.dev'
return ret_val
# <
version_info = (0, 2, "alpha", 2)
__version__ = _convert_version(version_info)
del _convert_version
import argparse
from argparse import ArgumentParser
class SubParsersAction(argparse._SubParsersAction):
"""support aliases, based on differences of 3.3 and 2.7
"""
class _AliasesChoicesPseudoAction(argparse.Action):
def __init__(self, name, aliases, help):
metavar = dest = name
if aliases:
metavar += ' (%s)' % ', '.join(aliases)
sup = super(SubParsersAction._AliasesChoicesPseudoAction, self)
sup.__init__(option_strings=[], dest=dest, help=help,
metavar=metavar)
def add_parser(self, name, **kwargs):
# remove aliases and help kwargs so the orginal add_parser
# does not get them
aliases = kwargs.pop('aliases', ())
help = kwargs.pop('help', None)
parser = argparse._SubParsersAction.add_parser(self, name, **kwargs)
if help is not None:
choice_action = self._AliasesChoicesPseudoAction(name, aliases,
help)
self._choices_actions.append(choice_action)
if aliases is not None:
for alias in aliases:
self._name_parser_map[alias] = parser
return parser
from _action.checksinglestore import CheckSingleStoreAction
from _action.count import CountAction
from _action.splitappend import SplitAppendAction
class SmartFormatter(argparse.HelpFormatter):
"""
you can only specify one formatter in standard argparse, so you cannot
both have pre-formatted description (RawDescriptionHelpFormatter)
and ArgumentDefaultsHelpFormatter.
The SmartFormatter has sensible defaults (RawDescriptionFormatter) and
the individual help text can be marked ( help="R|" ) for
variations in formatting.
"""
def __init__(self, *args, **kw):
self._add_defaults = False
super(SmartFormatter, self).__init__(*args, **kw)
def _fill_text(self, text, width, indent):
return ''.join([indent + line for line in text.splitlines(True)])
def _split_lines(self, text, width):
#print 'TEXT', text
if text.startswith('D|'):
self._add_defaults = True
text = text[2:]
if text.startswith('R|'):
return text[2:].splitlines()
return argparse.HelpFormatter._split_lines(self, text, width)
def _get_help_string(self, action):
if not self._add_defaults:
return argparse.HelpFormatter._get_help_string(self, action)
help = action.help
if '%(default)' not in action.help:
if action.default is not argparse.SUPPRESS:
defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
if action.option_strings or action.nargs in defaulting_nargs:
help += ' (default: %(default)s)'
return help
# decorators
# decorate method as a subparser, ToDo: signature
def sub_parser(*args, **kw):
class Decorator(object):
def __init__(self):
self.target = None
def __call__(self, target):
self.target = target
target.sub_parser = {'args': args, 'kw': kw}
target.option = self.option
return target
def option(self, *a, **k):
""" after a method xyz is decorated as sub_parser, you can add
options with:
@xyz.option('--force')
def force(self):
pass
if option argument is a short option ('-F'), add the long
option based on the function name
if no option argument, add function_name if 'nargs' in k
else add long option based on function name
"""
# here check if a is option name else take from function
def option_func(*args):
"""called with the original function that is decorated
add function name to last options element
"""
self.target.options[-1]['fun'] = args[0].__name__
pass
if not hasattr(self.target, "options"):
self.target.options = []
self.target.options.append({'args': a, 'kw': k})
return option_func
decorator = Decorator()
return decorator
# global options can come before and after a sub_parser, ToDo: signature
def global_option(*args, **kw):
def decorator(target):
target.global_option = {'args': args, 'kw': kw}
return target
return decorator
# global only options can come before a sub_parser only, ToDo: signature
def global_only_option(*args, **kw):
def decorator(target):
target.global_only_option = {'args': args, 'kw': kw}
return target
return decorator
def create_argument_parser(self, *args, **keywords):
argument_parser = argparse.ArgumentParser(**keywords)
self._subparsers = None
for x in dir(self):
if x.startswith('_'):
continue
method = getattr(self, x)
if hasattr(method, "sub_parser"):
if self._subparsers is None:
self._subparsers = argument_parser.add_subparsers(
dest="subparser_name", help='sub-command help')
#(name, aliases=aliases, help=help)
arg = method.sub_parser['args']
if not arg or not isinstance(arg[0], basestring):
arg = list(arg)
arg.insert(0, x)
sp = self._subparsers.add_parser(*arg,
**method.sub_parser['kw'])
sp.set_defaults(func=method)
#print x, method.sub_parser
if hasattr(method, "options"):
for o in method.options:
#print 'arg1', o
arg = list(o['args'])
fun_name = o.get('fun')
if arg:
# short option name only, add long option name
# based on function name
if len(arg[0]) == 2 and arg[0][0] == '-':
if (fun_name):
arg.insert(0, '--' + fun_name)
else:
# no option name
if o['kw'].get('nargs') == '+':
# file names etc, no leading dashes
arg.insert(0, fun_name)
else:
# add long option based on function name
arg.insert(0, '--' + fun_name)
#print 'arg2', arg
sp.add_argument(*arg, **o['kw'])
#print ' opt:', x, method.options
if hasattr(method, "global_only_option"):
arg = method.global_only_option['args']
kw = method.global_only_option['kw']
argument_parser.add_argument(*arg, **kw)
for x in dir(self):
if x.startswith('_'):
continue
method = getattr(self, x)
if hasattr(method, "global_option"):
for name in self._subparsers._name_parser_map:
sp = self._subparsers._name_parser_map[name]
arg = method.global_option['args']
if arg and not arg[0].startswith('--'):
arg = list(arg)
arg.insert(0, '--' + x)
sp.add_argument(*arg, **method.global_option['kw'])
return argument_parser
|