From 375be235d759059b4c7df3c0d360829d99a1d2c0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 10 Jan 2022 11:51:07 +0100 Subject: [PATCH 1/4] Add additional docs for uncooperative ctor deprecation Fixes #9488 --- doc/en/deprecations.rst | 40 ++++++++++++++++++++++++++++ doc/en/example/nonpython/conftest.py | 4 +-- src/_pytest/nodes.py | 4 ++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index 6351d1f6e6a..bcc71f4a383 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -56,6 +56,10 @@ Plugins which implement custom items and collectors are encouraged to replace ``fspath`` parameters (``py.path.local``) with ``path`` parameters (``pathlib.Path``), and drop any other usage of the ``py`` library if possible. +If possible, plugins with custom items should use :ref:`cooperative +constructors ` to avoid hardcoding +arguments they only pass on to the superclass. + .. note:: The name of the :class:`~_pytest.nodes.Node` arguments and attributes (the new attribute being ``path``) is **the opposite** of the situation for @@ -191,6 +195,42 @@ Instead, a separate collector node should be used, which collects the item. See .. _example pr fixing inheritance: https://github.com/asmeurer/pytest-flakes/pull/40/files +.. _uncooperative-constructors-deprecated: + +Constructors of custom :class:`pytest.Node` subclasses should take ``**kwargs`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 7.0 + +If custom subclasses of nodes like :class:`pytest.Item` override the +``__init__`` method, they should take ``**kwargs``. Thus, + +.. code-block:: python + + class CustomItem(pytest.Item): + + def __init__(self, name, parent, additional_arg): + super().__init__(name, parent) + self.additional_arg = additional_arg + +should be turned into: + +.. code-block:: python + + class CustomItem(pytest.Item): + + def __init__(self, additional_arg, **kwargs): + super().__init__(**kwargs) + self.additional_arg = additional_arg + +to avoid hard-coding the arguments pytest can pass to the superclass. +See :ref:`non-python tests` for a full example. + +For cases without conflicts, no deprecation warning is emitted. For cases with +conflicts (such as :class:`pytest.File` now taking ``path`` instead of +``fspath``, as :ref:`outlined above `), a +deprecation warning is now raised. + Backward compatibilities in ``Parser.addoption`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/en/example/nonpython/conftest.py b/doc/en/example/nonpython/conftest.py index 7ec4134036c..f9b76387022 100644 --- a/doc/en/example/nonpython/conftest.py +++ b/doc/en/example/nonpython/conftest.py @@ -18,8 +18,8 @@ def collect(self): class YamlItem(pytest.Item): - def __init__(self, name, parent, spec): - super().__init__(name, parent) + def __init__(self, spec, **kwargs): + super().__init__(**kwargs) self.spec = spec def runtest(self): diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 53dea04e795..e77525212b9 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -145,7 +145,9 @@ def _create(self, *k, **kw): warnings.warn( PytestDeprecationWarning( - f"{self} is not using a cooperative constructor and only takes {set(known_kw)}" + f"{self} is not using a cooperative constructor and only takes {set(known_kw)}.\n" + "See https://docs.pytest.org/en/stable/deprecations.html#constructors-of-custom-pytest-node-subclasses-should-take-kwargs" + " for more details." ) ) From a81a177752d22af9335c1f7b40ff4b1cc15f30c6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Jan 2022 10:52:47 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/en/deprecations.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index bcc71f4a383..db78cce52e3 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -208,17 +208,15 @@ If custom subclasses of nodes like :class:`pytest.Item` override the .. code-block:: python class CustomItem(pytest.Item): - - def __init__(self, name, parent, additional_arg): - super().__init__(name, parent) - self.additional_arg = additional_arg + def __init__(self, name, parent, additional_arg): + super().__init__(name, parent) + self.additional_arg = additional_arg should be turned into: .. code-block:: python class CustomItem(pytest.Item): - def __init__(self, additional_arg, **kwargs): super().__init__(**kwargs) self.additional_arg = additional_arg From 0644de3472613153e1c2cfd56aa69a5dfe4ea7a9 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 11 Jan 2022 17:47:12 +0100 Subject: [PATCH 3/4] Break up long line --- src/_pytest/nodes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index e77525212b9..6e8454ad7c6 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -146,8 +146,9 @@ def _create(self, *k, **kw): warnings.warn( PytestDeprecationWarning( f"{self} is not using a cooperative constructor and only takes {set(known_kw)}.\n" - "See https://docs.pytest.org/en/stable/deprecations.html#constructors-of-custom-pytest-node-subclasses-should-take-kwargs" - " for more details." + "See https://docs.pytest.org/en/stable/deprecations.html" + "#constructors-of-custom-pytest-node-subclasses-should-take-kwargs " + "for more details." ) ) From e68f103e3658de999f08965ef410c63638d37d85 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 25 Jan 2022 09:40:48 +0100 Subject: [PATCH 4/4] Recommend kwonly args --- doc/en/deprecations.rst | 2 +- doc/en/example/nonpython/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index db78cce52e3..9951327dd73 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -217,7 +217,7 @@ should be turned into: .. code-block:: python class CustomItem(pytest.Item): - def __init__(self, additional_arg, **kwargs): + def __init__(self, *, additional_arg, **kwargs): super().__init__(**kwargs) self.additional_arg = additional_arg diff --git a/doc/en/example/nonpython/conftest.py b/doc/en/example/nonpython/conftest.py index f9b76387022..bc39a1f6b20 100644 --- a/doc/en/example/nonpython/conftest.py +++ b/doc/en/example/nonpython/conftest.py @@ -18,7 +18,7 @@ def collect(self): class YamlItem(pytest.Item): - def __init__(self, spec, **kwargs): + def __init__(self, *, spec, **kwargs): super().__init__(**kwargs) self.spec = spec