@@ -263,13 +263,12 @@ def add_argument(self, action):
263263
264264 # find all invocations
265265 get_invocation = self ._format_action_invocation
266- invocations = [get_invocation (action )]
266+ invocation_lengths = [len ( get_invocation (action )) + self . _current_indent ]
267267 for subaction in self ._iter_indented_subactions (action ):
268- invocations .append (get_invocation (subaction ))
268+ invocation_lengths .append (len ( get_invocation (subaction )) + self . _current_indent )
269269
270270 # update the maximum item length
271- invocation_length = max (map (len , invocations ))
272- action_length = invocation_length + self ._current_indent
271+ action_length = max (invocation_lengths )
273272 self ._action_max_length = max (self ._action_max_length ,
274273 action_length )
275274
@@ -1270,7 +1269,8 @@ def __call__(self, parser, namespace, values, option_string=None):
12701269 setattr (namespace , key , value )
12711270
12721271 if arg_strings :
1273- vars (namespace ).setdefault (_UNRECOGNIZED_ARGS_ATTR , [])
1272+ if not hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
1273+ setattr (namespace , _UNRECOGNIZED_ARGS_ATTR , [])
12741274 getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ).extend (arg_strings )
12751275
12761276class _ExtendAction (_AppendAction ):
@@ -1576,9 +1576,8 @@ def _get_positional_kwargs(self, dest, **kwargs):
15761576
15771577 # mark positional arguments as required if at least one is
15781578 # always required
1579- if kwargs .get ('nargs' ) not in [OPTIONAL , ZERO_OR_MORE ]:
1580- kwargs ['required' ] = True
1581- if kwargs .get ('nargs' ) == ZERO_OR_MORE and 'default' not in kwargs :
1579+ nargs = kwargs .get ('nargs' )
1580+ if nargs not in [OPTIONAL , ZERO_OR_MORE , REMAINDER , SUPPRESS , 0 ]:
15821581 kwargs ['required' ] = True
15831582
15841583 # return the keyword arguments with no option strings
@@ -1849,8 +1848,8 @@ def add_subparsers(self, **kwargs):
18491848 kwargs .setdefault ('parser_class' , type (self ))
18501849
18511850 if 'title' in kwargs or 'description' in kwargs :
1852- title = _ ( kwargs .pop ('title' , 'subcommands' ))
1853- description = _ ( kwargs .pop ('description' , None ) )
1851+ title = kwargs .pop ('title' , _ ( 'subcommands' ))
1852+ description = kwargs .pop ('description' , None )
18541853 self ._subparsers = self .add_argument_group (title , description )
18551854 else :
18561855 self ._subparsers = self ._positionals
@@ -1972,11 +1971,11 @@ def _parse_known_args(self, arg_strings, namespace):
19721971 # otherwise, add the arg to the arg strings
19731972 # and note the index if it was an option
19741973 else :
1975- option_tuple = self ._parse_optional (arg_string )
1976- if option_tuple is None :
1974+ option_tuples = self ._parse_optional (arg_string )
1975+ if option_tuples is None :
19771976 pattern = 'A'
19781977 else :
1979- option_string_indices [i ] = option_tuple
1978+ option_string_indices [i ] = option_tuples
19801979 pattern = 'O'
19811980 arg_string_pattern_parts .append (pattern )
19821981
@@ -1992,9 +1991,8 @@ def take_action(action, argument_strings, option_string=None):
19921991 argument_values = self ._get_values (action , argument_strings )
19931992
19941993 # error if this argument is not allowed with other previously
1995- # seen arguments, assuming that actions that use the default
1996- # value don't really count as "present"
1997- if argument_values is not action .default :
1994+ # seen arguments
1995+ if action .option_strings or argument_strings :
19981996 seen_non_default_actions .add (action )
19991997 for conflict_action in action_conflicts .get (action , []):
20001998 if conflict_action in seen_non_default_actions :
@@ -2011,8 +2009,16 @@ def take_action(action, argument_strings, option_string=None):
20112009 def consume_optional (start_index ):
20122010
20132011 # get the optional identified at this index
2014- option_tuple = option_string_indices [start_index ]
2015- action , option_string , sep , explicit_arg = option_tuple
2012+ option_tuples = option_string_indices [start_index ]
2013+ # if multiple actions match, the option string was ambiguous
2014+ if len (option_tuples ) > 1 :
2015+ options = ', ' .join ([option_string
2016+ for action , option_string , sep , explicit_arg in option_tuples ])
2017+ args = {'option' : arg_string , 'matches' : options }
2018+ msg = _ ('ambiguous option: %(option)s could match %(matches)s' )
2019+ raise ArgumentError (None , msg % args )
2020+
2021+ action , option_string , sep , explicit_arg = option_tuples [0 ]
20162022
20172023 # identify additional optionals in the same arg string
20182024 # (e.g. -xyz is the same as -x -y -z if no args are required)
@@ -2108,6 +2114,15 @@ def consume_positionals(start_index):
21082114 # and add the Positional and its args to the list
21092115 for action , arg_count in zip (positionals , arg_counts ):
21102116 args = arg_strings [start_index : start_index + arg_count ]
2117+ # Strip out the first '--' if it is not in REMAINDER arg.
2118+ if action .nargs == PARSER :
2119+ if arg_strings_pattern [start_index ] == '-' :
2120+ assert args [0 ] == '--'
2121+ args .remove ('--' )
2122+ elif action .nargs != REMAINDER :
2123+ if (arg_strings_pattern .find ('-' , start_index ,
2124+ start_index + arg_count ) >= 0 ):
2125+ args .remove ('--' )
21112126 start_index += arg_count
21122127 take_action (action , args )
21132128
@@ -2254,18 +2269,19 @@ def _match_argument(self, action, arg_strings_pattern):
22542269 def _match_arguments_partial (self , actions , arg_strings_pattern ):
22552270 # progressively shorten the actions list by slicing off the
22562271 # final actions until we find a match
2257- result = []
22582272 for i in range (len (actions ), 0 , - 1 ):
22592273 actions_slice = actions [:i ]
22602274 pattern = '' .join ([self ._get_nargs_pattern (action )
22612275 for action in actions_slice ])
22622276 match = _re .match (pattern , arg_strings_pattern )
22632277 if match is not None :
2264- result .extend ([len (string ) for string in match .groups ()])
2265- break
2266-
2267- # return the list of arg string counts
2268- return result
2278+ result = [len (string ) for string in match .groups ()]
2279+ if (match .end () < len (arg_strings_pattern )
2280+ and arg_strings_pattern [match .end ()] == 'O' ):
2281+ while result and not result [- 1 ]:
2282+ del result [- 1 ]
2283+ return result
2284+ return []
22692285
22702286 def _parse_optional (self , arg_string ):
22712287 # if it's an empty string, it was meant to be a positional
@@ -2279,7 +2295,7 @@ def _parse_optional(self, arg_string):
22792295 # if the option string is present in the parser, return the action
22802296 if arg_string in self ._option_string_actions :
22812297 action = self ._option_string_actions [arg_string ]
2282- return action , arg_string , None , None
2298+ return [( action , arg_string , None , None )]
22832299
22842300 # if it's just a single character, it was meant to be positional
22852301 if len (arg_string ) == 1 :
@@ -2289,25 +2305,14 @@ def _parse_optional(self, arg_string):
22892305 option_string , sep , explicit_arg = arg_string .partition ('=' )
22902306 if sep and option_string in self ._option_string_actions :
22912307 action = self ._option_string_actions [option_string ]
2292- return action , option_string , sep , explicit_arg
2308+ return [( action , option_string , sep , explicit_arg )]
22932309
22942310 # search through all possible prefixes of the option string
22952311 # and all actions in the parser for possible interpretations
22962312 option_tuples = self ._get_option_tuples (arg_string )
22972313
2298- # if multiple actions match, the option string was ambiguous
2299- if len (option_tuples ) > 1 :
2300- options = ', ' .join ([option_string
2301- for action , option_string , sep , explicit_arg in option_tuples ])
2302- args = {'option' : arg_string , 'matches' : options }
2303- msg = _ ('ambiguous option: %(option)s could match %(matches)s' )
2304- raise ArgumentError (None , msg % args )
2305-
2306- # if exactly one action matched, this segmentation is good,
2307- # so return the parsed action
2308- elif len (option_tuples ) == 1 :
2309- option_tuple , = option_tuples
2310- return option_tuple
2314+ if option_tuples :
2315+ return option_tuples
23112316
23122317 # if it was not found as an option, but it looks like a negative
23132318 # number, it was meant to be positional
@@ -2322,7 +2327,7 @@ def _parse_optional(self, arg_string):
23222327
23232328 # it was meant to be an optional but there is no such option
23242329 # in this parser (though it might be a valid option in a subparser)
2325- return None , arg_string , None , None
2330+ return [( None , arg_string , None , None )]
23262331
23272332 def _get_option_tuples (self , option_string ):
23282333 result = []
@@ -2345,7 +2350,9 @@ def _get_option_tuples(self, option_string):
23452350 # but multiple character options always have to have their argument
23462351 # separate
23472352 elif option_string [0 ] in chars and option_string [1 ] not in chars :
2348- option_prefix = option_string
2353+ option_prefix , sep , explicit_arg = option_string .partition ('=' )
2354+ if not sep :
2355+ sep = explicit_arg = None
23492356 short_option_prefix = option_string [:2 ]
23502357 short_explicit_arg = option_string [2 :]
23512358
@@ -2354,9 +2361,9 @@ def _get_option_tuples(self, option_string):
23542361 action = self ._option_string_actions [option_string ]
23552362 tup = action , option_string , '' , short_explicit_arg
23562363 result .append (tup )
2357- elif option_string .startswith (option_prefix ):
2364+ elif self . allow_abbrev and option_string .startswith (option_prefix ):
23582365 action = self ._option_string_actions [option_string ]
2359- tup = action , option_string , None , None
2366+ tup = action , option_string , sep , explicit_arg
23602367 result .append (tup )
23612368
23622369 # shouldn't ever get here
@@ -2370,43 +2377,40 @@ def _get_nargs_pattern(self, action):
23702377 # in all examples below, we have to allow for '--' args
23712378 # which are represented as '-' in the pattern
23722379 nargs = action .nargs
2380+ # if this is an optional action, -- is not allowed
2381+ option = action .option_strings
23732382
23742383 # the default (None) is assumed to be a single argument
23752384 if nargs is None :
2376- nargs_pattern = '(-*A-*)'
2385+ nargs_pattern = '([A])' if option else '( -*A-*)'
23772386
23782387 # allow zero or one arguments
23792388 elif nargs == OPTIONAL :
2380- nargs_pattern = '(-*A?-*)'
2389+ nargs_pattern = '(A?)' if option else '( -*A?-*)'
23812390
23822391 # allow zero or more arguments
23832392 elif nargs == ZERO_OR_MORE :
2384- nargs_pattern = '(-*[A-]*)'
2393+ nargs_pattern = '(A*)' if option else '( -*[A-]*)'
23852394
23862395 # allow one or more arguments
23872396 elif nargs == ONE_OR_MORE :
2388- nargs_pattern = '(-*A[A-]*)'
2397+ nargs_pattern = '(A+)' if option else '( -*A[A-]*)'
23892398
23902399 # allow any number of options or arguments
23912400 elif nargs == REMAINDER :
2392- nargs_pattern = '([- AO]*)'
2401+ nargs_pattern = '([AO]*)' if option else '(. *)'
23932402
23942403 # allow one argument followed by any number of options or arguments
23952404 elif nargs == PARSER :
2396- nargs_pattern = '(-*A[-AO]*)'
2405+ nargs_pattern = '(A[AO]*)' if option else '( -*A[-AO]*)'
23972406
23982407 # suppress action, like nargs=0
23992408 elif nargs == SUPPRESS :
2400- nargs_pattern = '(-* -*)'
2409+ nargs_pattern = '()' if option else '( -*)'
24012410
24022411 # all others should be integers
24032412 else :
2404- nargs_pattern = '(-*%s-*)' % '-*' .join ('A' * nargs )
2405-
2406- # if this is an optional action, -- is not allowed
2407- if action .option_strings :
2408- nargs_pattern = nargs_pattern .replace ('-*' , '' )
2409- nargs_pattern = nargs_pattern .replace ('-' , '' )
2413+ nargs_pattern = '([AO]{%d})' % nargs if option else '((?:-*A){%d}-*)' % nargs
24102414
24112415 # return the pattern
24122416 return nargs_pattern
@@ -2503,20 +2507,13 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
25032507 # Value conversion methods
25042508 # ========================
25052509 def _get_values (self , action , arg_strings ):
2506- # for everything but PARSER, REMAINDER args, strip out first '--'
2507- if not action .option_strings and action .nargs not in [PARSER , REMAINDER ]:
2508- try :
2509- arg_strings .remove ('--' )
2510- except ValueError :
2511- pass
2512-
25132510 # optional argument produces a default when not present
25142511 if not arg_strings and action .nargs == OPTIONAL :
25152512 if action .option_strings :
25162513 value = action .const
25172514 else :
25182515 value = action .default
2519- if isinstance (value , str ):
2516+ if isinstance (value , str ) and value is not SUPPRESS :
25202517 value = self ._get_value (action , value )
25212518 self ._check_value (action , value )
25222519
@@ -2587,11 +2584,15 @@ def _get_value(self, action, arg_string):
25872584
25882585 def _check_value (self , action , value ):
25892586 # converted value must be one of the choices (if specified)
2590- if action .choices is not None and value not in action .choices :
2591- args = {'value' : value ,
2592- 'choices' : ', ' .join (map (repr , action .choices ))}
2593- msg = _ ('invalid choice: %(value)r (choose from %(choices)s)' )
2594- raise ArgumentError (action , msg % args )
2587+ choices = action .choices
2588+ if choices is not None :
2589+ if isinstance (choices , str ):
2590+ choices = iter (choices )
2591+ if value not in choices :
2592+ args = {'value' : value ,
2593+ 'choices' : ', ' .join (map (repr , action .choices ))}
2594+ msg = _ ('invalid choice: %(value)r (choose from %(choices)s)' )
2595+ raise ArgumentError (action , msg % args )
25952596
25962597 # =======================
25972598 # Help-formatting methods
0 commit comments