129
129
from optparse import OptionParser , SUPPRESS_HELP
130
130
import sys
131
131
132
+ class CommandInfo (
133
+ namedtuple ('BaseCommandInfo' ,
134
+ ['name' , 'callable' , 'category' , 'ignore_self' ])):
135
+ """Class to contain information about a spepcific supported command."""
136
+ def __new__ (cls , name = None , callable = None , category = None , ignore_self = None ):
137
+ """Creates a new CommandInfo allowing for default values.
138
+
139
+ Args:
140
+ name - Name of the command.
141
+ callable - Callable function of the command.
142
+ category - Category classification of the command.
143
+ ignore_self - Whether the arg list should ignore the first value if it is
144
+ self.
145
+ Returns:
146
+ info - A CommandInfo.
147
+ """
148
+ return super (CommandInfo , cls ).__new__ (cls , name , callable , category ,
149
+ ignore_self )
150
+
132
151
class Commandr (object ):
133
152
"""Class for managing commandr context."""
134
153
@@ -152,8 +171,6 @@ def __init__(self):
152
171
# List of commands in the order they appeared, of the format:
153
172
# [(name, callable, category)]
154
173
self ._command_list = []
155
- self ._command_info = namedtuple (
156
- '_COMMAND_INFO' , ['name' , 'callable' , 'category' , 'ignore_self' ])
157
174
158
175
self .command ('help' , ignore_self = True )(self ._HelpExitNoCommand )
159
176
@@ -183,18 +200,14 @@ def Hi(name, title='Mr.'):
183
200
decorator/function to register the command.
184
201
"""
185
202
def command_decorator (cmd_fn , cmd_fn_name = None ):
186
- final_name = (cmd_fn_name if cmd_fn_name is not None
187
- else command_name if command_name is not None
188
- else cmd_fn .func_name )
189
- info = self ._command_info (final_name , cmd_fn , category , ignore_self )
190
- self ._all_commands [final_name ] = info
203
+ info = self .AddCommand (cmd_fn , cmd_fn_name or command_name , category ,
204
+ ignore_self )
191
205
if main :
192
206
if not self .main :
193
- self .main = final_name
207
+ self .main = info . name
194
208
else :
195
209
raise CommandrDuplicateMainError ("'%s' tried to override '%s'" % (
196
- final_name , self ._main_command ))
197
- self ._command_list .append (info )
210
+ info .name , self ._main_command ))
198
211
return cmd_fn
199
212
200
213
# Handle no command_name case.
@@ -204,6 +217,24 @@ def command_decorator(cmd_fn, cmd_fn_name=None):
204
217
205
218
return command_decorator
206
219
220
+ def AddCommand (self , cmd_fn , cmd_fn_name , category , ignore_self ):
221
+ """Adds a command to the commandr list.
222
+
223
+ Args:
224
+ cmd_fn - The function to add.
225
+ cmd_fn_name - The name of the command being added or the func_name.
226
+ category - The category of the command.
227
+ ignore_self - Whether to ignore self in the arg list.
228
+ Returns:
229
+ info - The CommandInfo created.
230
+ """
231
+ final_name = (cmd_fn_name if cmd_fn_name is not None
232
+ else cmd_fn .func_name )
233
+ info = CommandInfo (final_name , cmd_fn , category , ignore_self )
234
+ self ._all_commands [info .name ] = info
235
+ self ._command_list .append (info )
236
+ return info
237
+
207
238
def SetOptions (self ,
208
239
hyphenate = None ,
209
240
show_all_help_variants = None ,
@@ -302,12 +333,14 @@ def RunFunction(self,
302
333
main - If set, it will use the supplied value as the command name to run
303
334
if no command name is supplied. It will override any previous values.
304
335
"""
336
+ info = self ._all_commands .get (cmd_name )
337
+ if not info :
338
+ info = self .AddCommand (cmd_fn , cmd_name , None , ignore_self )
339
+
305
340
self .SetOptions (hyphenate , show_all_help_variants , ignore_self , main_doc ,
306
341
main )
307
342
308
- cmd_name = cmd_name or ""
309
-
310
- argspec , defaults_dict = self ._BuildOptParse (cmd_name )
343
+ argspec , defaults_dict = self ._BuildOptParse (info )
311
344
312
345
(options , args ) = self .parser .parse_args ()
313
346
@@ -316,12 +349,10 @@ def RunFunction(self,
316
349
# If help, print our message, else remove it so it doesn't confuse the
317
350
# execution
318
351
if options_dict ['help' ]:
319
- self ._HelpExitCommand (None , cmd_name , cmd_fn )
352
+ self ._HelpExitCommand (None , info . name , info . callable )
320
353
elif 'help' in options_dict :
321
354
del options_dict ['help' ]
322
355
323
- info = (self ._all_commands .get (cmd_name )
324
- or self ._command_info (cmd_name , cmd_fn ))
325
356
ignore = (info .ignore_self
326
357
if info .ignore_self is not None
327
358
else self .ignore_self )
@@ -335,7 +366,7 @@ def RunFunction(self,
335
366
while True :
336
367
if i + skipped >= len (argspec .args ):
337
368
self ._HelpExitCommand ("Too many arguments" ,
338
- cmd_name , cmd_fn , options_dict , argspec .args )
369
+ info . name , info . callable , options_dict , argspec .args )
339
370
key = argspec .args [i + skipped ]
340
371
if ignore and key == 'self' :
341
372
skipped += 1
@@ -348,7 +379,7 @@ def RunFunction(self,
348
379
if i + skipped >= len (argspec .args ):
349
380
self ._HelpExitCommand (
350
381
"Too many arguments: True/False must be specified via switches" ,
351
- cmd_name , cmd_fn , options_dict , argspec .args )
382
+ info . name , info . callable , options_dict , argspec .args )
352
383
353
384
key = argspec .args [i + skipped ]
354
385
@@ -360,7 +391,7 @@ def RunFunction(self,
360
391
self ._HelpExitCommand (
361
392
"Repeated option: %s\n Option: %s\n Argument: %s" % (
362
393
key , options_dict [key ], value ),
363
- cmd_name , cmd_fn , options_dict , argspec .args )
394
+ info . name , info . callable , options_dict , argspec .args )
364
395
365
396
# cast specific types
366
397
if key in defaults_dict :
@@ -381,24 +412,24 @@ def RunFunction(self,
381
412
if key not in defaults_dict :
382
413
self ._HelpExitCommand (
383
414
"All options without default values must be specified" ,
384
- cmd_name , cmd_fn , options_dict , argspec .args )
415
+ info . name , info . callable , options_dict , argspec .args )
385
416
elif defaults_dict [key ] is not None :
386
417
options_dict [key ] = defaults_dict [key ]
387
418
388
419
self .current_command = info
389
420
try :
390
- result = cmd_fn (** options_dict )
421
+ result = info . callable (** options_dict )
391
422
except CommandrUsageError as e :
392
423
self .Usage (str (e ) or None )
393
424
394
425
if result :
395
426
print result
396
427
397
- def _BuildOptParse (self , cmd_name ):
428
+ def _BuildOptParse (self , info ):
398
429
"""Sets the current command parser to reflect the provided command.
399
430
400
431
Args:
401
- cmd_name - Name of the command being built.
432
+ info - CommandInfo of the command being built.
402
433
Returns:
403
434
argspec - ArgSpec object returned from inspect.getargspec() on the chosen
404
435
command function.
@@ -407,7 +438,7 @@ def _BuildOptParse(self, cmd_name):
407
438
Returns:
408
439
A populated OptionParser object.
409
440
"""
410
- usage = 'Usage: %%prog %s [options]\n ' % (cmd_name ) + \
441
+ usage = 'Usage: %%prog %s [options]\n ' % (info . name ) + \
411
442
'Options without default values MUST be specified\n \n ' + \
412
443
'Use: %prog help [command]\n to see other commands available.'
413
444
@@ -419,8 +450,6 @@ def _BuildOptParse(self, cmd_name):
419
450
# Parse the command function's arguments into the OptionsParser.
420
451
letters = set (['h' ]) # -h is for help
421
452
422
- info = self ._all_commands .get (cmd_name ) or self ._command_info ()
423
-
424
453
# Check if the command function is wrapped with other decorators, and if so,
425
454
# find the original function signature.
426
455
cmd_fn_root = info .callable
0 commit comments