diff --git a/changelog/13484.bugfix.rst b/changelog/13484.bugfix.rst new file mode 100644 index 00000000000..4407003e8e9 --- /dev/null +++ b/changelog/13484.bugfix.rst @@ -0,0 +1 @@ +Fixed ``-W`` option values being duplicated in ``Config.known_args_namespace``. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 86786c2b04a..2dab4e279b5 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1483,6 +1483,8 @@ def parse(self, args: list[str], addopts: bool = True) -> None: + args ) + # At this point, self.option contains only defaults from the _processopt + # callback. ns = self._parser.parse_known_args(args, namespace=copy.copy(self.option)) rootpath, inipath, inicfg, ignored_config_files = determine_setup( inifile=ns.inifilename, @@ -1533,7 +1535,12 @@ def parse(self, args: list[str], addopts: bool = True) -> None: # are going to be loaded. self.pluginmanager.consider_env() - self._parser.parse_known_args(args, namespace=self.known_args_namespace) + # Parse again, now including options added in pytest_addoption + # by third-party plugins loaded above. This way they're available + # on early_config in the pytest_load_initial_conftests hook call below. + self.known_args_namespace = self._parser.parse_known_args( + args, namespace=copy.copy(self.option) + ) self._validate_plugins() self._warn_about_skipped_plugins() diff --git a/testing/test_warnings.py b/testing/test_warnings.py index d4a5038d5d2..e2363bd884a 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -1038,3 +1038,12 @@ def test_one(): result = pytester.runpytest() result.assert_outcomes(passed=1, warnings=1) assert result.ret == ExitCode.OK + + +def test_pythonwarnings_not_duplicated(pytester: Pytester) -> None: + """Regression test for #13484: -W values should not be duplicated in + known_args_namespace due to the arg parser being called multiple times.""" + config = pytester.parseconfig("-W", "error") + warnings_list = config.known_args_namespace.pythonwarnings + assert warnings_list is not None + assert warnings_list == ["error"]