Do not allow abbreviated arguments
This commit is contained in:
		
							parent
							
								
									4f57d40a43
								
							
						
					
					
						commit
						d72fb73fa0
					
				|  | @ -0,0 +1,7 @@ | |||
| Pytest no longer accepts prefixes of command-line arguments, for example | ||||
| typing ``pytest --doctest-mod`` inplace of ``--doctest-modules``. | ||||
| This was previously allowed where the ``ArgumentParser`` thought it was unambiguous, | ||||
| but this could be incorrect due to delayed parsing of options for plugins. | ||||
| See for example issues `#1149 <https://github.com/pytest-dev/pytest/issues/1149>`__, | ||||
| `#3413 <https://github.com/pytest-dev/pytest/issues/3413>`__, and | ||||
| `#4009 <https://github.com/pytest-dev/pytest/issues/4009>`__. | ||||
|  | @ -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" | ||||
|     ) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| import argparse | ||||
| import sys | ||||
| import warnings | ||||
| from gettext import gettext | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
|  | @ -328,6 +330,7 @@ class MyOptionParser(argparse.ArgumentParser): | |||
|             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 | ||||
|  | @ -355,6 +358,42 @@ class MyOptionParser(argparse.ArgumentParser): | |||
|             getattr(args, FILE_OR_DIR).extend(argv) | ||||
|         return args | ||||
| 
 | ||||
|     if sys.version_info[:2] < (3, 8):  # pragma: no cover | ||||
|         # Backport of https://github.com/python/cpython/pull/14316 so we can | ||||
|         # disable long --argument abbreviations without breaking short flags. | ||||
|         def _parse_optional(self, arg_string): | ||||
|             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 | ||||
|             if self.allow_abbrev or not arg_string.startswith("--"): | ||||
|                 option_tuples = self._get_option_tuples(arg_string) | ||||
|                 if len(option_tuples) > 1: | ||||
|                     msg = gettext( | ||||
|                         "ambiguous option: %(option)s could match %(matches)s" | ||||
|                     ) | ||||
|                     options = ", ".join(option for _, option, _ in option_tuples) | ||||
|                     self.error(msg % {"option": arg_string, "matches": options}) | ||||
|                 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 | ||||
|  |  | |||
|  | @ -984,7 +984,7 @@ def test_zipimport_hook(testdir, tmpdir): | |||
|             "app/foo.py": """ | ||||
|             import pytest | ||||
|             def main(): | ||||
|                 pytest.main(['--pyarg', 'foo']) | ||||
|                 pytest.main(['--pyargs', 'foo']) | ||||
|         """ | ||||
|         } | ||||
|     ) | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import pathlib | |||
| 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) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -735,7 +735,7 @@ def test_capture_badoutput_issue412(testdir): | |||
|             assert 0 | ||||
|         """ | ||||
|     ) | ||||
|     result = testdir.runpytest("--cap=fd") | ||||
|     result = testdir.runpytest("--capture=fd") | ||||
|     result.stdout.fnmatch_lines( | ||||
|         """ | ||||
|         *def test_func* | ||||
|  |  | |||
|  | @ -200,7 +200,7 @@ class TestParser: | |||
| 
 | ||||
|     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" | ||||
|  | @ -239,10 +239,8 @@ class TestParser: | |||
|         parser.addoption("--funcarg", "--func-arg", action="store_true") | ||||
|         parser.addoption("--abc-def", "--abc-def", action="store_true") | ||||
|         parser.addoption("--klm-hij", action="store_true") | ||||
|         args = parser.parse(["--funcarg", "--k"]) | ||||
|         assert args.funcarg is True | ||||
|         assert args.abc_def is False | ||||
|         assert args.klm_hij is True | ||||
|         with pytest.raises(UsageError): | ||||
|             parser.parse(["--funcarg", "--k"]) | ||||
| 
 | ||||
|     def test_drop_short_2(self, parser): | ||||
|         parser.addoption("--func-arg", "--doit", action="store_true") | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ class TestPasteCapture: | |||
|                 pytest.skip("") | ||||
|         """ | ||||
|         ) | ||||
|         reprec = testdir.inline_run(testpath, "--paste=failed") | ||||
|         reprec = testdir.inline_run(testpath, "--pastebin=failed") | ||||
|         assert len(pastebinlist) == 1 | ||||
|         s = pastebinlist[0] | ||||
|         assert s.find("def test_fail") != -1 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue