From 30f1b81eb27f3589079c434688caa7d1e20e70f9 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Thu, 18 Mar 2021 23:08:03 +0100 Subject: [PATCH 1/9] address #8361 - introduce hook caller wrappers that enable backward compat --- src/_pytest/config/__init__.py | 4 +++- src/_pytest/config/compat.py | 41 ++++++++++++++++++++++++++++++++++ src/_pytest/main.py | 4 +++- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/_pytest/config/compat.py diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 624fbd02f8c..bdb68b3e2d4 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -917,8 +917,10 @@ def __init__( :type: PytestPluginManager """ + from .compat import PathAwareHookProxy + self.trace = self.pluginmanager.trace.root.get("config") - self.hook = self.pluginmanager.hook + self.hook = PathAwareHookProxy(self.pluginmanager.hook) self._inicache: Dict[str, Any] = {} self._override_ini: Sequence[str] = () self._opt2dest: Dict[str, str] = {} diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py new file mode 100644 index 00000000000..2adc2d9196f --- /dev/null +++ b/src/_pytest/config/compat.py @@ -0,0 +1,41 @@ +from typing import TYPE_CHECKING + +from _pytest.nodes import _imply_path + +if TYPE_CHECKING: + from ..compat import LEGACY_PATH + + +import functools + +# hookname: (Path, LEGACY_PATH) +imply_paths_hooks = { + "pytest_ignore_collect": ("fspath", "path"), + "pytest_collect_file": ("fspath", "path"), + "pytest_pycollect_makemodule": ("fspath", "path"), + "pytest_report_header": ("startpath", "startdir"), + "pytest_report_collectionfinish": ("startpath", "startdir"), +} + + +class PathAwareHookProxy: + def __init__(self, hook_caller): + self.__hook_caller = hook_caller + + def __getattr__(self, key): + if key not in imply_paths_hooks: + return getattr(self.__hook_caller, key) + else: + hook = getattr(self.__hook_caller, key) + path_var, fspath_var = imply_paths_hooks[key] + + @functools.wraps(hook) + def fixed_hook(**kw): + path_value = kw.pop(path_var, None) + fspath_value: "LEGACY_PATH" = kw.pop(fspath_var, None) + path_value, fspath_value = _imply_path(path_value, fspath_value) + kw[path_var] = path_value + kw[fspath_var] = fspath_value + return hook(**kw) + + return fixed_hook diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 06cfb1fd54f..97a14ea594c 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -551,7 +551,9 @@ def gethookproxy(self, fspath: "os.PathLike[str]"): remove_mods = pm._conftest_plugins.difference(my_conftestmodules) if remove_mods: # One or more conftests are not in use at this fspath. - proxy = FSHookProxy(pm, remove_mods) + from .config.compat import PathAwareHookProxy + + proxy = PathAwareHookProxy(FSHookProxy(pm, remove_mods)) else: # All plugins are active for this fspath. proxy = self.config.hook From a550db4b6c8c809d6cbf42c11c428da40d3f247e Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 20 Mar 2021 21:50:40 +0100 Subject: [PATCH 2/9] drop internal py.path.local objects from hook calls --- src/_pytest/main.py | 10 +++------- src/_pytest/python.py | 18 +++++------------- src/_pytest/terminal.py | 3 +-- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 97a14ea594c..ffe8b852c43 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -563,9 +563,8 @@ def _recurse(self, direntry: "os.DirEntry[str]") -> bool: if direntry.name == "__pycache__": return False fspath = Path(direntry.path) - path = legacy_path(fspath) ihook = self.gethookproxy(fspath.parent) - if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): + if ihook.pytest_ignore_collect(fspath=fspath, config=self.config): return False norecursepatterns = self.config.getini("norecursedirs") if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns): @@ -575,7 +574,6 @@ def _recurse(self, direntry: "os.DirEntry[str]") -> bool: def _collectfile( self, fspath: Path, handle_dupes: bool = True ) -> Sequence[nodes.Collector]: - path = legacy_path(fspath) assert ( fspath.is_file() ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( @@ -583,9 +581,7 @@ def _collectfile( ) ihook = self.gethookproxy(fspath) if not self.isinitpath(fspath): - if ihook.pytest_ignore_collect( - fspath=fspath, path=path, config=self.config - ): + if ihook.pytest_ignore_collect(fspath=fspath, config=self.config): return () if handle_dupes: @@ -597,7 +593,7 @@ def _collectfile( else: duplicate_paths.add(fspath) - return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self) # type: ignore[no-any-return] + return ihook.pytest_collect_file(fspath=fspath, parent=self) # type: ignore[no-any-return] @overload def perform_collect( diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 04fbb45701b..652c72123b4 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -188,9 +188,7 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: return True -def pytest_collect_file( - fspath: Path, path: LEGACY_PATH, parent: nodes.Collector -) -> Optional["Module"]: +def pytest_collect_file(fspath: Path, parent: nodes.Collector) -> Optional["Module"]: if fspath.suffix == ".py": if not parent.session.isinitpath(fspath): if not path_matches_patterns( @@ -198,9 +196,7 @@ def pytest_collect_file( ): return None ihook = parent.session.gethookproxy(fspath) - module: Module = ihook.pytest_pycollect_makemodule( - fspath=fspath, path=path, parent=parent - ) + module: Module = ihook.pytest_pycollect_makemodule(fspath=fspath, parent=parent) return module return None @@ -675,9 +671,8 @@ def _recurse(self, direntry: "os.DirEntry[str]") -> bool: if direntry.name == "__pycache__": return False fspath = Path(direntry.path) - path = legacy_path(fspath) ihook = self.session.gethookproxy(fspath.parent) - if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): + if ihook.pytest_ignore_collect(fspath=fspath, config=self.config): return False norecursepatterns = self.config.getini("norecursedirs") if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns): @@ -687,7 +682,6 @@ def _recurse(self, direntry: "os.DirEntry[str]") -> bool: def _collectfile( self, fspath: Path, handle_dupes: bool = True ) -> Sequence[nodes.Collector]: - path = legacy_path(fspath) assert ( fspath.is_file() ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( @@ -695,9 +689,7 @@ def _collectfile( ) ihook = self.session.gethookproxy(fspath) if not self.session.isinitpath(fspath): - if ihook.pytest_ignore_collect( - fspath=fspath, path=path, config=self.config - ): + if ihook.pytest_ignore_collect(fspath=fspath, config=self.config): return () if handle_dupes: @@ -709,7 +701,7 @@ def _collectfile( else: duplicate_paths.add(fspath) - return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self) # type: ignore[no-any-return] + return ihook.pytest_collect_file(fspath=fspath, parent=self) # type: ignore[no-any-return] def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: this_path = self.path.parent diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 2c95113e561..252f898bfa6 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -716,7 +716,7 @@ def pytest_sessionstart(self, session: "Session") -> None: msg += " -- " + str(sys.executable) self.write_line(msg) lines = self.config.hook.pytest_report_header( - config=self.config, startpath=self.startpath, startdir=self.startdir + config=self.config, startpath=self.startpath ) self._write_report_lines_from_hooks(lines) @@ -753,7 +753,6 @@ def pytest_collection_finish(self, session: "Session") -> None: lines = self.config.hook.pytest_report_collectionfinish( config=self.config, startpath=self.startpath, - startdir=self.startdir, items=session.items, ) self._write_report_lines_from_hooks(lines) From 29940227534e6d5860990e54581afb6658d9f6d2 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 20 Mar 2021 23:01:18 +0100 Subject: [PATCH 3/9] reshape typing for hook invocation proxying --- src/_pytest/config/compat.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index 2adc2d9196f..28b0b524a18 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,13 +1,10 @@ -from typing import TYPE_CHECKING +import functools +from pathlib import Path +from typing import Optional +from ..compat import LEGACY_PATH from _pytest.nodes import _imply_path -if TYPE_CHECKING: - from ..compat import LEGACY_PATH - - -import functools - # hookname: (Path, LEGACY_PATH) imply_paths_hooks = { "pytest_ignore_collect": ("fspath", "path"), @@ -31,8 +28,8 @@ def __getattr__(self, key): @functools.wraps(hook) def fixed_hook(**kw): - path_value = kw.pop(path_var, None) - fspath_value: "LEGACY_PATH" = kw.pop(fspath_var, None) + path_value: Optional[Path] = kw.pop(path_var, None) + fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None) path_value, fspath_value = _imply_path(path_value, fspath_value) kw[path_var] = path_value kw[fspath_var] = fspath_value From 4ddf6c647c7fdc94efb55e64a01ee4e2c0b696e9 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 20 Mar 2021 23:39:38 +0100 Subject: [PATCH 4/9] test warnings and fix invocation bugs --- .pre-commit-config.yaml | 2 +- src/_pytest/config/compat.py | 14 ++++++++++++-- src/_pytest/deprecated.py | 4 ++++ testing/deprecated_test.py | 21 +++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b96fdccf10c..13220430962 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,7 +89,7 @@ repos: types: [python] - id: py-path-deprecated name: py.path usage is deprecated + exclude: docs|src/_pytest/deprecated.py|testing/deprecated_test.py language: pygrep entry: \bpy\.path\.local - exclude: docs types: [python] diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index 28b0b524a18..82572a97090 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,8 +1,9 @@ -import functools +import warnings from pathlib import Path from typing import Optional from ..compat import LEGACY_PATH +from ..deprecated import HOOK_LEGACY_PATH_ARG from _pytest.nodes import _imply_path # hookname: (Path, LEGACY_PATH) @@ -19,6 +20,9 @@ class PathAwareHookProxy: def __init__(self, hook_caller): self.__hook_caller = hook_caller + def __dir__(self): + return dir(self.__hook_caller) + def __getattr__(self, key): if key not in imply_paths_hooks: return getattr(self.__hook_caller, key) @@ -26,13 +30,19 @@ def __getattr__(self, key): hook = getattr(self.__hook_caller, key) path_var, fspath_var = imply_paths_hooks[key] - @functools.wraps(hook) def fixed_hook(**kw): path_value: Optional[Path] = kw.pop(path_var, None) fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None) + if fspath_value is not None: + warnings.warn( + HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg=fspath_var, pathlib_path_arg=path_var + ) + ) path_value, fspath_value = _imply_path(path_value, fspath_value) kw[path_var] = path_value kw[fspath_var] = fspath_value return hook(**kw) + fixed_hook.__name__ = key return fixed_hook diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 596574877bf..9ac4d81b442 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -95,6 +95,10 @@ "see https://docs.pytest.org/en/latest/deprecations.html#node-fspath-in-favor-of-pathlib-and-node-path", ) +HOOK_LEGACY_PATH_ARG = UnformattedWarning( + PytestDeprecationWarning, + "{pylib_path_arg} : py.path.local is deprecated, please use {pathlib_path_arg} : pathlib.Path", +) # You want to make some `__init__` or function "private". # # def my_private_function(some, args): diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 18300f62a1a..41db4242730 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -4,7 +4,9 @@ import pytest from _pytest import deprecated +from _pytest.compat import legacy_path from _pytest.pytester import Pytester +from pytest import PytestDeprecationWarning @pytest.mark.parametrize("attribute", pytest.collect.__all__) # type: ignore @@ -153,3 +155,22 @@ def test_raising_unittest_skiptest_during_collection_is_deprecated( "*PytestDeprecationWarning: Raising unittest.SkipTest*", ] ) + + +def test_hookproxy_warnings_for_fspath(pytestconfig, tmp_path, request): + path = legacy_path(tmp_path) + + with pytest.warns( + PytestDeprecationWarning, + match="path : py.path.local is deprecated, please use fspath : pathlib.Path", + ): + pytestconfig.hook.pytest_ignore_collect( + config=pytestconfig, path=path, fspath=tmp_path + ) + with pytest.warns( + PytestDeprecationWarning, + match="path : py.path.local is deprecated, please use fspath : pathlib.Path", + ): + request.node.ihook.pytest_ignore_collect( + config=pytestconfig, path=path, fspath=tmp_path + ) From 7ac7610089b5e0e0f9ab0c8276c53cd8e4567ed1 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 20 Mar 2021 23:44:36 +0100 Subject: [PATCH 5/9] add tresting for implication --- testing/deprecated_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 41db4242730..b4e73dd5b50 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -174,3 +174,6 @@ def test_hookproxy_warnings_for_fspath(pytestconfig, tmp_path, request): request.node.ihook.pytest_ignore_collect( config=pytestconfig, path=path, fspath=tmp_path ) + + pytestconfig.hook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) + request.node.ihook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) From bad1963697ab8d6538368a3e86f7848bfe8c63ea Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Mon, 29 Mar 2021 22:29:35 +0200 Subject: [PATCH 6/9] fix #8361: address review/quality comments --- doc/en/deprecations.rst | 14 ++++++++++++++ src/_pytest/config/compat.py | 19 ++++++++++++++++--- src/_pytest/deprecated.py | 4 +++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index 6ecb37b385a..d6b108d5012 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -19,6 +19,20 @@ Below is a complete list of all pytest features which are considered deprecated. :class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters `. +``py.path.local`` arguments for hooks replaced with ``pathlib.Path`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to support the transition oto pathlib, the following hooks added additional arugments: + +* ``pytest_ignore_collect(fspath: pathlib.Path)`` +* ``pytest_collect_file(fspath: pathlib.Path)`` +* ``pytest_pycollect_makemodule(fspath: pathlib.Path)`` +* ``pytest_report_header(startpath: pathlib.Path)`` +* ``pytest_report_collectionfinish(startpath: pathlib.Path)`` + +The accompanying ``py.path.local`` based paths have been deprecated. + + ``Node.fspath`` in favor of ``pathlib`` and ``Node.path`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index 82572a97090..d9e6e280cee 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,3 +1,4 @@ +import functools import warnings from pathlib import Path from typing import Optional @@ -17,20 +18,31 @@ class PathAwareHookProxy: + """ + this helper wraps around hook callers + until pluggy supports fixingcalls, this one will do + + it currently doesnt return full hook caller proxies for fixed hooks, + this may have to be changed later depending on bugs + """ + def __init__(self, hook_caller): self.__hook_caller = hook_caller def __dir__(self): return dir(self.__hook_caller) - def __getattr__(self, key): + def __getattr__(self, key, _wraps=functools.wraps): + hook = getattr(self.__hook_caller, key) if key not in imply_paths_hooks: - return getattr(self.__hook_caller, key) + self.__dict__[key] = hook + return hook else: - hook = getattr(self.__hook_caller, key) path_var, fspath_var = imply_paths_hooks[key] + @_wraps(hook) def fixed_hook(**kw): + path_value: Optional[Path] = kw.pop(path_var, None) fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None) if fspath_value is not None: @@ -45,4 +57,5 @@ def fixed_hook(**kw): return hook(**kw) fixed_hook.__name__ = key + self.__dict__[key] = fixed_hook return fixed_hook diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 9ac4d81b442..7a09d516362 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -97,7 +97,9 @@ HOOK_LEGACY_PATH_ARG = UnformattedWarning( PytestDeprecationWarning, - "{pylib_path_arg} : py.path.local is deprecated, please use {pathlib_path_arg} : pathlib.Path", + "The ({pylib_path_arg}: py.path.local) argument is deprecated, please use ({pathlib_path_arg}: pathlib.Path)\n" + "see https://docs.pytest.org/en/latest/deprecations.html" + "#py-path-local-arguments-for-hooks-replaced-with-pathlib-path", ) # You want to make some `__init__` or function "private". # From deb5b5bd963cb1c283053d4ea703de555c162c3c Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 2 Apr 2021 00:58:05 +0200 Subject: [PATCH 7/9] fix #8371: fix stack-level --- src/_pytest/config/compat.py | 3 ++- testing/deprecated_test.py | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index d9e6e280cee..c93f3738d4f 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -49,7 +49,8 @@ def fixed_hook(**kw): warnings.warn( HOOK_LEGACY_PATH_ARG.format( pylib_path_arg=fspath_var, pathlib_path_arg=path_var - ) + ), + stacklevel=2, ) path_value, fspath_value = _imply_path(path_value, fspath_value) kw[path_var] = path_value diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index b4e73dd5b50..0c84ab422a1 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -160,20 +160,22 @@ def test_raising_unittest_skiptest_during_collection_is_deprecated( def test_hookproxy_warnings_for_fspath(pytestconfig, tmp_path, request): path = legacy_path(tmp_path) - with pytest.warns( - PytestDeprecationWarning, - match="path : py.path.local is deprecated, please use fspath : pathlib.Path", - ): + PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(fspath: pathlib\.Path.*" + + with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: pytestconfig.hook.pytest_ignore_collect( config=pytestconfig, path=path, fspath=tmp_path ) - with pytest.warns( - PytestDeprecationWarning, - match="path : py.path.local is deprecated, please use fspath : pathlib.Path", - ): + (record,) = r + assert record.filename == __file__ + assert record.lineno == 166 + + with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: request.node.ihook.pytest_ignore_collect( config=pytestconfig, path=path, fspath=tmp_path ) - + (record,) = r + assert record.filename == __file__ + assert record.lineno == 174 pytestconfig.hook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) request.node.ihook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) From 53ebe34ca2ede967d8636fe0632081319ea80ea9 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 3 Apr 2021 12:46:50 +0200 Subject: [PATCH 8/9] Apply suggestions from code review Co-authored-by: Bruno Oliveira --- doc/en/deprecations.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index d6b108d5012..db04a48b369 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -22,15 +22,15 @@ Below is a complete list of all pytest features which are considered deprecated. ``py.path.local`` arguments for hooks replaced with ``pathlib.Path`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In order to support the transition oto pathlib, the following hooks added additional arugments: +In order to support the transition to :mod:`pathlib`, the following hooks now receive additional arguments: -* ``pytest_ignore_collect(fspath: pathlib.Path)`` -* ``pytest_collect_file(fspath: pathlib.Path)`` -* ``pytest_pycollect_makemodule(fspath: pathlib.Path)`` -* ``pytest_report_header(startpath: pathlib.Path)`` -* ``pytest_report_collectionfinish(startpath: pathlib.Path)`` +* :func:`pytest_ignore_collect(fspath: pathlib.Path) <_pytest.hookspec.pytest_ignore_collect>` +* :func:`pytest_collect_file(fspath: pathlib.Path) <_pytest.hookspec.pytest_collect_file>` +* :func:`pytest_pycollect_makemodule(fspath: pathlib.Path) <_pytest.hookspec.pytest_pycollect_makemodule>` +* :func:`pytest_report_header(startpath: pathlib.Path) <_pytest.hookspec.pytest_report_header>` +* :func:`pytest_report_collectionfinish(startpath: pathlib.Path) <_pytest.hookspec.pytest_report_collectionfinish>` -The accompanying ``py.path.local`` based paths have been deprecated. +The accompanying ``py.path.local`` based paths have been deprecated: plugins which manually invoke those hooks should only pass the new ``pathlib.Path`` arguments, and users should change their hook implementations to use the new ``pathlib.Path`` arguments. ``Node.fspath`` in favor of ``pathlib`` and ``Node.path`` From aa10bff750b0468b6187aa3eb7f84553fc07597b Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 3 Apr 2021 14:51:36 +0200 Subject: [PATCH 9/9] fix deprecation test for path/fspath hook args --- testing/deprecated_test.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 0c84ab422a1..1d012adf250 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -1,4 +1,5 @@ import re +import sys import warnings from unittest import mock @@ -157,25 +158,23 @@ def test_raising_unittest_skiptest_during_collection_is_deprecated( ) -def test_hookproxy_warnings_for_fspath(pytestconfig, tmp_path, request): +@pytest.mark.parametrize("hooktype", ["hook", "ihook"]) +def test_hookproxy_warnings_for_fspath(tmp_path, hooktype, request): path = legacy_path(tmp_path) PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(fspath: pathlib\.Path.*" + if hooktype == "ihook": + hooks = request.node.ihook + else: + hooks = request.config.hook with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: - pytestconfig.hook.pytest_ignore_collect( - config=pytestconfig, path=path, fspath=tmp_path - ) - (record,) = r - assert record.filename == __file__ - assert record.lineno == 166 + l1 = sys._getframe().f_lineno + hooks.pytest_ignore_collect(config=request.config, path=path, fspath=tmp_path) + l2 = sys._getframe().f_lineno - with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: - request.node.ihook.pytest_ignore_collect( - config=pytestconfig, path=path, fspath=tmp_path - ) (record,) = r assert record.filename == __file__ - assert record.lineno == 174 - pytestconfig.hook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) - request.node.ihook.pytest_ignore_collect(config=pytestconfig, fspath=tmp_path) + assert l1 < record.lineno < l2 + + hooks.pytest_ignore_collect(config=request.config, fspath=tmp_path)