@@ -1924,6 +1924,9 @@ def parse_args(self, args=None, namespace=None):
19241924 return args
19251925
19261926 def parse_known_args (self , args = None , namespace = None ):
1927+ return self ._parse_known_args2 (args , namespace , intermixed = False )
1928+
1929+ def _parse_known_args2 (self , args , namespace , intermixed ):
19271930 if args is None :
19281931 # args default to the system args
19291932 args = _sys .argv [1 :]
@@ -1950,18 +1953,18 @@ def parse_known_args(self, args=None, namespace=None):
19501953 # parse the arguments and exit if there are any errors
19511954 if self .exit_on_error :
19521955 try :
1953- namespace , args = self ._parse_known_args (args , namespace )
1956+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
19541957 except ArgumentError as err :
19551958 self .error (str (err ))
19561959 else :
1957- namespace , args = self ._parse_known_args (args , namespace )
1960+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
19581961
19591962 if hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
19601963 args .extend (getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ))
19611964 delattr (namespace , _UNRECOGNIZED_ARGS_ATTR )
19621965 return namespace , args
19631966
1964- def _parse_known_args (self , arg_strings , namespace ):
1967+ def _parse_known_args (self , arg_strings , namespace , intermixed ):
19651968 # replace arg strings that are file references
19661969 if self .fromfile_prefix_chars is not None :
19671970 arg_strings = self ._read_args_from_files (arg_strings )
@@ -2052,6 +2055,7 @@ def consume_optional(start_index):
20522055 # if we found no optional action, skip it
20532056 if action is None :
20542057 extras .append (arg_strings [start_index ])
2058+ extras_pattern .append ('O' )
20552059 return start_index + 1
20562060
20572061 # if there is an explicit argument, try to match the
@@ -2087,6 +2091,7 @@ def consume_optional(start_index):
20872091 sep = ''
20882092 else :
20892093 extras .append (char + explicit_arg )
2094+ extras_pattern .append ('O' )
20902095 stop = start_index + 1
20912096 break
20922097 # if the action expect exactly one argument, we've
@@ -2165,6 +2170,7 @@ def consume_positionals(start_index):
21652170 # consume Positionals and Optionals alternately, until we have
21662171 # passed the last option string
21672172 extras = []
2173+ extras_pattern = []
21682174 start_index = 0
21692175 if option_string_indices :
21702176 max_option_string_index = max (option_string_indices )
@@ -2178,7 +2184,7 @@ def consume_positionals(start_index):
21782184 if next_option_string_index in option_string_indices :
21792185 break
21802186 next_option_string_index += 1
2181- if start_index != next_option_string_index :
2187+ if not intermixed and start_index != next_option_string_index :
21822188 positionals_end_index = consume_positionals (start_index )
21832189
21842190 # only try to parse the next optional if we didn't consume
@@ -2194,16 +2200,35 @@ def consume_positionals(start_index):
21942200 if start_index not in option_string_indices :
21952201 strings = arg_strings [start_index :next_option_string_index ]
21962202 extras .extend (strings )
2203+ extras_pattern .extend (arg_strings_pattern [start_index :next_option_string_index ])
21972204 start_index = next_option_string_index
21982205
21992206 # consume the next optional and any arguments for it
22002207 start_index = consume_optional (start_index )
22012208
2202- # consume any positionals following the last Optional
2203- stop_index = consume_positionals (start_index )
2209+ if not intermixed :
2210+ # consume any positionals following the last Optional
2211+ stop_index = consume_positionals (start_index )
22042212
2205- # if we didn't consume all the argument strings, there were extras
2206- extras .extend (arg_strings [stop_index :])
2213+ # if we didn't consume all the argument strings, there were extras
2214+ extras .extend (arg_strings [stop_index :])
2215+ else :
2216+ extras .extend (arg_strings [start_index :])
2217+ extras_pattern .extend (arg_strings_pattern [start_index :])
2218+ extras_pattern = '' .join (extras_pattern )
2219+ assert len (extras_pattern ) == len (extras )
2220+ # consume all positionals
2221+ arg_strings = [s for s , c in zip (extras , extras_pattern ) if c != 'O' ]
2222+ arg_strings_pattern = extras_pattern .replace ('O' , '' )
2223+ stop_index = consume_positionals (0 )
2224+ # leave unknown optionals and non-consumed positionals in extras
2225+ for i , c in enumerate (extras_pattern ):
2226+ if not stop_index :
2227+ break
2228+ if c != 'O' :
2229+ stop_index -= 1
2230+ extras [i ] = None
2231+ extras = [s for s in extras if s is not None ]
22072232
22082233 # make sure all required actions were present and also convert
22092234 # action defaults which were not given as arguments
@@ -2469,10 +2494,6 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
24692494 # are then parsed. If the parser definition is incompatible with the
24702495 # intermixed assumptions (e.g. use of REMAINDER, subparsers) a
24712496 # TypeError is raised.
2472- #
2473- # positionals are 'deactivated' by setting nargs and default to
2474- # SUPPRESS. This blocks the addition of that positional to the
2475- # namespace
24762497
24772498 positionals = self ._get_positional_actions ()
24782499 a = [action for action in positionals
@@ -2481,59 +2502,7 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
24812502 raise TypeError ('parse_intermixed_args: positional arg'
24822503 ' with nargs=%s' % a [0 ].nargs )
24832504
2484- if [action .dest for group in self ._mutually_exclusive_groups
2485- for action in group ._group_actions if action in positionals ]:
2486- raise TypeError ('parse_intermixed_args: positional in'
2487- ' mutuallyExclusiveGroup' )
2488-
2489- try :
2490- save_usage = self .usage
2491- try :
2492- if self .usage is None :
2493- # capture the full usage for use in error messages
2494- self .usage = self .format_usage ()[7 :]
2495- for action in positionals :
2496- # deactivate positionals
2497- action .save_nargs = action .nargs
2498- # action.nargs = 0
2499- action .nargs = SUPPRESS
2500- action .save_default = action .default
2501- action .default = SUPPRESS
2502- namespace , remaining_args = self .parse_known_args (args ,
2503- namespace )
2504- for action in positionals :
2505- # remove the empty positional values from namespace
2506- if (hasattr (namespace , action .dest )
2507- and getattr (namespace , action .dest )== []):
2508- from warnings import warn
2509- warn ('Do not expect %s in %s' % (action .dest , namespace ))
2510- delattr (namespace , action .dest )
2511- finally :
2512- # restore nargs and usage before exiting
2513- for action in positionals :
2514- action .nargs = action .save_nargs
2515- action .default = action .save_default
2516- optionals = self ._get_optional_actions ()
2517- try :
2518- # parse positionals. optionals aren't normally required, but
2519- # they could be, so make sure they aren't.
2520- for action in optionals :
2521- action .save_required = action .required
2522- action .required = False
2523- for group in self ._mutually_exclusive_groups :
2524- group .save_required = group .required
2525- group .required = False
2526- namespace , extras = self .parse_known_args (remaining_args ,
2527- namespace )
2528- finally :
2529- # restore parser values before exiting
2530- for action in optionals :
2531- action .required = action .save_required
2532- for group in self ._mutually_exclusive_groups :
2533- group .required = group .save_required
2534- finally :
2535- self .usage = save_usage
2536- return namespace , extras
2505+ return self ._parse_known_args2 (args , namespace , intermixed = True )
25372506
25382507 # ========================
25392508 # Value conversion methods
0 commit comments