From 58136c53762fe90b06814750c69f42e034d82f09 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Thu, 18 Apr 2024 22:08:28 +0300 Subject: [PATCH] hookspec: deprecate hookimpls requesting py.path parameters --- .pre-commit-config.yaml | 2 +- changelog/12069.deprecation.rst | 12 ++++++++++ changelog/12069.trivial.rst | 1 + doc/en/requirements.txt | 2 +- pyproject.toml | 2 +- src/_pytest/hookspec.py | 41 +++++++++++++++++++++++++++++++-- testing/deprecated_test.py | 26 +++++++++++++++++++++ 7 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 changelog/12069.deprecation.rst create mode 100644 changelog/12069.trivial.rst diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5d216d2db..81ed1d5f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,7 +34,7 @@ repos: additional_dependencies: - iniconfig>=1.1.0 - attrs>=19.2.0 - - pluggy>=1.4.0 + - pluggy>=1.5.0 - packaging - tomli - types-pkg_resources diff --git a/changelog/12069.deprecation.rst b/changelog/12069.deprecation.rst new file mode 100644 index 000000000..c8798b5ff --- /dev/null +++ b/changelog/12069.deprecation.rst @@ -0,0 +1,12 @@ +A deprecation warning is now raised when implementations of one of the following hooks request a deprecated ``py.path.local`` parameter instead of the ``pathlib.Path`` parameter which replaced it: + +- :hook:`pytest_ignore_collect` - the ``path`` parameter - use ``collection_path`` instead. +- :hook:`pytest_collect_file` - the ``path`` parameter - use ``file_path`` instead. +- :hook:`pytest_pycollect_makemodule` - the ``path`` parameter - use ``module_path`` instead. +- :hook:`pytest_report_header` - the ``startdir`` parameter - use ``start_path`` instead. +- :hook:`pytest_report_collectionfinish` - the ``startdir`` parameter - use ``start_path`` instead. + +The replacement parameters are available since pytest 7.0.0. +The old parameters will be removed in pytest 9.0.0. + +See :ref:`legacy-path-hooks-deprecated` for more details. diff --git a/changelog/12069.trivial.rst b/changelog/12069.trivial.rst new file mode 100644 index 000000000..8eb9b0c46 --- /dev/null +++ b/changelog/12069.trivial.rst @@ -0,0 +1 @@ +``pluggy>=1.5.0`` is now required. diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt index 524157404..974988c8c 100644 --- a/doc/en/requirements.txt +++ b/doc/en/requirements.txt @@ -1,5 +1,5 @@ pallets-sphinx-themes -pluggy>=1.2.0 +pluggy>=1.5.0 pygments-pytest>=2.3.0 sphinx-removed-in>=0.2.0 sphinx>=7 diff --git a/pyproject.toml b/pyproject.toml index 4d4b52287..43efacf09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ 'exceptiongroup>=1.0.0rc8; python_version < "3.11"', "iniconfig", "packaging", - "pluggy<2.0,>=1.4", + "pluggy<2.0,>=1.5", 'tomli>=1; python_version < "3.11"', ] [project.optional-dependencies] diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index db55bd82d..acfe7eb95 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -15,6 +15,8 @@ from typing import Union from pluggy import HookspecMarker +from .deprecated import HOOK_LEGACY_PATH_ARG + if TYPE_CHECKING: import pdb @@ -297,7 +299,14 @@ def pytest_collection_finish(session: "Session") -> None: """ -@hookspec(firstresult=True) +@hookspec( + firstresult=True, + warn_on_impl_args={ + "path": HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg="path", pathlib_path_arg="collection_path" + ), + }, +) def pytest_ignore_collect( collection_path: Path, path: "LEGACY_PATH", config: "Config" ) -> Optional[bool]: @@ -356,6 +365,13 @@ def pytest_collect_directory(path: Path, parent: "Collector") -> "Optional[Colle """ +@hookspec( + warn_on_impl_args={ + "path": HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg="path", pathlib_path_arg="file_path" + ), + }, +) def pytest_collect_file( file_path: Path, path: "LEGACY_PATH", parent: "Collector" ) -> "Optional[Collector]": @@ -468,7 +484,14 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor # ------------------------------------------------------------------------- -@hookspec(firstresult=True) +@hookspec( + firstresult=True, + warn_on_impl_args={ + "path": HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg="path", pathlib_path_arg="module_path" + ), + }, +) def pytest_pycollect_makemodule( module_path: Path, path: "LEGACY_PATH", parent ) -> Optional["Module"]: @@ -994,6 +1017,13 @@ def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> No # ------------------------------------------------------------------------- +@hookspec( + warn_on_impl_args={ + "startdir": HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg="startdir", pathlib_path_arg="start_path" + ), + }, +) def pytest_report_header( # type:ignore[empty-body] config: "Config", start_path: Path, startdir: "LEGACY_PATH" ) -> Union[str, List[str]]: @@ -1022,6 +1052,13 @@ def pytest_report_header( # type:ignore[empty-body] """ +@hookspec( + warn_on_impl_args={ + "startdir": HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg="startdir", pathlib_path_arg="start_path" + ), + }, +) def pytest_report_collectionfinish( # type:ignore[empty-body] config: "Config", start_path: Path, diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 2be4d6dfc..9e83a49d5 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -121,6 +121,32 @@ def test_hookproxy_warnings_for_pathlib(tmp_path, hooktype, request): ) +def test_hookimpl_warnings_for_pathlib() -> None: + class Plugin: + def pytest_ignore_collect(self, path: object) -> None: + raise NotImplementedError() + + def pytest_collect_file(self, path: object) -> None: + raise NotImplementedError() + + def pytest_pycollect_makemodule(self, path: object) -> None: + raise NotImplementedError() + + def pytest_report_header(self, startdir: object) -> str: + raise NotImplementedError() + + def pytest_report_collectionfinish(self, startdir: object) -> str: + raise NotImplementedError() + + pm = pytest.PytestPluginManager() + with pytest.warns( + pytest.PytestRemovedIn9Warning, + match=r"py\.path\.local.* argument is deprecated", + ) as wc: + pm.register(Plugin()) + assert len(wc.list) == 5 + + def test_node_ctor_fspath_argument_is_deprecated(pytester: Pytester) -> None: mod = pytester.getmodulecol("")