From 4d81b842a5a2af9d3160e7b3895b7d78604d19bb Mon Sep 17 00:00:00 2001 From: eternalrights <3147268827@qq.com> Date: Fri, 24 Jul 2026 16:05:47 +0800 Subject: [PATCH] Fix AttributeError crash in Argument.dest on invalid option strings When a plugin registers an option with an invalid name (e.g. one that starts with a digit), argparse's Action.__init__ raises before the dest attribute is assigned. If Argument.dest then reads self._action.dest, it raises a secondary AttributeError instead of letting argparse report the real problem. Use getattr with a "" fallback so a missing dest attribute does not crash on access. Closes #13817 --- changelog/14773.bugfix.rst | 1 + src/_pytest/config/argparsing.py | 2 +- testing/test_config.py | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changelog/14773.bugfix.rst diff --git a/changelog/14773.bugfix.rst b/changelog/14773.bugfix.rst new file mode 100644 index 00000000000..7f6ae597cac --- /dev/null +++ b/changelog/14773.bugfix.rst @@ -0,0 +1 @@ +Fixed a crash in ``Argument.dest`` when accessing an option with an invalid option string (for example, one that starts with a digit). Previously, this would raise an ``AttributeError`` because the underlying ``argparse.Action`` may not have a ``dest`` attribute when initialization fails. diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index d6a97c8928e..5092c2389f9 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -302,7 +302,7 @@ def names(self) -> Sequence[str]: @property def dest(self) -> str: - return self._action.dest + return getattr(self._action, "dest", "") @property def default(self) -> Any: diff --git a/testing/test_config.py b/testing/test_config.py index 14946dde164..1d88f8f9a25 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -2487,6 +2487,21 @@ def test_help_formatter_uses_py_get_terminal_width(monkeypatch: MonkeyPatch) -> assert formatter._width == 42 +def test_argument_dest_does_not_crash_on_invalid_option() -> None: + """``Argument.dest`` should not raise ``AttributeError`` when accessed on an + Action that failed to initialize (e.g. with an invalid option string).""" + from _pytest.config.argparsing import Argument + + # Simulate the crash path: an option name that fails _set_opt_strings + # may result in an Action without a `dest` attribute. + class BrokenAction: + pass + + action = BrokenAction() + arg = Argument(action) # type: ignore[arg-type] + assert arg.dest == "" + + def test_config_does_not_load_blocked_plugin_from_args(pytester: Pytester) -> None: """This tests that pytest's config setup handles "-p no:X".""" p = pytester.makepyfile("def test(capfd): pass")