Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actually deprecate long standing features #3978

18 changes: 18 additions & 0 deletions changelog/3616.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
The following accesses have been documented as deprecated for years, but are now actually emitting deprecation warnings.

* Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances. Now
users will this warning::

usage of Function.Module is deprecated, please use pytest.Module instead

Users should just ``import pytest`` and access those objects using the ``pytest`` module.

* ``request.cached_setup``, this was the precursor of the setup/teardown mechanism available to fixtures. You can
consult `funcarg comparision section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_.

* Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_collect_make_item`` to customize node types during
collection.

This issue should affect only advanced plugins who create new collection types, so if you see this warning
message please contact the authors so they can change the code.
3 changes: 2 additions & 1 deletion changelog/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Each file should be named like ``<ISSUE>.<TYPE>.rst``, where
* ``feature``: new user facing features, like new command-line options and new behavior.
* ``bugfix``: fixes a reported bug.
* ``doc``: documentation improvement, like rewording an entire session or adding missing docs.
* ``removal``: feature deprecation or removal.
* ``deprecation``: feature deprecation.
* ``removal``: feature removal.
* ``vendor``: changes in packages vendored in pytest.
* ``trivial``: fixing a small typo or internal change that might be noteworthy.

Expand Down
10 changes: 10 additions & 0 deletions doc/en/historical-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,13 @@ Previous to version 2.4 to set a break point in code one needed to use ``pytest.
This is no longer needed and one can use the native ``import pdb;pdb.set_trace()`` call directly.

For more details see :ref:`breakpoints`.

"compat" properties
-------------------

.. deprecated:: 3.9

Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances have long
been documented as deprecated, but started to emit warnings from pytest ``3.9`` and onward.

Users should just ``import pytest`` and access those objects using the ``pytest`` module.
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ template = "changelog/_template.rst"

[[tool.towncrier.type]]
directory = "removal"
name = "Deprecations and Removals"
name = "Removals"
showcontent = true

[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true

[[tool.towncrier.type]]
Expand Down
5 changes: 5 additions & 0 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
or ``session`` indicating the caching lifecycle of the resource.
:arg extrakey: added to internal caching key of (funcargname, scope).
"""
msg = (
"cached_setup is deprecated and will be removed in a future release. "
"Use standard fixture functions instead."
)
warnings.warn(RemovedInPytest4Warning(msg), stacklevel=2)
if not hasattr(self.config, "_setupcache"):
self.config._setupcache = {} # XXX weakref?
cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
Expand Down
24 changes: 15 additions & 9 deletions src/_pytest/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from _pytest.compat import getfslineno

from _pytest.mark.structures import NodeKeywords, MarkInfo
from _pytest.warning_types import RemovedInPytest4Warning

SEP = "/"

Expand Down Expand Up @@ -61,11 +62,13 @@ def __get__(self, obj, owner):
if obj is None:
return self

# TODO: reenable in the features branch
# warnings.warn(
# "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
# name=self.name, owner=type(owner).__name__),
# PendingDeprecationWarning, stacklevel=2)
warnings.warn(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i had massive issue about one part of those warnings being triggered from pytest internals by accident which is why i deffered it on the old warnings system

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch_warnings to the rescue. 😁

It won't show the warnings for this specific access, but I guess that's OK because the whole class will be kicked out anyway. 👍

"usage of {owner}.{name} is deprecated, please use pytest.{name} instead".format(
name=self.name, owner=owner.__name__
),
RemovedInPytest4Warning,
stacklevel=2,
)
return getattr(__import__("pytest"), self.name)


Expand Down Expand Up @@ -127,10 +130,13 @@ def _getcustomclass(self, name):
return getattr(__import__("pytest"), name)
else:
cls = getattr(self, name)
# TODO: reenable in the features branch
# warnings.warn("use of node.%s is deprecated, "
# "use pytest_pycollect_makeitem(...) to create custom "
# "collection nodes" % name, category=DeprecationWarning)
msg = (
'use of special named "%s" objects in collectors of type "%s" to '
"customize the created nodes is deprecated. "
"Use pytest_pycollect_makeitem(...) to create custom "
"collection nodes instead." % (name, type(self).__name__)
)
self.warn(RemovedInPytest4Warning(msg))
return cls

def __repr__(self):
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ def collect(self):
"%r generated tests with non-unique name %r" % (self, name)
)
seen[name] = True
values.append(self.Function(name, self, args=args, callobj=call))
values.append(Function(name, self, args=args, callobj=call))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a breaking change, not doing it is why i had massive trouble with the warnings

self.warn(deprecated.YIELD_TESTS)
return values

Expand Down
68 changes: 68 additions & 0 deletions testing/deprecated_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,74 @@ def test_gen2():
assert result.stdout.str().count("yield tests are deprecated") == 2


def test_compat_properties_deprecation(testdir):
testdir.makepyfile(
"""
def test_foo(request):
print(request.node.Module)
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
"*test_compat_properties_deprecation.py:2:*usage of Function.Module is deprecated, "
"please use pytest.Module instead*",
"*1 passed, 1 warnings in*",
]
)


def test_cached_setup_deprecation(testdir):
testdir.makepyfile(
"""
import pytest
@pytest.fixture
def fix(request):
return request.cached_setup(lambda: 1)

def test_foo(fix):
assert fix == 1
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
"*test_cached_setup_deprecation.py:4:*cached_setup is deprecated*",
"*1 passed, 1 warnings in*",
]
)


def test_custom_class_deprecation(testdir):
testdir.makeconftest(
"""
import pytest

class MyModule(pytest.Module):

class Class(pytest.Class):
pass

def pytest_pycollect_makemodule(path, parent):
return MyModule(path, parent)
"""
)
testdir.makepyfile(
"""
class Test:
def test_foo(self):
pass
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
'*test_custom_class_deprecation.py:1:*"Class" objects in collectors of type "MyModule*',
"*1 passed, 1 warnings in*",
]
)


@pytest.mark.filterwarnings("default")
def test_funcarg_prefix_deprecation(testdir):
testdir.makepyfile(
Expand Down
2 changes: 2 additions & 0 deletions testing/python/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,7 @@ def test_func2b(self, something):
)
reprec.assertoutcome(passed=4)

@pytest.mark.filterwarnings("ignore:cached_setup is deprecated")
def test_request_cachedsetup_extrakey(self, testdir):
item1 = testdir.getitem("def test_func(): pass")
req1 = fixtures.FixtureRequest(item1)
Expand All @@ -994,6 +995,7 @@ def setup():
assert ret1 == ret1b
assert ret2 == ret2b

@pytest.mark.filterwarnings("ignore:cached_setup is deprecated")
def test_request_cachedsetup_cache_deletion(self, testdir):
item1 = testdir.getitem("def test_func(): pass")
req1 = fixtures.FixtureRequest(item1)
Expand Down