Skip to content

Commit a98f02d

Browse files
committed
Remove deprecated py.path hook arguments
1 parent 0f18a7f commit a98f02d

File tree

7 files changed

+51
-161
lines changed

7 files changed

+51
-161
lines changed

doc/en/deprecations.rst

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -104,31 +104,6 @@ Changed ``hookwrapper`` attributes:
104104
* ``historic``
105105

106106

107-
``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
108-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109-
110-
.. deprecated:: 7.0
111-
112-
In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the following hooks now receive additional arguments:
113-
114-
* :hook:`pytest_ignore_collect(collection_path: pathlib.Path) <pytest_ignore_collect>` as equivalent to ``path``
115-
* :hook:`pytest_collect_file(file_path: pathlib.Path) <pytest_collect_file>` as equivalent to ``path``
116-
* :hook:`pytest_pycollect_makemodule(module_path: pathlib.Path) <pytest_pycollect_makemodule>` as equivalent to ``path``
117-
* :hook:`pytest_report_header(start_path: pathlib.Path) <pytest_report_header>` as equivalent to ``startdir``
118-
* :hook:`pytest_report_collectionfinish(start_path: pathlib.Path) <pytest_report_collectionfinish>` as equivalent to ``startdir``
119-
120-
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.
121-
122-
.. note::
123-
The name of the :class:`~_pytest.nodes.Node` arguments and attributes,
124-
:ref:`outlined above <node-ctor-fspath-deprecation>` (the new attribute
125-
being ``path``) is **the opposite** of the situation for hooks (the old
126-
argument being ``path``).
127-
128-
This is an unfortunate artifact due to historical reasons, which should be
129-
resolved in future versions as we slowly get rid of the :pypi:`py`
130-
dependency (see :issue:`9283` for a longer discussion).
131-
132107
Directly constructing internal classes
133108
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134109

@@ -276,6 +251,33 @@ an appropriate period of deprecation has passed.
276251

277252
Some breaking changes which could not be deprecated are also listed.
278253

254+
``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
255+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
256+
257+
.. deprecated:: 7.0
258+
.. versionremoved:: 8.0
259+
260+
In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the following hooks now receive additional arguments:
261+
262+
* :hook:`pytest_ignore_collect(collection_path: pathlib.Path) <pytest_ignore_collect>` as equivalent to ``path``
263+
* :hook:`pytest_collect_file(file_path: pathlib.Path) <pytest_collect_file>` as equivalent to ``path``
264+
* :hook:`pytest_pycollect_makemodule(module_path: pathlib.Path) <pytest_pycollect_makemodule>` as equivalent to ``path``
265+
* :hook:`pytest_report_header(start_path: pathlib.Path) <pytest_report_header>` as equivalent to ``startdir``
266+
* :hook:`pytest_report_collectionfinish(start_path: pathlib.Path) <pytest_report_collectionfinish>` as equivalent to ``startdir``
267+
268+
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.
269+
270+
.. note::
271+
The name of the :class:`~_pytest.nodes.Node` arguments and attributes,
272+
:ref:`outlined above <node-ctor-fspath-deprecation>` (the new attribute
273+
being ``path``) is **the opposite** of the situation for hooks (the old
274+
argument being ``path``).
275+
276+
This is an unfortunate artifact due to historical reasons, which should be
277+
resolved in future versions as we slowly get rid of the :pypi:`py`
278+
dependency (see :issue:`9283` for a longer discussion).
279+
280+
279281
.. _nose-deprecation:
280282

281283
Support for tests written for nose

src/_pytest/config/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
from typing import TYPE_CHECKING
3939
from typing import Union
4040

41-
import pluggy
4241
from pluggy import HookimplMarker
4342
from pluggy import HookimplOpts
4443
from pluggy import HookspecMarker
@@ -48,7 +47,6 @@
4847
import _pytest._code
4948
import _pytest.deprecated
5049
import _pytest.hookspec
51-
from .compat import PathAwareHookProxy
5250
from .exceptions import PrintHelp as PrintHelp
5351
from .exceptions import UsageError as UsageError
5452
from .findpaths import determine_setup
@@ -1008,7 +1006,7 @@ def __init__(
10081006
self._store = self.stash
10091007

10101008
self.trace = self.pluginmanager.trace.root.get("config")
1011-
self.hook: pluggy.HookRelay = PathAwareHookProxy(self.pluginmanager.hook) # type: ignore[assignment]
1009+
self.hook = self.pluginmanager.hook # type: ignore[assignment]
10121010
self._inicache: Dict[str, Any] = {}
10131011
self._override_ini: Sequence[str] = ()
10141012
self._opt2dest: Dict[str, str] = {}

src/_pytest/config/compat.py

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
11
from __future__ import annotations
22

3-
import functools
4-
import warnings
53
from pathlib import Path
6-
from typing import Mapping
7-
8-
import pluggy
94

105
from ..compat import LEGACY_PATH
11-
from ..compat import legacy_path
12-
from ..deprecated import HOOK_LEGACY_PATH_ARG
13-
14-
# hookname: (Path, LEGACY_PATH)
15-
imply_paths_hooks: Mapping[str, tuple[str, str]] = {
16-
"pytest_ignore_collect": ("collection_path", "path"),
17-
"pytest_collect_file": ("file_path", "path"),
18-
"pytest_pycollect_makemodule": ("module_path", "path"),
19-
"pytest_report_header": ("start_path", "startdir"),
20-
"pytest_report_collectionfinish": ("start_path", "startdir"),
21-
}
226

237

248
def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
@@ -27,57 +11,3 @@ def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
2711
f"Path({fspath!r}) != {path!r}\n"
2812
"if both path and fspath are given they need to be equal"
2913
)
30-
31-
32-
class PathAwareHookProxy:
33-
"""
34-
this helper wraps around hook callers
35-
until pluggy supports fixingcalls, this one will do
36-
37-
it currently doesn't return full hook caller proxies for fixed hooks,
38-
this may have to be changed later depending on bugs
39-
"""
40-
41-
def __init__(self, hook_relay: pluggy.HookRelay) -> None:
42-
self._hook_relay = hook_relay
43-
44-
def __dir__(self) -> list[str]:
45-
return dir(self._hook_relay)
46-
47-
def __getattr__(self, key: str) -> pluggy.HookCaller:
48-
hook: pluggy.HookCaller = getattr(self._hook_relay, key)
49-
if key not in imply_paths_hooks:
50-
self.__dict__[key] = hook
51-
return hook
52-
else:
53-
path_var, fspath_var = imply_paths_hooks[key]
54-
55-
@functools.wraps(hook)
56-
def fixed_hook(**kw):
57-
path_value: Path | None = kw.pop(path_var, None)
58-
fspath_value: LEGACY_PATH | None = kw.pop(fspath_var, None)
59-
if fspath_value is not None:
60-
warnings.warn(
61-
HOOK_LEGACY_PATH_ARG.format(
62-
pylib_path_arg=fspath_var, pathlib_path_arg=path_var
63-
),
64-
stacklevel=2,
65-
)
66-
if path_value is not None:
67-
if fspath_value is not None:
68-
_check_path(path_value, fspath_value)
69-
else:
70-
fspath_value = legacy_path(path_value)
71-
else:
72-
assert fspath_value is not None
73-
path_value = Path(fspath_value)
74-
75-
kw[path_var] = path_value
76-
kw[fspath_var] = fspath_value
77-
return hook(**kw)
78-
79-
fixed_hook.name = hook.name # type: ignore[attr-defined]
80-
fixed_hook.spec = hook.spec # type: ignore[attr-defined]
81-
fixed_hook.__name__ = key
82-
self.__dict__[key] = fixed_hook
83-
return fixed_hook # type: ignore[return-value]

src/_pytest/deprecated.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,6 @@
3535
PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.")
3636

3737

38-
HOOK_LEGACY_PATH_ARG = UnformattedWarning(
39-
PytestRemovedIn8Warning,
40-
"The ({pylib_path_arg}: py.path.local) argument is deprecated, please use ({pathlib_path_arg}: pathlib.Path)\n"
41-
"see https://docs.pytest.org/en/latest/deprecations.html"
42-
"#py-path-local-arguments-for-hooks-replaced-with-pathlib-path",
43-
)
44-
4538
NODE_CTOR_FSPATH_ARG = UnformattedWarning(
4639
PytestRemovedIn8Warning,
4740
"The (fspath: py.path.local) argument to {node_type_name} is deprecated. "

src/_pytest/hookspec.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
from _pytest.runner import CallInfo
4141
from _pytest.terminal import TerminalReporter
4242
from _pytest.terminal import TestShortLogReport
43-
from _pytest.compat import LEGACY_PATH
4443

4544

4645
hookspec = HookspecMarker("pytest")
@@ -246,9 +245,7 @@ def pytest_collection_finish(session: "Session") -> None:
246245

247246

248247
@hookspec(firstresult=True)
249-
def pytest_ignore_collect(
250-
collection_path: Path, path: "LEGACY_PATH", config: "Config"
251-
) -> Optional[bool]:
248+
def pytest_ignore_collect(collection_path: Path, config: "Config") -> Optional[bool]:
252249
"""Return True to prevent considering this path for collection.
253250
254251
This hook is consulted for all files and directories prior to calling
@@ -262,8 +259,10 @@ def pytest_ignore_collect(
262259
263260
.. versionchanged:: 7.0.0
264261
The ``collection_path`` parameter was added as a :class:`pathlib.Path`
265-
equivalent of the ``path`` parameter. The ``path`` parameter
266-
has been deprecated.
262+
equivalent of the ``path`` parameter.
263+
264+
.. versionchanged:: 8.0.0
265+
The ``path`` parameter has been removed.
267266
"""
268267

269268

@@ -288,9 +287,7 @@ def pytest_collect_directory(path: Path, parent: "Collector") -> "Optional[Colle
288287
"""
289288

290289

291-
def pytest_collect_file(
292-
file_path: Path, path: "LEGACY_PATH", parent: "Collector"
293-
) -> "Optional[Collector]":
290+
def pytest_collect_file(file_path: Path, parent: "Collector") -> "Optional[Collector]":
294291
"""Create a :class:`~pytest.Collector` for the given path, or None if not relevant.
295292
296293
For best results, the returned collector should be a subclass of
@@ -303,8 +300,10 @@ def pytest_collect_file(
303300
304301
.. versionchanged:: 7.0.0
305302
The ``file_path`` parameter was added as a :class:`pathlib.Path`
306-
equivalent of the ``path`` parameter. The ``path`` parameter
307-
has been deprecated.
303+
equivalent of the ``path`` parameter.
304+
305+
.. versionchanged:: 8.0.0
306+
The ``path`` parameter was removed.
308307
"""
309308

310309

@@ -363,9 +362,7 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor
363362

364363

365364
@hookspec(firstresult=True)
366-
def pytest_pycollect_makemodule(
367-
module_path: Path, path: "LEGACY_PATH", parent
368-
) -> Optional["Module"]:
365+
def pytest_pycollect_makemodule(module_path: Path, parent) -> Optional["Module"]:
369366
"""Return a :class:`pytest.Module` collector or None for the given path.
370367
371368
This hook will be called for each matching test module path.
@@ -381,7 +378,8 @@ def pytest_pycollect_makemodule(
381378
The ``module_path`` parameter was added as a :class:`pathlib.Path`
382379
equivalent of the ``path`` parameter.
383380
384-
The ``path`` parameter has been deprecated in favor of ``fspath``.
381+
.. versionchanged:: 8.0.0
382+
The ``path`` parameter has been removed in favor of ``module_path``.
385383
"""
386384

387385

@@ -751,7 +749,7 @@ def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> No
751749

752750

753751
def pytest_report_header( # type:ignore[empty-body]
754-
config: "Config", start_path: Path, startdir: "LEGACY_PATH"
752+
config: "Config", start_path: Path
755753
) -> Union[str, List[str]]:
756754
"""Return a string or list of strings to be displayed as header info for terminal reporting.
757755
@@ -774,15 +772,16 @@ def pytest_report_header( # type:ignore[empty-body]
774772
775773
.. versionchanged:: 7.0.0
776774
The ``start_path`` parameter was added as a :class:`pathlib.Path`
777-
equivalent of the ``startdir`` parameter. The ``startdir`` parameter
778-
has been deprecated.
775+
equivalent of the ``startdir`` parameter.
776+
777+
.. versionchanged:: 8.0.0
778+
The ``startdir`` parameter has been removed.
779779
"""
780780

781781

782782
def pytest_report_collectionfinish( # type:ignore[empty-body]
783783
config: "Config",
784784
start_path: Path,
785-
startdir: "LEGACY_PATH",
786785
items: Sequence["Item"],
787786
) -> Union[str, List[str]]:
788787
"""Return a string or list of strings to be displayed after collection
@@ -806,8 +805,10 @@ def pytest_report_collectionfinish( # type:ignore[empty-body]
806805
807806
.. versionchanged:: 7.0.0
808807
The ``start_path`` parameter was added as a :class:`pathlib.Path`
809-
equivalent of the ``startdir`` parameter. The ``startdir`` parameter
810-
has been deprecated.
808+
equivalent of the ``startdir`` parameter.
809+
810+
.. versionchanged:: 8.0.0
811+
The ``startdir`` parameter has been removed.
811812
"""
812813

813814

src/_pytest/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from _pytest.config import PytestPluginManager
3434
from _pytest.config import UsageError
3535
from _pytest.config.argparsing import Parser
36-
from _pytest.config.compat import PathAwareHookProxy
3736
from _pytest.fixtures import FixtureManager
3837
from _pytest.outcomes import exit
3938
from _pytest.pathlib import absolutepath
@@ -644,7 +643,7 @@ def gethookproxy(self, fspath: "os.PathLike[str]") -> pluggy.HookRelay:
644643
proxy: pluggy.HookRelay
645644
if remove_mods:
646645
# One or more conftests are not in use at this path.
647-
proxy = PathAwareHookProxy(FSHookProxy(pm, remove_mods)) # type: ignore[arg-type,assignment]
646+
proxy = FSHookProxy(pm, remove_mods) # type: ignore[arg-type,assignment]
648647
else:
649648
# All plugins are active for this fspath.
650649
proxy = self.config.hook

testing/deprecated_test.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import re
2-
import sys
3-
from pathlib import Path
42

53
import pytest
64
from _pytest import deprecated
@@ -89,37 +87,6 @@ def __init__(self, foo: int, *, _ispytest: bool = False) -> None:
8987
PrivateInit(10, _ispytest=True)
9088

9189

92-
@pytest.mark.parametrize("hooktype", ["hook", "ihook"])
93-
def test_hookproxy_warnings_for_pathlib(tmp_path, hooktype, request):
94-
path = legacy_path(tmp_path)
95-
96-
PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(collection_path: pathlib\.Path.*"
97-
if hooktype == "ihook":
98-
hooks = request.node.ihook
99-
else:
100-
hooks = request.config.hook
101-
102-
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
103-
l1 = sys._getframe().f_lineno
104-
hooks.pytest_ignore_collect(
105-
config=request.config, path=path, collection_path=tmp_path
106-
)
107-
l2 = sys._getframe().f_lineno
108-
109-
(record,) = r
110-
assert record.filename == __file__
111-
assert l1 < record.lineno < l2
112-
113-
hooks.pytest_ignore_collect(config=request.config, collection_path=tmp_path)
114-
115-
# Passing entirely *different* paths is an outright error.
116-
with pytest.raises(ValueError, match=r"path.*fspath.*need to be equal"):
117-
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
118-
hooks.pytest_ignore_collect(
119-
config=request.config, path=path, collection_path=Path("/bla/bla")
120-
)
121-
122-
12390
def test_node_ctor_fspath_argument_is_deprecated(pytester: Pytester) -> None:
12491
mod = pytester.getmodulecol("")
12592

0 commit comments

Comments
 (0)