Improve reference and path/fspath docs (#9341)

* Improve reference and path/fspath docs

Closes #9283

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fixups

* Add explanation

* Update wording after #9363

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Florian Bruhin 2021-12-06 11:25:05 +01:00 committed by GitHub
parent 5852d66a6a
commit 663be09723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 16 deletions

View File

@ -1,3 +1,12 @@
``py.path.local`` arguments for hooks have been deprecated. See :ref:`the deprecation note <legacy-path-hooks-deprecated>` for full details. ``py.path.local`` arguments for hooks have been deprecated. See :ref:`the deprecation note <legacy-path-hooks-deprecated>` for full details.
``py.path.local`` arguments to Node constructors have been deprecated. See :ref:`the deprecation note <node-ctor-fspath-deprecation>` for full details. ``py.path.local`` arguments to Node constructors have been deprecated. See :ref:`the deprecation note <node-ctor-fspath-deprecation>` for full details.
.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes (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).

View File

@ -5,3 +5,12 @@ The following hooks now receive an additional ``pathlib.Path`` argument, equival
- :func:`pytest_pycollect_makemodule <_pytest.hookspec.pytest_pycollect_makemodule>` - The ``module_path`` parameter (equivalent to existing ``path`` parameter). - :func:`pytest_pycollect_makemodule <_pytest.hookspec.pytest_pycollect_makemodule>` - The ``module_path`` parameter (equivalent to existing ``path`` parameter).
- :func:`pytest_report_header <_pytest.hookspec.pytest_report_header>` - The ``start_path`` parameter (equivalent to existing ``startdir`` parameter). - :func:`pytest_report_header <_pytest.hookspec.pytest_report_header>` - The ``start_path`` parameter (equivalent to existing ``startdir`` parameter).
- :func:`pytest_report_collectionfinish <_pytest.hookspec.pytest_report_collectionfinish>` - The ``start_path`` parameter (equivalent to existing ``startdir`` parameter). - :func:`pytest_report_collectionfinish <_pytest.hookspec.pytest_report_collectionfinish>` - The ``start_path`` parameter (equivalent to existing ``startdir`` parameter).
.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes (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).

View File

@ -1 +1,11 @@
Implement ``Node.path`` as a ``pathlib.Path``. Implement ``Node.path`` as a ``pathlib.Path``. Both the old ``fspath`` and this new attribute gets set no matter whether ``path`` or ``fspath`` (deprecated) is passed to the constructor. It is a replacement for the ``fspath`` attribute (which represents the same path as ``py.path.local``). While ``fspath`` is not deprecated yet
due to the ongoing migration of methods like :meth:`~_pytest.Item.reportinfo`, we expect to deprecate it in a future release.
.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes (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).

1
changelog/9341.doc.rst Normal file
View File

@ -0,0 +1 @@
Various methods commonly used for :ref:`non-python tests` are now correctly documented in the reference docs. They were undocumented previously.

View File

@ -53,9 +53,24 @@ Plugins which construct nodes should pass the ``path`` argument, of type
:class:`pathlib.Path`, instead of the ``fspath`` argument. :class:`pathlib.Path`, instead of the ``fspath`` argument.
Plugins which implement custom items and collectors are encouraged to replace Plugins which implement custom items and collectors are encouraged to replace
``py.path.local`` ``fspath`` parameters with ``pathlib.Path`` parameters, and ``fspath`` parameters (``py.path.local``) with ``path`` parameters
drop any other usage of the ``py`` library if possible. (``pathlib.Path``), and drop any other usage of the ``py`` library if possible.
.. note::
The name of the :class:`~_pytest.nodes.Node` arguments and attributes (the
new attribute being ``path``) is **the opposite** of the situation for
hooks, :ref:`outlined below <legacy-path-hooks-deprecated>` (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).
Due to the ongoing migration of methods like :meth:`~_pytest.Item.reportinfo`
which still is expected to return a ``py.path.local`` object, nodes still have
both ``fspath`` (``py.path.local``) and ``path`` (``pathlib.Path``) attributes,
no matter what argument was used in the constructor. We expect to deprecate the
``fspath`` attribute in a future release.
.. _legacy-path-hooks-deprecated: .. _legacy-path-hooks-deprecated:
@ -74,6 +89,16 @@ In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the
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. 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 Directly constructing internal classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -159,6 +159,13 @@ class Node(metaclass=NodeMeta):
Collector subclasses have children; Items are leaf nodes. Collector subclasses have children; Items are leaf nodes.
""" """
# Implemented in the legacypath plugin.
#: A ``LEGACY_PATH`` copy of the :attr:`path` attribute. Intended for usage
#: for methods not migrated to ``pathlib.Path`` yet, such as
#: :meth:`Item.reportinfo`. Will be deprecated in a future release, prefer
#: using :attr:`path` instead.
fspath: LEGACY_PATH
# Use __slots__ to make attribute access faster. # Use __slots__ to make attribute access faster.
# Note that __dict__ is still available. # Note that __dict__ is still available.
__slots__ = ( __slots__ = (
@ -188,26 +195,26 @@ class Node(metaclass=NodeMeta):
#: The parent collector node. #: The parent collector node.
self.parent = parent self.parent = parent
#: The pytest config object.
if config: if config:
#: The pytest config object.
self.config: Config = config self.config: Config = config
else: else:
if not parent: if not parent:
raise TypeError("config or parent must be provided") raise TypeError("config or parent must be provided")
self.config = parent.config self.config = parent.config
#: The pytest session this node is part of.
if session: if session:
#: The pytest session this node is part of.
self.session = session self.session = session
else: else:
if not parent: if not parent:
raise TypeError("session or parent must be provided") raise TypeError("session or parent must be provided")
self.session = parent.session self.session = parent.session
#: Filesystem path where this node was collected from (can be None).
if path is None and fspath is None: if path is None and fspath is None:
path = getattr(parent, "path", None) path = getattr(parent, "path", None)
self.path = _imply_path(type(self), path, fspath=fspath) #: Filesystem path where this node was collected from (can be None).
self.path: Path = _imply_path(type(self), path, fspath=fspath)
# The explicit annotation is to avoid publicly exposing NodeKeywords. # The explicit annotation is to avoid publicly exposing NodeKeywords.
#: Keywords/markers collected from all scopes. #: Keywords/markers collected from all scopes.
@ -478,6 +485,8 @@ class Node(metaclass=NodeMeta):
) -> Union[str, TerminalRepr]: ) -> Union[str, TerminalRepr]:
"""Return a representation of a collection or test failure. """Return a representation of a collection or test failure.
.. seealso:: :ref:`non-python tests`
:param excinfo: Exception information for the failure. :param excinfo: Exception information for the failure.
""" """
return self._repr_failure_py(excinfo, style) return self._repr_failure_py(excinfo, style)
@ -686,6 +695,12 @@ class Item(Node):
self.user_properties: List[Tuple[str, object]] = [] self.user_properties: List[Tuple[str, object]] = []
def runtest(self) -> None: def runtest(self) -> None:
"""Run the test case for this item.
Must be implemented by subclasses.
.. seealso:: :ref:`non-python tests`
"""
raise NotImplementedError("runtest must be implemented by Item subclass") raise NotImplementedError("runtest must be implemented by Item subclass")
def add_report_section(self, when: str, key: str, content: str) -> None: def add_report_section(self, when: str, key: str, content: str) -> None:
@ -706,6 +721,16 @@ class Item(Node):
self._report_sections.append((when, key, content)) self._report_sections.append((when, key, content))
def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]: def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
"""Get location information for this item for test reports.
Returns a tuple with three elements:
- The path of the test (default ``self.path``)
- The line number of the test (default ``None``)
- A name of the test to be shown (default ``""``)
.. seealso:: :ref:`non-python tests`
"""
return self.path, None, "" return self.path, None, ""
@cached_property @cached_property

View File

@ -1578,26 +1578,26 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
class Function(PyobjMixin, nodes.Item): class Function(PyobjMixin, nodes.Item):
"""An Item responsible for setting up and executing a Python test function. """An Item responsible for setting up and executing a Python test function.
param name: :param name:
The full function name, including any decorations like those The full function name, including any decorations like those
added by parametrization (``my_func[my_param]``). added by parametrization (``my_func[my_param]``).
param parent: :param parent:
The parent Node. The parent Node.
param config: :param config:
The pytest Config object. The pytest Config object.
param callspec: :param callspec:
If given, this is function has been parametrized and the callspec contains If given, this is function has been parametrized and the callspec contains
meta information about the parametrization. meta information about the parametrization.
param callobj: :param callobj:
If given, the object which will be called when the Function is invoked, If given, the object which will be called when the Function is invoked,
otherwise the callobj will be obtained from ``parent`` using ``originalname``. otherwise the callobj will be obtained from ``parent`` using ``originalname``.
param keywords: :param keywords:
Keywords bound to the function object for "-k" matching. Keywords bound to the function object for "-k" matching.
param session: :param session:
The pytest Session object. The pytest Session object.
param fixtureinfo: :param fixtureinfo:
Fixture information already resolved at this fixture node.. Fixture information already resolved at this fixture node..
param originalname: :param originalname:
The attribute name to use for accessing the underlying function object. The attribute name to use for accessing the underlying function object.
Defaults to ``name``. Set this if name is different from the original name, Defaults to ``name``. Set this if name is different from the original name,
for example when it contains decorations like those added by parametrization for example when it contains decorations like those added by parametrization