Skip to content

Commit

Permalink
Do not allow abbreviated arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Zac-HD committed Jun 23, 2019
1 parent 4f57d40 commit 0676236
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 4 deletions.
4 changes: 4 additions & 0 deletions changelog/1149.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Pytest no longer accepts prefixes of command-line arguments.
This was previously allowed where the ``ArgumentParser`` thought it was unambigious,
because this could be incorrect due to delayed parsing of options for plugins.
See for example issues #1149, #3413, and #4009.
2 changes: 1 addition & 1 deletion extra/get_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def report(issues):
if __name__ == "__main__":
import argparse

parser = argparse.ArgumentParser("process bitbucket issues")
parser = argparse.ArgumentParser("process bitbucket issues", allow_abbrev=False)
parser.add_argument(
"--refresh", action="store_true", help="invalidate cache, refresh issues"
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def changelog(version, write_out=False):

def main():
init(autoreset=True)
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument("version", help="Release version")
options = parser.parse_args()
pre_release(options.version)
Expand Down
39 changes: 39 additions & 0 deletions src/_pytest/config/argparsing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
import warnings
from gettext import gettext

import py

Expand Down Expand Up @@ -328,6 +329,7 @@ def __init__(self, parser, extra_info=None, prog=None):
usage=parser._usage,
add_help=False,
formatter_class=DropShorterLongHelpFormatter,
allow_abbrev=False,
)
# extra_info is a dict of (param -> value) to display if there's
# an usage error to provide more contextual information to the user
Expand Down Expand Up @@ -355,6 +357,43 @@ def parse_args(self, args=None, namespace=None):
getattr(args, FILE_OR_DIR).extend(argv)
return args

def _parse_optional(self, arg_string):
# This method is entirely copied from `argparse.ArgumentParser`, with a
# one-line bugfix for https://bugs.python.org/issue26967 so we can disable
# argument abbreviation without breaking flag combination (e.g. -vv).
if not arg_string:
return None
if not arg_string[0] in self.prefix_chars:
return None
if arg_string in self._option_string_actions:
action = self._option_string_actions[arg_string]
return action, arg_string, None
if len(arg_string) == 1:
return None
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
# The "or startswith" part is all we needed to patch!
if self.allow_abbrev or not arg_string.startswith("--"):
option_tuples = self._get_option_tuples(arg_string)
if len(option_tuples) > 1:
# (OK, plus tidying this up a bit and the explicit `gettext`)
options = ", ".join(option for _, option, _ in option_tuples)
args = {"option": arg_string, "matches": options}
msg = gettext("ambiguous option: %(option)s could match %(matches)s")
self.error(msg % args)
elif len(option_tuples) == 1:
option_tuple, = option_tuples
return option_tuple
if self._negative_number_matcher.match(arg_string):
if not self._has_negative_number_optionals:
return None
if " " in arg_string:
return None
return None, arg_string, None


class DropShorterLongHelpFormatter(argparse.HelpFormatter):
"""shorten help for long options that differ only in extra hyphens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
HERE = pathlib.Path(__file__).parent
TEST_CONTENT = (HERE / "template_test.py").read_bytes()

parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument("numbers", nargs="*", type=int)


Expand Down
2 changes: 1 addition & 1 deletion testing/test_parseopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def defaultget(option):

def test_drop_short_helper(self):
parser = argparse.ArgumentParser(
formatter_class=parseopt.DropShorterLongHelpFormatter
formatter_class=parseopt.DropShorterLongHelpFormatter, allow_abbrev=False
)
parser.add_argument(
"-t", "--twoword", "--duo", "--two-word", "--two", help="foo"
Expand Down

0 comments on commit 0676236

Please sign in to comment.