35
35
'__source__' , '__training__' ]
36
36
DUNDERS = BASE_DUNDERS + [
37
37
'__date__' , '__details__' , '__description__' , '__doc__' , '__docformat__' , '__email__' , '__examples__' ,
38
- '__functions__ ' , '__maximum_python_version__ ' , '__minimum_python_version__ ' , '__priority__ ' , '__product__ ' ,
39
- '__script__' , '__status__' , '__version__' ,
38
+ '__example_limit__ ' , '__functions__ ' , '__maximum_python_version__ ' , '__minimum_python_version__ ' , '__priority__ ' ,
39
+ '__product__' , '__requires__' , ' __script__' , '__status__' , '__version__' ,
40
40
]
41
- if sys .version_info >= (3 , 8 ):
42
- DUNDERS .append ('__requires__' )
43
-
44
41
DEFAULT_MAX_LEN = 20
45
42
DEFAULT_LST_MAX_LEN = 10
46
43
@@ -158,14 +155,14 @@ def add_parser(self, name, **kwargs):
158
155
choice_action .category = category
159
156
self ._choices_actions .append (choice_action )
160
157
# create the parser, but with another formatter and separating the help into an argument group
158
+ kwargs .update (name = name , parent_action = self )
161
159
parser = self ._parser_class (add_help = False , ** kwargs )
162
- parser .name = name
163
160
# add default extra arguments group
164
161
i = parser .add_argument_group ("extra arguments" )
165
162
i .add_argument ("-h" , action = "usage" , prefix = "show" , help = gt ("show usage message and exit" ))
166
163
i .add_argument ("--help" , action = "help" , prefix = "show" , help = gt ("show this help message and exit" ))
167
164
# add it to the map
168
- self ._name_parser_map [name ] = parser
165
+ self ._name_parser_map [parser . name ] = parser
169
166
# make parser available under aliases also
170
167
for alias in aliases :
171
168
self ._name_parser_map [alias ] = parser
@@ -316,13 +313,16 @@ def __init__(self, *args, **kwargs):
316
313
if not hasattr (ArgumentParser , "_globals_dict" ):
317
314
ArgumentParser ._globals_dict = get_tool_globals ()
318
315
gd = ArgumentParser ._globals_dict
319
- if sys .version_info >= (3 , 8 ):
320
- self ._check_requirements (gd .get ('__requires__' ))
316
+ self ._check_requirements (gd .get ('__requires__' ))
321
317
configure_docformat (gd )
322
318
self ._config_parsed = False
323
319
self ._docfmt = gd .get ('__docformat__' )
320
+ self ._parent_action = kwargs .pop ('parent_action' , None )
321
+ self ._parent = self ._parent_action ._parent if self ._parent_action else None
324
322
self ._reparse_args = {'pos' : [], 'opt' : [], 'sub' : []}
323
+ self .name = kwargs .pop ('name' , self .__class__ .name )
325
324
self .examples = gd .get ('__examples__' , [])
325
+ self .example_limit = gd .get ('__example_limit__' , {})
326
326
script = basename (self .tokens [0 ])
327
327
_stem = lambda p : splitext (p )[0 ]
328
328
if gd .get ('__script__' ) is None :
@@ -344,6 +344,19 @@ def __init__(self, *args, **kwargs):
344
344
l = ["{} {}" .format (ArgumentParser .prog , e ) for e in self .examples ]
345
345
l = list (filter (lambda x : x .startswith (kwargs ['prog' ]), l ))
346
346
if len (l ) > 0 :
347
+ dest = self ._parent_action .dest if getattr (self , "_parent_action" , None ) else None
348
+ if (n := self .example_limit if isinstance (self .example_limit , int ) else \
349
+ self .example_limit .get (self .name , self .example_limit .get (dest , 0 ))):
350
+ from random import shuffle
351
+ from shlex import split
352
+ shuffle (l )
353
+ _tmp , new_l = set (), []
354
+ for example in l :
355
+ token = split (example )[self .depth + 1 ]
356
+ if token not in _tmp :
357
+ new_l .append (example )
358
+ _tmp .add (token )
359
+ l = sorted (new_l )
347
360
kwargs ['epilog' ] = txt2title (gt ("Usage example{}" .format (["" , "s" ][len (l ) > 1 ])) + ":" )
348
361
e = '\n ' .join (["\n " , " " ][self ._docfmt is None ] + txt2paragraph (e ) for e in l )
349
362
kwargs ['epilog' ] += "\n " + e
@@ -603,6 +616,11 @@ def _sorted_actions(self):
603
616
for a in filter (lambda _ : self .is_action (_ , 'parsers' ), self ._actions ):
604
617
yield a
605
618
619
+ def add_subparsers (self , ** kwargs ):
620
+ action = super (ArgumentParser , self ).add_subparsers (** kwargs )
621
+ action ._parent = self
622
+ return action
623
+
606
624
def config_args (self , section = "main" ):
607
625
""" Additional method for feeding input arguments from a config file. """
608
626
if self ._config_parsed :
@@ -730,19 +748,26 @@ def print_usage(self, file=None):
730
748
self ._print_message (txt_terminal_render (self .format_usage ()), file or sys .stdout )
731
749
732
750
@property
733
- def tokens (self ):
751
+ def depth (self ):
752
+ p , d = self , 0
753
+ while (p := getattr (p , "_parent" , None )):
754
+ d += 1
755
+ return d
756
+
757
+ @property
758
+ def root (self ):
734
759
p = self
735
- while hasattr (p , "_parent" ) and p . _parent is not None :
760
+ while getattr (p , "_parent" , None ) :
736
761
p = p ._parent
737
- if hasattr (p , "_tokens" ):
738
- return p ._tokens
762
+ return p
763
+
764
+ @property
765
+ def tokens (self ):
766
+ return getattr (self .root , "_tokens" , None )
739
767
740
768
@tokens .setter
741
769
def tokens (self , command ):
742
- p = self
743
- while hasattr (p , "_parent" ) and p ._parent is not None :
744
- p = p ._parent
745
- if hasattr (p , "_tokens" ):
770
+ if hasattr (p := self .root , "_tokens" ):
746
771
return
747
772
p ._tokens = sys .argv if command is None else command
748
773
if isinstance (p ._tokens , str ):
0 commit comments