diff --git a/changelog/9396.bugfix.rst b/changelog/9396.bugfix.rst new file mode 100644 index 000000000..dcb83bbc1 --- /dev/null +++ b/changelog/9396.bugfix.rst @@ -0,0 +1 @@ +Ensure :attr:`pytest.Config.inifile` is available during the :func:`pytest_cmdline_main <_pytest.hookspec.pytest_cmdline_main>` hook (regression during ``7.0.0rc1``). diff --git a/src/_pytest/legacypath.py b/src/_pytest/legacypath.py index 4c2db9412..37e8c2422 100644 --- a/src/_pytest/legacypath.py +++ b/src/_pytest/legacypath.py @@ -403,14 +403,44 @@ def Node_fspath_set(self: Node, value: LEGACY_PATH) -> None: self.path = Path(value) +@hookimpl(tryfirst=True) +def pytest_load_initial_conftests(early_config: Config) -> None: + """Monkeypatch legacy path attributes in several classes, as early as possible.""" + mp = MonkeyPatch() + early_config.add_cleanup(mp.undo) + + # Add Cache.makedir(). + mp.setattr(Cache, "makedir", Cache_makedir, raising=False) + + # Add FixtureRequest.fspath property. + mp.setattr(FixtureRequest, "fspath", property(FixtureRequest_fspath), raising=False) + + # Add TerminalReporter.startdir property. + mp.setattr( + TerminalReporter, "startdir", property(TerminalReporter_startdir), raising=False + ) + + # Add Config.{invocation_dir,rootdir,inifile} properties. + mp.setattr(Config, "invocation_dir", property(Config_invocation_dir), raising=False) + mp.setattr(Config, "rootdir", property(Config_rootdir), raising=False) + mp.setattr(Config, "inifile", property(Config_inifile), raising=False) + + # Add Session.startdir property. + mp.setattr(Session, "startdir", property(Session_stardir), raising=False) + + # Add pathlist configuration type. + mp.setattr(Config, "_getini_unknown_type", Config__getini_unknown_type) + + # Add Node.fspath property. + mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False) + + @hookimpl def pytest_configure(config: Config) -> None: - import pytest - - mp = pytest.MonkeyPatch() - config.add_cleanup(mp.undo) - + """Installs the LegacyTmpdirPlugin if the ``tmpdir`` plugin is also installed.""" if config.pluginmanager.has_plugin("tmpdir"): + mp = MonkeyPatch() + config.add_cleanup(mp.undo) # Create TmpdirFactory and attach it to the config object. # # This is to comply with existing plugins which expect the handler to be @@ -427,35 +457,6 @@ def pytest_configure(config: Config) -> None: config.pluginmanager.register(LegacyTmpdirPlugin, "legacypath-tmpdir") - # Add Cache.makedir(). - mp.setattr(pytest.Cache, "makedir", Cache_makedir, raising=False) - - # Add FixtureRequest.fspath property. - mp.setattr( - pytest.FixtureRequest, "fspath", property(FixtureRequest_fspath), raising=False - ) - - # Add TerminalReporter.startdir property. - mp.setattr( - TerminalReporter, "startdir", property(TerminalReporter_startdir), raising=False - ) - - # Add Config.{invocation_dir,rootdir,inifile} properties. - mp.setattr( - pytest.Config, "invocation_dir", property(Config_invocation_dir), raising=False - ) - mp.setattr(pytest.Config, "rootdir", property(Config_rootdir), raising=False) - mp.setattr(pytest.Config, "inifile", property(Config_inifile), raising=False) - - # Add Session.startdir property. - mp.setattr(pytest.Session, "startdir", property(Session_stardir), raising=False) - - # Add pathlist configuration type. - mp.setattr(pytest.Config, "_getini_unknown_type", Config__getini_unknown_type) - - # Add Node.fspath property. - mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False) - @hookimpl def pytest_plugin_registered(plugin: object, manager: PytestPluginManager) -> None: diff --git a/testing/test_config.py b/testing/test_config.py index 9a57b919d..f691d3ed5 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1268,6 +1268,7 @@ def test_load_initial_conftest_last_ordering(_config_for_test): expected = [ "_pytest.config", m.__module__, + "_pytest.legacypath", "_pytest.pythonpath", "_pytest.capture", "_pytest.warnings", diff --git a/testing/test_legacypath.py b/testing/test_legacypath.py index 1d3fdb4bd..fbfd88b73 100644 --- a/testing/test_legacypath.py +++ b/testing/test_legacypath.py @@ -161,3 +161,20 @@ def test_override_ini_paths(pytester: pytest.Pytester) -> None: ) result = pytester.runpytest("--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s") result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"]) + + +def test_inifile_from_cmdline_main_hook(pytester: pytest.Pytester) -> None: + """Ensure Config.inifile is available during pytest_cmdline_main (#9396).""" + p = pytester.makeini( + """ + [pytest] + """ + ) + pytester.makeconftest( + """ + def pytest_cmdline_main(config): + print("pytest_cmdline_main inifile =", config.inifile) + """ + ) + result = pytester.runpytest_subprocess("-s") + result.stdout.fnmatch_lines(f"*pytest_cmdline_main inifile = {p}")