@@ -1896,6 +1896,9 @@ def parse_args(self, args=None, namespace=None):
1896
1896
return args
1897
1897
1898
1898
def parse_known_args (self , args = None , namespace = None ):
1899
+ return self ._parse_known_args2 (args , namespace , intermixed = False )
1900
+
1901
+ def _parse_known_args2 (self , args , namespace , intermixed ):
1899
1902
if args is None :
1900
1903
# args default to the system args
1901
1904
args = _sys .argv [1 :]
@@ -1922,18 +1925,18 @@ def parse_known_args(self, args=None, namespace=None):
1922
1925
# parse the arguments and exit if there are any errors
1923
1926
if self .exit_on_error :
1924
1927
try :
1925
- namespace , args = self ._parse_known_args (args , namespace )
1928
+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
1926
1929
except ArgumentError as err :
1927
1930
self .error (str (err ))
1928
1931
else :
1929
- namespace , args = self ._parse_known_args (args , namespace )
1932
+ namespace , args = self ._parse_known_args (args , namespace , intermixed )
1930
1933
1931
1934
if hasattr (namespace , _UNRECOGNIZED_ARGS_ATTR ):
1932
1935
args .extend (getattr (namespace , _UNRECOGNIZED_ARGS_ATTR ))
1933
1936
delattr (namespace , _UNRECOGNIZED_ARGS_ATTR )
1934
1937
return namespace , args
1935
1938
1936
- def _parse_known_args (self , arg_strings , namespace ):
1939
+ def _parse_known_args (self , arg_strings , namespace , intermixed ):
1937
1940
# replace arg strings that are file references
1938
1941
if self .fromfile_prefix_chars is not None :
1939
1942
arg_strings = self ._read_args_from_files (arg_strings )
@@ -2024,6 +2027,7 @@ def consume_optional(start_index):
2024
2027
# if we found no optional action, skip it
2025
2028
if action is None :
2026
2029
extras .append (arg_strings [start_index ])
2030
+ extras_pattern .append ('O' )
2027
2031
return start_index + 1
2028
2032
2029
2033
# if there is an explicit argument, try to match the
@@ -2059,6 +2063,7 @@ def consume_optional(start_index):
2059
2063
sep = ''
2060
2064
else :
2061
2065
extras .append (char + explicit_arg )
2066
+ extras_pattern .append ('O' )
2062
2067
stop = start_index + 1
2063
2068
break
2064
2069
# if the action expect exactly one argument, we've
@@ -2137,6 +2142,7 @@ def consume_positionals(start_index):
2137
2142
# consume Positionals and Optionals alternately, until we have
2138
2143
# passed the last option string
2139
2144
extras = []
2145
+ extras_pattern = []
2140
2146
start_index = 0
2141
2147
if option_string_indices :
2142
2148
max_option_string_index = max (option_string_indices )
@@ -2150,7 +2156,7 @@ def consume_positionals(start_index):
2150
2156
if next_option_string_index in option_string_indices :
2151
2157
break
2152
2158
next_option_string_index += 1
2153
- if start_index != next_option_string_index :
2159
+ if not intermixed and start_index != next_option_string_index :
2154
2160
positionals_end_index = consume_positionals (start_index )
2155
2161
2156
2162
# only try to parse the next optional if we didn't consume
@@ -2166,16 +2172,35 @@ def consume_positionals(start_index):
2166
2172
if start_index not in option_string_indices :
2167
2173
strings = arg_strings [start_index :next_option_string_index ]
2168
2174
extras .extend (strings )
2175
+ extras_pattern .extend (arg_strings_pattern [start_index :next_option_string_index ])
2169
2176
start_index = next_option_string_index
2170
2177
2171
2178
# consume the next optional and any arguments for it
2172
2179
start_index = consume_optional (start_index )
2173
2180
2174
- # consume any positionals following the last Optional
2175
- stop_index = consume_positionals (start_index )
2181
+ if not intermixed :
2182
+ # consume any positionals following the last Optional
2183
+ stop_index = consume_positionals (start_index )
2176
2184
2177
- # if we didn't consume all the argument strings, there were extras
2178
- extras .extend (arg_strings [stop_index :])
2185
+ # if we didn't consume all the argument strings, there were extras
2186
+ extras .extend (arg_strings [stop_index :])
2187
+ else :
2188
+ extras .extend (arg_strings [start_index :])
2189
+ extras_pattern .extend (arg_strings_pattern [start_index :])
2190
+ extras_pattern = '' .join (extras_pattern )
2191
+ assert len (extras_pattern ) == len (extras )
2192
+ # consume all positionals
2193
+ arg_strings = [s for s , c in zip (extras , extras_pattern ) if c != 'O' ]
2194
+ arg_strings_pattern = extras_pattern .replace ('O' , '' )
2195
+ stop_index = consume_positionals (0 )
2196
+ # leave unknown optionals and non-consumed positionals in extras
2197
+ for i , c in enumerate (extras_pattern ):
2198
+ if not stop_index :
2199
+ break
2200
+ if c != 'O' :
2201
+ stop_index -= 1
2202
+ extras [i ] = None
2203
+ extras = [s for s in extras if s is not None ]
2179
2204
2180
2205
# make sure all required actions were present and also convert
2181
2206
# action defaults which were not given as arguments
@@ -2441,10 +2466,6 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
2441
2466
# are then parsed. If the parser definition is incompatible with the
2442
2467
# intermixed assumptions (e.g. use of REMAINDER, subparsers) a
2443
2468
# TypeError is raised.
2444
- #
2445
- # positionals are 'deactivated' by setting nargs and default to
2446
- # SUPPRESS. This blocks the addition of that positional to the
2447
- # namespace
2448
2469
2449
2470
positionals = self ._get_positional_actions ()
2450
2471
a = [action for action in positionals
@@ -2453,59 +2474,7 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
2453
2474
raise TypeError ('parse_intermixed_args: positional arg'
2454
2475
' with nargs=%s' % a [0 ].nargs )
2455
2476
2456
- if [action .dest for group in self ._mutually_exclusive_groups
2457
- for action in group ._group_actions if action in positionals ]:
2458
- raise TypeError ('parse_intermixed_args: positional in'
2459
- ' mutuallyExclusiveGroup' )
2460
-
2461
- try :
2462
- save_usage = self .usage
2463
- try :
2464
- if self .usage is None :
2465
- # capture the full usage for use in error messages
2466
- self .usage = self .format_usage ()[7 :]
2467
- for action in positionals :
2468
- # deactivate positionals
2469
- action .save_nargs = action .nargs
2470
- # action.nargs = 0
2471
- action .nargs = SUPPRESS
2472
- action .save_default = action .default
2473
- action .default = SUPPRESS
2474
- namespace , remaining_args = self .parse_known_args (args ,
2475
- namespace )
2476
- for action in positionals :
2477
- # remove the empty positional values from namespace
2478
- if (hasattr (namespace , action .dest )
2479
- and getattr (namespace , action .dest )== []):
2480
- from warnings import warn
2481
- warn ('Do not expect %s in %s' % (action .dest , namespace ))
2482
- delattr (namespace , action .dest )
2483
- finally :
2484
- # restore nargs and usage before exiting
2485
- for action in positionals :
2486
- action .nargs = action .save_nargs
2487
- action .default = action .save_default
2488
- optionals = self ._get_optional_actions ()
2489
- try :
2490
- # parse positionals. optionals aren't normally required, but
2491
- # they could be, so make sure they aren't.
2492
- for action in optionals :
2493
- action .save_required = action .required
2494
- action .required = False
2495
- for group in self ._mutually_exclusive_groups :
2496
- group .save_required = group .required
2497
- group .required = False
2498
- namespace , extras = self .parse_known_args (remaining_args ,
2499
- namespace )
2500
- finally :
2501
- # restore parser values before exiting
2502
- for action in optionals :
2503
- action .required = action .save_required
2504
- for group in self ._mutually_exclusive_groups :
2505
- group .required = group .save_required
2506
- finally :
2507
- self .usage = save_usage
2508
- return namespace , extras
2477
+ return self ._parse_known_args2 (args , namespace , intermixed = True )
2509
2478
2510
2479
# ========================
2511
2480
# Value conversion methods
0 commit comments