@@ -1911,6 +1911,9 @@ def parse_args(self, args=None, namespace=None):
1911
1911
return args
1912
1912
1913
1913
def parse_known_args (self , args = None , namespace = None ):
1914
+ return self ._parse_known_args2 (args , namespace , intermixed = False )
1915
+
1916
+ def _parse_known_args2 (self , args , namespace , intermixed ):
1914
1917
if args is None :
1915
1918
# args default to the system args
1916
1919
args = _sys .argv [1 :]
@@ -1937,18 +1940,18 @@ def parse_known_args(self, args=None, namespace=None):
1937
1940
# parse the arguments and exit if there are any errors
1938
1941
if self .exit_on_error :
1939
1942
try :
1940
- namespace , args = self ._parse_known_args (args , namespace )
1943
+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
1941
1944
except ArgumentError as err :
1942
1945
self .error (str (err ))
1943
1946
else :
1944
- namespace , args = self ._parse_known_args (args , namespace )
1947
+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
1945
1948
1946
1949
if hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
1947
1950
args .extend (getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ))
1948
1951
delattr (namespace , _UNRECOGNIZED_ARGS_ATTR )
1949
1952
return namespace , args
1950
1953
1951
- def _parse_known_args (self , arg_strings , namespace ):
1954
+ def _parse_known_args (self , arg_strings , namespace , intermixed ):
1952
1955
# replace arg strings that are file references
1953
1956
if self .fromfile_prefix_chars is not None :
1954
1957
arg_strings = self ._read_args_from_files (arg_strings )
@@ -2038,6 +2041,7 @@ def consume_optional(start_index):
2038
2041
# if we found no optional action, skip it
2039
2042
if action is None :
2040
2043
extras .append (arg_strings [start_index ])
2044
+ extras_pattern .append ('O' )
2041
2045
return start_index + 1
2042
2046
2043
2047
# if there is an explicit argument, try to match the
@@ -2073,6 +2077,7 @@ def consume_optional(start_index):
2073
2077
sep = ''
2074
2078
else :
2075
2079
extras .append (char + explicit_arg )
2080
+ extras_pattern .append ('O' )
2076
2081
stop = start_index + 1
2077
2082
break
2078
2083
# if the action expect exactly one argument, we've
@@ -2143,6 +2148,7 @@ def consume_positionals(start_index):
2143
2148
# consume Positionals and Optionals alternately, until we have
2144
2149
# passed the last option string
2145
2150
extras = []
2151
+ extras_pattern = []
2146
2152
start_index = 0
2147
2153
if option_string_indices :
2148
2154
max_option_string_index = max (option_string_indices )
@@ -2155,7 +2161,7 @@ def consume_positionals(start_index):
2155
2161
index
2156
2162
for index in option_string_indices
2157
2163
if index >= start_index ])
2158
- if start_index != next_option_string_index :
2164
+ if not intermixed and start_index != next_option_string_index :
2159
2165
positionals_end_index = consume_positionals (start_index )
2160
2166
2161
2167
# only try to parse the next optional if we didn't consume
@@ -2171,16 +2177,35 @@ def consume_positionals(start_index):
2171
2177
if start_index not in option_string_indices :
2172
2178
strings = arg_strings [start_index :next_option_string_index ]
2173
2179
extras .extend (strings )
2180
+ extras_pattern .extend (arg_strings_pattern [start_index :next_option_string_index ])
2174
2181
start_index = next_option_string_index
2175
2182
2176
2183
# consume the next optional and any arguments for it
2177
2184
start_index = consume_optional (start_index )
2178
2185
2179
- # consume any positionals following the last Optional
2180
- stop_index = consume_positionals (start_index )
2186
+ if not intermixed :
2187
+ # consume any positionals following the last Optional
2188
+ stop_index = consume_positionals (start_index )
2181
2189
2182
- # if we didn't consume all the argument strings, there were extras
2183
- extras .extend (arg_strings [stop_index :])
2190
+ # if we didn't consume all the argument strings, there were extras
2191
+ extras .extend (arg_strings [stop_index :])
2192
+ else :
2193
+ extras .extend (arg_strings [start_index :])
2194
+ extras_pattern .extend (arg_strings_pattern [start_index :])
2195
+ extras_pattern = '' .join (extras_pattern )
2196
+ assert len (extras_pattern ) == len (extras )
2197
+ # consume all positionals
2198
+ arg_strings = [s for s , c in zip (extras , extras_pattern ) if c != 'O' ]
2199
+ arg_strings_pattern = extras_pattern .replace ('O' , '' )
2200
+ stop_index = consume_positionals (0 )
2201
+ # leave unknown optionals and non-consumed positionals in extras
2202
+ for i , c in enumerate (extras_pattern ):
2203
+ if not stop_index :
2204
+ break
2205
+ if c != 'O' :
2206
+ stop_index -= 1
2207
+ extras [i ] = None
2208
+ extras = [s for s in extras if s is not None ]
2184
2209
2185
2210
# make sure all required actions were present and also convert
2186
2211
# action defaults which were not given as arguments
@@ -2446,10 +2471,6 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
2446
2471
# are then parsed. If the parser definition is incompatible with the
2447
2472
# intermixed assumptions (e.g. use of REMAINDER, subparsers) a
2448
2473
# TypeError is raised.
2449
- #
2450
- # positionals are 'deactivated' by setting nargs and default to
2451
- # SUPPRESS. This blocks the addition of that positional to the
2452
- # namespace
2453
2474
2454
2475
positionals = self ._get_positional_actions ()
2455
2476
a = [action for action in positionals
@@ -2458,59 +2479,7 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
2458
2479
raise TypeError ('parse_intermixed_args: positional arg'
2459
2480
' with nargs=%s' % a [0 ].nargs )
2460
2481
2461
- if [action .dest for group in self ._mutually_exclusive_groups
2462
- for action in group ._group_actions if action in positionals ]:
2463
- raise TypeError ('parse_intermixed_args: positional in'
2464
- ' mutuallyExclusiveGroup' )
2465
-
2466
- try :
2467
- save_usage = self .usage
2468
- try :
2469
- if self .usage is None :
2470
- # capture the full usage for use in error messages
2471
- self .usage = self .format_usage ()[7 :]
2472
- for action in positionals :
2473
- # deactivate positionals
2474
- action .save_nargs = action .nargs
2475
- # action.nargs = 0
2476
- action .nargs = SUPPRESS
2477
- action .save_default = action .default
2478
- action .default = SUPPRESS
2479
- namespace , remaining_args = self .parse_known_args (args ,
2480
- namespace )
2481
- for action in positionals :
2482
- # remove the empty positional values from namespace
2483
- if (hasattr (namespace , action .dest )
2484
- and getattr (namespace , action .dest )== []):
2485
- from warnings import warn
2486
- warn ('Do not expect %s in %s' % (action .dest , namespace ))
2487
- delattr (namespace , action .dest )
2488
- finally :
2489
- # restore nargs and usage before exiting
2490
- for action in positionals :
2491
- action .nargs = action .save_nargs
2492
- action .default = action .save_default
2493
- optionals = self ._get_optional_actions ()
2494
- try :
2495
- # parse positionals. optionals aren't normally required, but
2496
- # they could be, so make sure they aren't.
2497
- for action in optionals :
2498
- action .save_required = action .required
2499
- action .required = False
2500
- for group in self ._mutually_exclusive_groups :
2501
- group .save_required = group .required
2502
- group .required = False
2503
- namespace , extras = self .parse_known_args (remaining_args ,
2504
- namespace )
2505
- finally :
2506
- # restore parser values before exiting
2507
- for action in optionals :
2508
- action .required = action .save_required
2509
- for group in self ._mutually_exclusive_groups :
2510
- group .required = group .save_required
2511
- finally :
2512
- self .usage = save_usage
2513
- return namespace , extras
2482
+ return self ._parse_known_args2 (args , namespace , intermixed = True )
2514
2483
2515
2484
# ========================
2516
2485
# Value conversion methods
0 commit comments