Skip to content

WIP: drop support for pytest < 4.2 #744

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

Closed
wants to merge 4 commits into from
Closed
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
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ jobs:
- python: 3.8
env: TOXENV=py38-dj30-sqlite-xdist-coverage

# Explicitly test (older) pytest 4.1.
# Explicitly test oldest supported pytest.
- python: 3.7
env: TOXENV=py37-dj21-sqlite-pytest41-coverage
env: TOXENV=py37-dj21-sqlite-pytest42-coverage

- python: 3.6
env: TOXENV=py36-djmaster-sqlite-coverage
Expand Down
95 changes: 1 addition & 94 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from functools import reduce
import os
import sys
import types

import pytest

Expand Down Expand Up @@ -51,9 +50,7 @@

PY2 = sys.version_info[0] == 2

# pytest 4.2 handles unittest setup/teardown itself via wrapping fixtures.
_pytest_version_info = tuple(int(x) for x in pytest.__version__.split(".", 2)[:2])
_handle_unittest_methods = _pytest_version_info < (4, 2)

_report_header = []

Expand Down Expand Up @@ -337,84 +334,6 @@ def pytest_configure():
_setup_django()


def _classmethod_is_defined_at_leaf(cls, method_name):
super_method = None

for base_cls in cls.__mro__[1:]: # pragma: no branch
super_method = base_cls.__dict__.get(method_name)
if super_method is not None:
break

assert super_method is not None, (
"%s could not be found in base classes" % method_name
)

method = getattr(cls, method_name)

try:
f = method.__func__
except AttributeError:
pytest.fail("%s.%s should be a classmethod" % (cls, method_name))
if PY2 and not (
inspect.ismethod(method)
and inspect.isclass(method.__self__)
and issubclass(cls, method.__self__)
):
pytest.fail("%s.%s should be a classmethod" % (cls, method_name))
return f is not super_method.__func__


_disabled_classmethods = {}


def _disable_class_methods(cls):
if cls in _disabled_classmethods:
return

_disabled_classmethods[cls] = (
# Get the classmethod object (not the resulting bound method),
# otherwise inheritance will be broken when restoring.
cls.__dict__.get("setUpClass"),
_classmethod_is_defined_at_leaf(cls, "setUpClass"),
cls.__dict__.get("tearDownClass"),
_classmethod_is_defined_at_leaf(cls, "tearDownClass"),
)

cls.setUpClass = types.MethodType(lambda cls: None, cls)
cls.tearDownClass = types.MethodType(lambda cls: None, cls)


def _restore_class_methods(cls):
(
setUpClass,
restore_setUpClass,
tearDownClass,
restore_tearDownClass,
) = _disabled_classmethods.pop(cls)

try:
del cls.setUpClass
except AttributeError:
raise

try:
del cls.tearDownClass
except AttributeError:
pass

if restore_setUpClass:
cls.setUpClass = setUpClass

if restore_tearDownClass:
cls.tearDownClass = tearDownClass


def pytest_runtest_setup(item):
if _handle_unittest_methods:
if django_settings_is_configured() and is_django_unittest(item):
_disable_class_methods(item.cls)


@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(items):
def get_order_number(test):
Expand Down Expand Up @@ -524,20 +443,8 @@ def non_debugging_runtest(self):

request.getfixturevalue("django_db_setup")

cls = request.node.cls

with django_db_blocker.unblock():
if _handle_unittest_methods:
_restore_class_methods(cls)
cls.setUpClass()
_disable_class_methods(cls)

yield

_restore_class_methods(cls)
cls.tearDownClass()
else:
yield
yield

if mp_debug:
mp_debug.undo()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def read(fname):
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
setup_requires=['setuptools_scm>=1.11.1'],
install_requires=[
'pytest>=3.6',
'pytest>=4.2',
'pathlib2;python_version<"3.4"',
],
extras_require={
Expand Down
10 changes: 1 addition & 9 deletions tests/test_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,8 @@ def test_pass(self):
result = django_testdir.runpytest_subprocess("-v", "-s")
expected_lines = [
"* ERROR at setup of TestFoo.test_pass *",
"E * TypeError: *",
]
if _pytest_version_info < (4, 2):
expected_lines += [
"E *Failed: <class 'tpkg.test_the_test.TestFoo'>.setUpClass should be a classmethod", # noqa:E501
]
else:
expected_lines += [
"E * TypeError: *",
]

result.stdout.fnmatch_lines(expected_lines)
assert result.ret == 1

Expand Down
5 changes: 3 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ deps =
postgres: psycopg2-binary
coverage: coverage-enable-subprocess

pytest41: pytest>=4.1,<4.2
pytest41: attrs==17.4.0
# Oldest supported pytest.
pytest42: pytest>=4.2,<4.3
pytest42: attrs==17.4.0
xdist: pytest-xdist>=1.15

setenv =
Expand Down