Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 40 additions & 38 deletions doc/en/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -297,33 +297,6 @@ Changed ``hookwrapper`` attributes:
* ``historic``


.. _legacy-path-hooks-deprecated:

``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 7.0

In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the following hooks now receive additional arguments:

* :hook:`pytest_ignore_collect(collection_path: pathlib.Path) <pytest_ignore_collect>` as equivalent to ``path``
* :hook:`pytest_collect_file(file_path: pathlib.Path) <pytest_collect_file>` as equivalent to ``path``
* :hook:`pytest_pycollect_makemodule(module_path: pathlib.Path) <pytest_pycollect_makemodule>` as equivalent to ``path``
* :hook:`pytest_report_header(start_path: pathlib.Path) <pytest_report_header>` as equivalent to ``startdir``
* :hook:`pytest_report_collectionfinish(start_path: pathlib.Path) <pytest_report_collectionfinish>` as equivalent to ``startdir``

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.

.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes,
:ref:`outlined above <node-ctor-fspath-deprecation>` (the new attribute
being ``path``) is **the opposite** of the situation for hooks (the old
argument being ``path``).

This is an unfortunate artifact due to historical reasons, which should be
resolved in future versions as we slowly get rid of the :pypi:`py`
dependency (see :issue:`9283` for a longer discussion).

Directly constructing internal classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -394,10 +367,30 @@ conflicts (such as :class:`pytest.File` now taking ``path`` instead of
``fspath``, as :ref:`outlined above <node-ctor-fspath-deprecation>`), a
deprecation warning is now raised.


The ``yield_fixture`` function/decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 6.2

``pytest.yield_fixture`` is a deprecated alias for :func:`pytest.fixture`.

It has been so for a very long time, so can be search/replaced safely.


Removed Features and Breaking Changes
-------------------------------------

As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
an appropriate period of deprecation has passed.

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

Applying a mark to a fixture function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 7.4
.. versionremoved:: 9.0

Applying a mark to a fixture function never had any effect, but it is a common user error.

Expand All @@ -411,24 +404,33 @@ Users expected in this case that the ``usefixtures`` mark would have its intende

Now pytest will issue a warning when it encounters this problem, and will raise an error in the future versions.

.. _legacy-path-hooks-deprecated:

The ``yield_fixture`` function/decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 6.2
``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``pytest.yield_fixture`` is a deprecated alias for :func:`pytest.fixture`.
.. deprecated:: 7.0
.. versionremoved:: 9.0

It has been so for a very long time, so can be search/replaced safely.
In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the following hooks now receive additional arguments:

* :hook:`pytest_ignore_collect(collection_path: pathlib.Path) <pytest_ignore_collect>` as equivalent to ``path``
* :hook:`pytest_collect_file(file_path: pathlib.Path) <pytest_collect_file>` as equivalent to ``path``
* :hook:`pytest_pycollect_makemodule(module_path: pathlib.Path) <pytest_pycollect_makemodule>` as equivalent to ``path``
* :hook:`pytest_report_header(start_path: pathlib.Path) <pytest_report_header>` as equivalent to ``startdir``
* :hook:`pytest_report_collectionfinish(start_path: pathlib.Path) <pytest_report_collectionfinish>` as equivalent to ``startdir``

Removed Features and Breaking Changes
-------------------------------------
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.

As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
an appropriate period of deprecation has passed.
.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes,
:ref:`outlined above <node-ctor-fspath-deprecation>` (the new attribute
being ``path``) is **the opposite** of the situation for hooks (the old
argument being ``path``).

Some breaking changes which could not be deprecated are also listed.
This is an unfortunate artifact due to historical reasons, which should be
resolved in future versions as we slowly get rid of the :pypi:`py`
dependency (see :issue:`9283` for a longer discussion).

.. _yield tests deprecated:

Expand Down
4 changes: 1 addition & 3 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,12 @@
from typing import TYPE_CHECKING
import warnings

import pluggy
from pluggy import HookimplMarker
from pluggy import HookimplOpts
from pluggy import HookspecMarker
from pluggy import HookspecOpts
from pluggy import PluginManager

from .compat import PathAwareHookProxy
from .exceptions import PrintHelp as PrintHelp
from .exceptions import UsageError as UsageError
from .findpaths import determine_setup
Expand Down Expand Up @@ -1087,7 +1085,7 @@ def __init__(
self._store = self.stash

self.trace = self.pluginmanager.trace.root.get("config")
self.hook: pluggy.HookRelay = PathAwareHookProxy(self.pluginmanager.hook) # type: ignore[assignment]
self.hook = self.pluginmanager.hook
self._inicache: dict[str, Any] = {}
self._cleanup_stack = contextlib.ExitStack()
self.pluginmanager.register(self, "pytestconfig")
Expand Down
72 changes: 0 additions & 72 deletions src/_pytest/config/compat.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
from __future__ import annotations

from collections.abc import Mapping
import functools
from pathlib import Path
from typing import Any
import warnings

import pluggy

from ..compat import LEGACY_PATH
from ..compat import legacy_path
from ..deprecated import HOOK_LEGACY_PATH_ARG


# hookname: (Path, LEGACY_PATH)
imply_paths_hooks: Mapping[str, tuple[str, str]] = {
"pytest_ignore_collect": ("collection_path", "path"),
"pytest_collect_file": ("file_path", "path"),
"pytest_pycollect_makemodule": ("module_path", "path"),
"pytest_report_header": ("start_path", "startdir"),
"pytest_report_collectionfinish": ("start_path", "startdir"),
}


def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
Expand All @@ -29,57 +11,3 @@ def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
f"Path({fspath!r}) != {path!r}\n"
"if both path and fspath are given they need to be equal"
)


class PathAwareHookProxy:
"""
this helper wraps around hook callers
until pluggy supports fixingcalls, this one will do

it currently doesn't return full hook caller proxies for fixed hooks,
this may have to be changed later depending on bugs
"""

def __init__(self, hook_relay: pluggy.HookRelay) -> None:
self._hook_relay = hook_relay

def __dir__(self) -> list[str]:
return dir(self._hook_relay)

def __getattr__(self, key: str) -> pluggy.HookCaller:
hook: pluggy.HookCaller = getattr(self._hook_relay, key)
if key not in imply_paths_hooks:
self.__dict__[key] = hook
return hook
else:
path_var, fspath_var = imply_paths_hooks[key]

@functools.wraps(hook)
def fixed_hook(**kw: Any) -> Any:
path_value: Path | None = kw.pop(path_var, None)
fspath_value: LEGACY_PATH | None = 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
),
stacklevel=2,
)
if path_value is not None:
if fspath_value is not None:
_check_path(path_value, fspath_value)
else:
fspath_value = legacy_path(path_value)
else:
assert fspath_value is not None
path_value = Path(fspath_value)

kw[path_var] = path_value
kw[fspath_var] = fspath_value
return hook(**kw)

fixed_hook.name = hook.name # type: ignore[attr-defined]
fixed_hook.spec = hook.spec # type: ignore[attr-defined]
fixed_hook.__name__ = key
self.__dict__[key] = fixed_hook
return fixed_hook # type: ignore[return-value]
12 changes: 0 additions & 12 deletions src/_pytest/deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@
PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.")


HOOK_LEGACY_PATH_ARG = UnformattedWarning(
PytestRemovedIn9Warning,
"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",
)

NODE_CTOR_FSPATH_ARG = UnformattedWarning(
PytestRemovedIn9Warning,
"The (fspath: py.path.local) argument to {node_type_name} is deprecated. "
Expand All @@ -63,11 +56,6 @@
"#configuring-hook-specs-impls-using-markers",
)

MARKED_FIXTURE = PytestRemovedIn9Warning(
"Marks applied to fixtures have no effect\n"
"See docs: https://docs.pytest.org/en/stable/deprecations.html#applying-a-mark-to-a-fixture-function"
)

MONKEYPATCH_LEGACY_NAMESPACE_PACKAGES = PytestRemovedIn10Warning(
"monkeypatch.syspath_prepend() called with pkg_resources legacy namespace packages detected.\n"
"Legacy namespace packages (using pkg_resources.declare_namespace) are deprecated.\n"
Expand Down
6 changes: 4 additions & 2 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
from _pytest.config import ExitCode
from _pytest.config.argparsing import Parser
from _pytest.deprecated import check_ispytest
from _pytest.deprecated import MARKED_FIXTURE
from _pytest.deprecated import YIELD_FIXTURE
from _pytest.main import Session
from _pytest.mark import Mark
Expand Down Expand Up @@ -1236,7 +1235,10 @@ def __call__(self, function: FixtureFunction) -> FixtureFunctionDefinition:
)

if hasattr(function, "pytestmark"):
warnings.warn(MARKED_FIXTURE, stacklevel=2)
fail(
"Marks cannot be applied to fixtures.\n"
"See docs: https://docs.pytest.org/en/stable/deprecations.html#applying-a-mark-to-a-fixture-function"
)

fixture_definition = FixtureFunctionDefinition(
function=function, fixture_function_marker=self, _ispytest=True
Expand Down
Loading