mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
[3.11] gh-60346: Improve handling single-dash options in ArgumentParser.parse_known_args() (GH-114180) (GH-115674)
(cherry picked from commit e47ecbd042
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
e1994c43c0
commit
c02b7ae4dd
3 changed files with 57 additions and 23 deletions
|
@ -1982,7 +1982,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
|
||||
# get the optional identified at this index
|
||||
option_tuple = option_string_indices[start_index]
|
||||
action, option_string, explicit_arg = option_tuple
|
||||
action, option_string, sep, explicit_arg = option_tuple
|
||||
|
||||
# identify additional optionals in the same arg string
|
||||
# (e.g. -xyz is the same as -x -y -z if no args are required)
|
||||
|
@ -2009,18 +2009,27 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
and option_string[1] not in chars
|
||||
and explicit_arg != ''
|
||||
):
|
||||
if sep or explicit_arg[0] in chars:
|
||||
msg = _('ignored explicit argument %r')
|
||||
raise ArgumentError(action, msg % explicit_arg)
|
||||
action_tuples.append((action, [], option_string))
|
||||
char = option_string[0]
|
||||
option_string = char + explicit_arg[0]
|
||||
new_explicit_arg = explicit_arg[1:] or None
|
||||
optionals_map = self._option_string_actions
|
||||
if option_string in optionals_map:
|
||||
action = optionals_map[option_string]
|
||||
explicit_arg = new_explicit_arg
|
||||
explicit_arg = explicit_arg[1:]
|
||||
if not explicit_arg:
|
||||
sep = explicit_arg = None
|
||||
elif explicit_arg[0] == '=':
|
||||
sep = '='
|
||||
explicit_arg = explicit_arg[1:]
|
||||
else:
|
||||
sep = ''
|
||||
else:
|
||||
msg = _('ignored explicit argument %r')
|
||||
raise ArgumentError(action, msg % explicit_arg)
|
||||
|
||||
extras.append(char + explicit_arg)
|
||||
stop = start_index + 1
|
||||
break
|
||||
# if the action expect exactly one argument, we've
|
||||
# successfully matched the option; exit the loop
|
||||
elif arg_count == 1:
|
||||
|
@ -2238,18 +2247,17 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
# if the option string is present in the parser, return the action
|
||||
if arg_string in self._option_string_actions:
|
||||
action = self._option_string_actions[arg_string]
|
||||
return action, arg_string, None
|
||||
return action, arg_string, None, None
|
||||
|
||||
# if it's just a single character, it was meant to be positional
|
||||
if len(arg_string) == 1:
|
||||
return None
|
||||
|
||||
# if the option string before the "=" is present, return the action
|
||||
if '=' in arg_string:
|
||||
option_string, explicit_arg = arg_string.split('=', 1)
|
||||
if option_string in self._option_string_actions:
|
||||
action = self._option_string_actions[option_string]
|
||||
return action, option_string, explicit_arg
|
||||
option_string, sep, explicit_arg = arg_string.partition('=')
|
||||
if sep and option_string in self._option_string_actions:
|
||||
action = self._option_string_actions[option_string]
|
||||
return action, option_string, sep, explicit_arg
|
||||
|
||||
# search through all possible prefixes of the option string
|
||||
# and all actions in the parser for possible interpretations
|
||||
|
@ -2258,7 +2266,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
# if multiple actions match, the option string was ambiguous
|
||||
if len(option_tuples) > 1:
|
||||
options = ', '.join([option_string
|
||||
for action, option_string, explicit_arg in option_tuples])
|
||||
for action, option_string, sep, explicit_arg in option_tuples])
|
||||
args = {'option': arg_string, 'matches': options}
|
||||
msg = _('ambiguous option: %(option)s could match %(matches)s')
|
||||
self.error(msg % args)
|
||||
|
@ -2282,7 +2290,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
|
||||
# it was meant to be an optional but there is no such option
|
||||
# in this parser (though it might be a valid option in a subparser)
|
||||
return None, arg_string, None
|
||||
return None, arg_string, None, None
|
||||
|
||||
def _get_option_tuples(self, option_string):
|
||||
result = []
|
||||
|
@ -2292,15 +2300,13 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
chars = self.prefix_chars
|
||||
if option_string[0] in chars and option_string[1] in chars:
|
||||
if self.allow_abbrev:
|
||||
if '=' in option_string:
|
||||
option_prefix, explicit_arg = option_string.split('=', 1)
|
||||
else:
|
||||
option_prefix = option_string
|
||||
explicit_arg = None
|
||||
option_prefix, sep, explicit_arg = option_string.partition('=')
|
||||
if not sep:
|
||||
sep = explicit_arg = None
|
||||
for option_string in self._option_string_actions:
|
||||
if option_string.startswith(option_prefix):
|
||||
action = self._option_string_actions[option_string]
|
||||
tup = action, option_string, explicit_arg
|
||||
tup = action, option_string, sep, explicit_arg
|
||||
result.append(tup)
|
||||
|
||||
# single character options can be concatenated with their arguments
|
||||
|
@ -2308,18 +2314,17 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
# separate
|
||||
elif option_string[0] in chars and option_string[1] not in chars:
|
||||
option_prefix = option_string
|
||||
explicit_arg = None
|
||||
short_option_prefix = option_string[:2]
|
||||
short_explicit_arg = option_string[2:]
|
||||
|
||||
for option_string in self._option_string_actions:
|
||||
if option_string == short_option_prefix:
|
||||
action = self._option_string_actions[option_string]
|
||||
tup = action, option_string, short_explicit_arg
|
||||
tup = action, option_string, '', short_explicit_arg
|
||||
result.append(tup)
|
||||
elif option_string.startswith(option_prefix):
|
||||
action = self._option_string_actions[option_string]
|
||||
tup = action, option_string, explicit_arg
|
||||
tup = action, option_string, None, None
|
||||
result.append(tup)
|
||||
|
||||
# shouldn't ever get here
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue