1
1
# Author: Steven J. Bethard <[email protected] >.
2
+ # New maintainer as of 29 August 2019: Raymond Hettinger <[email protected] >
2
3
3
4
"""Command-line parsing library
4
5
66
67
'ArgumentParser' ,
67
68
'ArgumentError' ,
68
69
'ArgumentTypeError' ,
70
+ 'BooleanOptionalAction' ,
69
71
'FileType' ,
70
72
'HelpFormatter' ,
71
73
'ArgumentDefaultsHelpFormatter' ,
@@ -127,7 +129,7 @@ def __repr__(self):
127
129
return '%s(%s)' % (type_name , ', ' .join (arg_strings ))
128
130
129
131
def _get_kwargs (self ):
130
- return sorted (self .__dict__ .items ())
132
+ return list (self .__dict__ .items ())
131
133
132
134
def _get_args (self ):
133
135
return []
@@ -164,15 +166,12 @@ def __init__(self,
164
166
165
167
# default setting for width
166
168
if width is None :
167
- try :
168
- width = int (_os .environ ['COLUMNS' ])
169
- except (KeyError , ValueError ):
170
- width = 80
169
+ import shutil
170
+ width = shutil .get_terminal_size ().columns
171
171
width -= 2
172
172
173
173
self ._prog = prog
174
174
self ._indent_increment = indent_increment
175
- self ._max_help_position = max_help_position
176
175
self ._max_help_position = min (max_help_position ,
177
176
max (width - 20 , indent_increment * 2 ))
178
177
self ._width = width
@@ -265,7 +264,7 @@ def add_argument(self, action):
265
264
invocations .append (get_invocation (subaction ))
266
265
267
266
# update the maximum item length
268
- invocation_length = max ([ len ( s ) for s in invocations ] )
267
+ invocation_length = max (map ( len , invocations ) )
269
268
action_length = invocation_length + self ._current_indent
270
269
self ._action_max_length = max (self ._action_max_length ,
271
270
action_length )
@@ -407,13 +406,19 @@ def _format_actions_usage(self, actions, groups):
407
406
inserts [start ] += ' ['
408
407
else :
409
408
inserts [start ] = '['
410
- inserts [end ] = ']'
409
+ if end in inserts :
410
+ inserts [end ] += ']'
411
+ else :
412
+ inserts [end ] = ']'
411
413
else :
412
414
if start in inserts :
413
415
inserts [start ] += ' ('
414
416
else :
415
417
inserts [start ] = '('
416
- inserts [end ] = ')'
418
+ if end in inserts :
419
+ inserts [end ] += ')'
420
+ else :
421
+ inserts [end ] = ')'
417
422
for i in range (start + 1 , end ):
418
423
inserts [i ] = '|'
419
424
@@ -450,7 +455,7 @@ def _format_actions_usage(self, actions, groups):
450
455
# if the Optional doesn't take a value, format is:
451
456
# -s or --long
452
457
if action .nargs == 0 :
453
- part = '%s' % option_string
458
+ part = action . format_usage ()
454
459
455
460
# if the Optional takes a value, format is:
456
461
# -s ARGS or --long ARGS
@@ -586,7 +591,11 @@ def _format_args(self, action, default_metavar):
586
591
elif action .nargs == OPTIONAL :
587
592
result = '[%s]' % get_metavar (1 )
588
593
elif action .nargs == ZERO_OR_MORE :
589
- result = '[%s [%s ...]]' % get_metavar (2 )
594
+ metavar = get_metavar (1 )
595
+ if len (metavar ) == 2 :
596
+ result = '[%s [%s ...]]' % metavar
597
+ else :
598
+ result = '[%s ...]' % metavar
590
599
elif action .nargs == ONE_OR_MORE :
591
600
result = '%s [%s ...]' % get_metavar (2 )
592
601
elif action .nargs == REMAINDER :
@@ -596,7 +605,10 @@ def _format_args(self, action, default_metavar):
596
605
elif action .nargs == SUPPRESS :
597
606
result = ''
598
607
else :
599
- formats = ['%s' for _ in range (action .nargs )]
608
+ try :
609
+ formats = ['%s' for _ in range (action .nargs )]
610
+ except TypeError :
611
+ raise ValueError ("invalid nargs value" ) from None
600
612
result = ' ' .join (formats ) % get_metavar (action .nargs )
601
613
return result
602
614
@@ -835,9 +847,52 @@ def _get_kwargs(self):
835
847
]
836
848
return [(name , getattr (self , name )) for name in names ]
837
849
850
+ def format_usage (self ):
851
+ return self .option_strings [0 ]
852
+
838
853
def __call__ (self , parser , namespace , values , option_string = None ):
839
854
raise NotImplementedError (_ ('.__call__() not defined' ))
840
855
856
+ class BooleanOptionalAction (Action ):
857
+ def __init__ (self ,
858
+ option_strings ,
859
+ dest ,
860
+ default = None ,
861
+ type = None ,
862
+ choices = None ,
863
+ required = False ,
864
+ help = None ,
865
+ metavar = None ):
866
+
867
+ _option_strings = []
868
+ for option_string in option_strings :
869
+ _option_strings .append (option_string )
870
+
871
+ if option_string .startswith ('--' ):
872
+ option_string = '--no-' + option_string [2 :]
873
+ _option_strings .append (option_string )
874
+
875
+ if help is not None and default is not None :
876
+ help += f" (default: { default } )"
877
+
878
+ super ().__init__ (
879
+ option_strings = _option_strings ,
880
+ dest = dest ,
881
+ nargs = 0 ,
882
+ default = default ,
883
+ type = type ,
884
+ choices = choices ,
885
+ required = required ,
886
+ help = help ,
887
+ metavar = metavar )
888
+
889
+ def __call__ (self , parser , namespace , values , option_string = None ):
890
+ if option_string in self .option_strings :
891
+ setattr (namespace , self .dest , not option_string .startswith ('--no-' ))
892
+
893
+ def format_usage (self ):
894
+ return ' | ' .join (self .option_strings )
895
+
841
896
842
897
class _StoreAction (Action ):
843
898
@@ -853,7 +908,7 @@ def __init__(self,
853
908
help = None ,
854
909
metavar = None ):
855
910
if nargs == 0 :
856
- raise ValueError ('nargs for store actions must be > 0; if you '
911
+ raise ValueError ('nargs for store actions must be != 0; if you '
857
912
'have nothing to store, actions such as store '
858
913
'true or store const may be more appropriate' )
859
914
if const is not None and nargs != OPTIONAL :
@@ -945,7 +1000,7 @@ def __init__(self,
945
1000
help = None ,
946
1001
metavar = None ):
947
1002
if nargs == 0 :
948
- raise ValueError ('nargs for append actions must be > 0; if arg '
1003
+ raise ValueError ('nargs for append actions must be != 0; if arg '
949
1004
'strings are not supplying the value to append, '
950
1005
'the append const action may be more appropriate' )
951
1006
if const is not None and nargs != OPTIONAL :
@@ -1157,6 +1212,12 @@ def __call__(self, parser, namespace, values, option_string=None):
1157
1212
vars (namespace ).setdefault (_UNRECOGNIZED_ARGS_ATTR , [])
1158
1213
getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ).extend (arg_strings )
1159
1214
1215
+ class _ExtendAction (_AppendAction ):
1216
+ def __call__ (self , parser , namespace , values , option_string = None ):
1217
+ items = getattr (namespace , self .dest , None )
1218
+ items = _copy_items (items )
1219
+ items .extend (values )
1220
+ setattr (namespace , self .dest , items )
1160
1221
1161
1222
# ==============
1162
1223
# Type classes
@@ -1201,8 +1262,9 @@ def __call__(self, string):
1201
1262
return open (string , self ._mode , self ._bufsize , self ._encoding ,
1202
1263
self ._errors )
1203
1264
except OSError as e :
1204
- message = _ ("can't open '%s': %s" )
1205
- raise ArgumentTypeError (message % (string , e ))
1265
+ args = {'filename' : string , 'error' : e }
1266
+ message = _ ("can't open '%(filename)s': %(error)s" )
1267
+ raise ArgumentTypeError (message % args )
1206
1268
1207
1269
def __repr__ (self ):
1208
1270
args = self ._mode , self ._bufsize
@@ -1265,6 +1327,7 @@ def __init__(self,
1265
1327
self .register ('action' , 'help' , _HelpAction )
1266
1328
self .register ('action' , 'version' , _VersionAction )
1267
1329
self .register ('action' , 'parsers' , _SubParsersAction )
1330
+ self .register ('action' , 'extend' , _ExtendAction )
1268
1331
1269
1332
# raise an exception if the conflict handler is invalid
1270
1333
self ._get_handler ()
@@ -1357,6 +1420,10 @@ def add_argument(self, *args, **kwargs):
1357
1420
if not callable (type_func ):
1358
1421
raise ValueError ('%r is not callable' % (type_func ,))
1359
1422
1423
+ if type_func is FileType :
1424
+ raise ValueError ('%r is a FileType class object, instance of it'
1425
+ ' must be passed' % (type_func ,))
1426
+
1360
1427
# raise an error if the metavar does not match the type
1361
1428
if hasattr (self , "_get_formatter" ):
1362
1429
try :
@@ -1471,10 +1538,8 @@ def _get_optional_kwargs(self, *args, **kwargs):
1471
1538
1472
1539
# strings starting with two prefix characters are long options
1473
1540
option_strings .append (option_string )
1474
- if option_string [0 ] in self .prefix_chars :
1475
- if len (option_string ) > 1 :
1476
- if option_string [1 ] in self .prefix_chars :
1477
- long_option_strings .append (option_string )
1541
+ if len (option_string ) > 1 and option_string [1 ] in self .prefix_chars :
1542
+ long_option_strings .append (option_string )
1478
1543
1479
1544
# infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
1480
1545
dest = kwargs .pop ('dest' , None )
@@ -1614,6 +1679,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
1614
1679
- conflict_handler -- String indicating how to handle conflicts
1615
1680
- add_help -- Add a -h/-help option
1616
1681
- allow_abbrev -- Allow long options to be abbreviated unambiguously
1682
+ - exit_on_error -- Determines whether or not ArgumentParser exits with
1683
+ error info when an error occurs
1617
1684
"""
1618
1685
1619
1686
def __init__ (self ,
@@ -1628,19 +1695,14 @@ def __init__(self,
1628
1695
argument_default = None ,
1629
1696
conflict_handler = 'error' ,
1630
1697
add_help = True ,
1631
- allow_abbrev = True ):
1632
- _ActionsContainer .__init__ (self ,
1633
- description = description ,
1634
- prefix_chars = prefix_chars ,
1635
- argument_default = argument_default ,
1636
- conflict_handler = conflict_handler )
1637
- # FIXME: get multiple inheritance method resolution right so we can use
1638
- # what's below instead of the modified version above
1639
- # superinit = super(ArgumentParser, self).__init__
1640
- # superinit(description=description,
1641
- # prefix_chars=prefix_chars,
1642
- # argument_default=argument_default,
1643
- # conflict_handler=conflict_handler)
1698
+ allow_abbrev = True ,
1699
+ exit_on_error = True ):
1700
+
1701
+ superinit = super (ArgumentParser , self ).__init__
1702
+ superinit (description = description ,
1703
+ prefix_chars = prefix_chars ,
1704
+ argument_default = argument_default ,
1705
+ conflict_handler = conflict_handler )
1644
1706
1645
1707
# default setting for prog
1646
1708
if prog is None :
@@ -1653,6 +1715,7 @@ def __init__(self,
1653
1715
self .fromfile_prefix_chars = fromfile_prefix_chars
1654
1716
self .add_help = add_help
1655
1717
self .allow_abbrev = allow_abbrev
1718
+ self .exit_on_error = exit_on_error
1656
1719
1657
1720
add_group = self .add_argument_group
1658
1721
self ._positionals = add_group (_ ('positional arguments' ))
@@ -1783,15 +1846,19 @@ def parse_known_args(self, args=None, namespace=None):
1783
1846
setattr (namespace , dest , self ._defaults [dest ])
1784
1847
1785
1848
# parse the arguments and exit if there are any errors
1786
- try :
1849
+ if self .exit_on_error :
1850
+ try :
1851
+ namespace , args = self ._parse_known_args (args , namespace )
1852
+ except ArgumentError :
1853
+ err = _sys .exc_info ()[1 ]
1854
+ self .error (str (err ))
1855
+ else :
1787
1856
namespace , args = self ._parse_known_args (args , namespace )
1788
- if hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
1789
- args .extend (getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ))
1790
- delattr (namespace , _UNRECOGNIZED_ARGS_ATTR )
1791
- return namespace , args
1792
- except ArgumentError :
1793
- err = _sys .exc_info ()[1 ]
1794
- self .error (str (err ))
1857
+
1858
+ if hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
1859
+ args .extend (getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ))
1860
+ delattr (namespace , _UNRECOGNIZED_ARGS_ATTR )
1861
+ return namespace , args
1795
1862
1796
1863
def _parse_known_args (self , arg_strings , namespace ):
1797
1864
# replace arg strings that are file references
@@ -2080,10 +2147,11 @@ def _match_argument(self, action, arg_strings_pattern):
2080
2147
OPTIONAL : _ ('expected at most one argument' ),
2081
2148
ONE_OR_MORE : _ ('expected at least one argument' ),
2082
2149
}
2083
- default = ngettext ('expected %s argument' ,
2150
+ msg = nargs_errors .get (action .nargs )
2151
+ if msg is None :
2152
+ msg = ngettext ('expected %s argument' ,
2084
2153
'expected %s arguments' ,
2085
2154
action .nargs ) % action .nargs
2086
- msg = nargs_errors .get (action .nargs , default )
2087
2155
raise ArgumentError (action , msg )
2088
2156
2089
2157
# return the number of arguments matched
@@ -2130,24 +2198,23 @@ def _parse_optional(self, arg_string):
2130
2198
action = self ._option_string_actions [option_string ]
2131
2199
return action , option_string , explicit_arg
2132
2200
2133
- if self .allow_abbrev :
2134
- # search through all possible prefixes of the option string
2135
- # and all actions in the parser for possible interpretations
2136
- option_tuples = self ._get_option_tuples (arg_string )
2137
-
2138
- # if multiple actions match, the option string was ambiguous
2139
- if len (option_tuples ) > 1 :
2140
- options = ', ' .join ([option_string
2141
- for action , option_string , explicit_arg in option_tuples ])
2142
- args = {'option' : arg_string , 'matches' : options }
2143
- msg = _ ('ambiguous option: %(option)s could match %(matches)s' )
2144
- self .error (msg % args )
2145
-
2146
- # if exactly one action matched, this segmentation is good,
2147
- # so return the parsed action
2148
- elif len (option_tuples ) == 1 :
2149
- option_tuple , = option_tuples
2150
- return option_tuple
2201
+ # search through all possible prefixes of the option string
2202
+ # and all actions in the parser for possible interpretations
2203
+ option_tuples = self ._get_option_tuples (arg_string )
2204
+
2205
+ # if multiple actions match, the option string was ambiguous
2206
+ if len (option_tuples ) > 1 :
2207
+ options = ', ' .join ([option_string
2208
+ for action , option_string , explicit_arg in option_tuples ])
2209
+ args = {'option' : arg_string , 'matches' : options }
2210
+ msg = _ ('ambiguous option: %(option)s could match %(matches)s' )
2211
+ self .error (msg % args )
2212
+
2213
+ # if exactly one action matched, this segmentation is good,
2214
+ # so return the parsed action
2215
+ elif len (option_tuples ) == 1 :
2216
+ option_tuple , = option_tuples
2217
+ return option_tuple
2151
2218
2152
2219
# if it was not found as an option, but it looks like a negative
2153
2220
# number, it was meant to be positional
@@ -2171,16 +2238,17 @@ def _get_option_tuples(self, option_string):
2171
2238
# split at the '='
2172
2239
chars = self .prefix_chars
2173
2240
if option_string [0 ] in chars and option_string [1 ] in chars :
2174
- if '=' in option_string :
2175
- option_prefix , explicit_arg = option_string .split ('=' , 1 )
2176
- else :
2177
- option_prefix = option_string
2178
- explicit_arg = None
2179
- for option_string in self ._option_string_actions :
2180
- if option_string .startswith (option_prefix ):
2181
- action = self ._option_string_actions [option_string ]
2182
- tup = action , option_string , explicit_arg
2183
- result .append (tup )
2241
+ if self .allow_abbrev :
2242
+ if '=' in option_string :
2243
+ option_prefix , explicit_arg = option_string .split ('=' , 1 )
2244
+ else :
2245
+ option_prefix = option_string
2246
+ explicit_arg = None
2247
+ for option_string in self ._option_string_actions :
2248
+ if option_string .startswith (option_prefix ):
2249
+ action = self ._option_string_actions [option_string ]
2250
+ tup = action , option_string , explicit_arg
2251
+ result .append (tup )
2184
2252
2185
2253
# single character options can be concatenated with their arguments
2186
2254
# but multiple character options always have to have their argument
0 commit comments