Skip to content

Commit

Permalink
Require pytest>=7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bluetech committed Oct 26, 2023
1 parent 06185eb commit e36a9bd
Show file tree
Hide file tree
Showing 20 changed files with 554 additions and 441 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pytest-django allows you to test your Django project/applications with the
* Django: 3.2, 4.0, 4.1, 4.2 and latest main branch (compatible at the time of
each release)
* Python: CPython>=3.8 or PyPy 3
* pytest: >=5.4
* pytest: >=7.0

For compatibility with older versions, use the pytest-django 3.*.* series.

Expand Down
16 changes: 8 additions & 8 deletions pytest_django/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def django_db_modify_db_settings_tox_suffix() -> None:


@pytest.fixture(scope="session")
def django_db_modify_db_settings_xdist_suffix(request) -> None:
def django_db_modify_db_settings_xdist_suffix(request: pytest.FixtureRequest) -> None:
skip_if_no_django()

xdist_suffix = getattr(request.config, "workerinput", {}).get("workerid")
Expand All @@ -83,23 +83,23 @@ def django_db_modify_db_settings(


@pytest.fixture(scope="session")
def django_db_use_migrations(request) -> bool:
def django_db_use_migrations(request: pytest.FixtureRequest) -> bool:
return not request.config.getvalue("nomigrations")


@pytest.fixture(scope="session")
def django_db_keepdb(request) -> bool:
def django_db_keepdb(request: pytest.FixtureRequest) -> bool:
return request.config.getvalue("reuse_db")


@pytest.fixture(scope="session")
def django_db_createdb(request) -> bool:
def django_db_createdb(request: pytest.FixtureRequest) -> bool:
return request.config.getvalue("create_db")


@pytest.fixture(scope="session")
def django_db_setup(
request,
request: pytest.FixtureRequest,
django_test_environment: None,
django_db_blocker,
django_db_use_migrations: bool,
Expand Down Expand Up @@ -142,7 +142,7 @@ def teardown_database() -> None:

@pytest.fixture()
def _django_db_helper(
request,
request: pytest.FixtureRequest,
django_db_setup: None,
django_db_blocker,
) -> None:
Expand Down Expand Up @@ -518,7 +518,7 @@ def settings():


@pytest.fixture(scope="session")
def live_server(request):
def live_server(request: pytest.FixtureRequest):
"""Run a live Django server in the background during tests
The address the server is started from is taken from the
Expand Down Expand Up @@ -549,7 +549,7 @@ def live_server(request):


@pytest.fixture(autouse=True, scope="function")
def _live_server_helper(request) -> None:
def _live_server_helper(request: pytest.FixtureRequest) -> None:
"""Helper to make live_server work, internal to pytest-django.
This helper will dynamically request the transactional_db fixture
Expand Down
53 changes: 25 additions & 28 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@


@pytest.hookimpl()
def pytest_addoption(parser) -> None:
def pytest_addoption(parser: pytest.Parser) -> None:
group = parser.getgroup("django")
group.addoption(
"--reuse-db",
Expand Down Expand Up @@ -259,8 +259,8 @@ def _get_boolean_value(

@pytest.hookimpl()
def pytest_load_initial_conftests(
early_config,
parser,
early_config: pytest.Config,
parser: pytest.Parser,
args: List[str],
) -> None:
# Register the marks
Expand Down Expand Up @@ -411,7 +411,7 @@ def get_order_number(test: pytest.Item) -> int:


@pytest.fixture(autouse=True, scope="session")
def django_test_environment(request) -> None:
def django_test_environment(request: pytest.FixtureRequest) -> None:
"""
Ensure that Django is loaded and has its testing environment setup.
Expand Down Expand Up @@ -459,7 +459,7 @@ def django_db_blocker() -> "Optional[_DatabaseBlocker]":


@pytest.fixture(autouse=True)
def _django_db_marker(request) -> None:
def _django_db_marker(request: pytest.FixtureRequest) -> None:
"""Implement the django_db marker, internal to pytest-django."""
marker = request.node.get_closest_marker("django_db")
if marker:
Expand All @@ -468,7 +468,7 @@ def _django_db_marker(request) -> None:

@pytest.fixture(autouse=True, scope="class")
def _django_setup_unittest(
request,
request: pytest.FixtureRequest,
django_db_blocker: "_DatabaseBlocker",
) -> Generator[None, None, None]:
"""Setup a django unittest, internal to pytest-django."""
Expand Down Expand Up @@ -521,7 +521,7 @@ def mailoutbox(

@pytest.fixture(scope="function")
def django_mail_patch_dns(
monkeypatch,
monkeypatch: pytest.MonkeyPatch,
django_mail_dnsname: str,
) -> None:
from django.core import mail
Expand All @@ -535,7 +535,7 @@ def django_mail_dnsname() -> str:


@pytest.fixture(autouse=True, scope="function")
def _django_set_urlconf(request) -> None:
def _django_set_urlconf(request: pytest.FixtureRequest) -> None:
"""Apply the @pytest.mark.urls marker, internal to pytest-django."""
marker = request.node.get_closest_marker("urls")
if marker:
Expand Down Expand Up @@ -628,30 +628,27 @@ def __mod__(self, var: str) -> str:
else:
return msg

# TODO: use pytest.MonkeyPatch once pytest<6.2 is not supported anymore
NOT_SET = object()
changed = False
previous_value = NOT_SET
if (
os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true"
and django_settings_is_configured()
):
from django.conf import settings as dj_settings
with pytest.MonkeyPatch.context() as mp:
if (
os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true"
and django_settings_is_configured()
):
from django.conf import settings as dj_settings

if dj_settings.TEMPLATES:
previous_value = dj_settings.TEMPLATES[0]["OPTIONS"].get("string_if_invalid", NOT_SET)
dj_settings.TEMPLATES[0]["OPTIONS"]["string_if_invalid"] = InvalidVarException()
changed = True
yield
if changed:
if previous_value is NOT_SET:
del dj_settings.TEMPLATES[0]["OPTIONS"]["string_if_invalid"]
else:
dj_settings.TEMPLATES[0]["OPTIONS"]["string_if_invalid"] = previous_value
if dj_settings.TEMPLATES:
mp.setitem(
dj_settings.TEMPLATES[0]["OPTIONS"],
"string_if_invalid",
InvalidVarException(),
)
yield


@pytest.fixture(autouse=True)
def _template_string_if_invalid_marker(monkeypatch, request) -> None:
def _template_string_if_invalid_marker(
monkeypatch: pytest.MonkeyPatch,
request: pytest.FixtureRequest,
) -> None:
"""Apply the @pytest.mark.ignore_template_errors marker,
internal to pytest-django."""
marker = request.keywords.get("ignore_template_errors", None)
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ project_urls =
packages = pytest_django
python_requires = >=3.8
setup_requires = setuptools_scm>=5.0.0
install_requires = pytest>=5.4.0
install_requires = pytest>=7.0.0
zip_safe = no

[options.entry_points]
Expand Down
Empty file added tests/__init__.py
Empty file.
71 changes: 41 additions & 30 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import copy
import pathlib
import shutil
from pathlib import Path
from textwrap import dedent
from typing import Optional
from typing import Optional, cast

import pytest
from django.conf import settings

from .helpers import DjangoPytester


pytest_plugins = "pytester"

REPOSITORY_ROOT = pathlib.Path(__file__).parent


def pytest_configure(config) -> None:
def pytest_configure(config: pytest.Config) -> None:
config.addinivalue_line(
"markers", "django_project: options for the django_testdir fixture"
"markers", "django_project: options for the django_pytester fixture"
)


Expand All @@ -32,13 +35,17 @@ def _marker_apifun(


@pytest.fixture
def testdir(testdir, monkeypatch):
def pytester(pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch) -> pytest.Pytester:
monkeypatch.delenv("PYTEST_ADDOPTS", raising=False)
return testdir
return pytester


@pytest.fixture(scope="function")
def django_testdir(request, testdir, monkeypatch):
def django_pytester(
request: pytest.FixtureRequest,
pytester: pytest.Pytester,
monkeypatch: pytest.MonkeyPatch,
) -> DjangoPytester:
from pytest_django_test.db_helpers import (
DB_NAME, SECOND_DB_NAME, SECOND_TEST_DB_NAME, TEST_DB_NAME,
)
Expand Down Expand Up @@ -106,56 +113,60 @@ def django_testdir(request, testdir, monkeypatch):
)

if options["project_root"]:
project_root = testdir.mkdir(options["project_root"])
project_root = pytester.mkdir(options["project_root"])
else:
project_root = testdir.tmpdir
project_root = pytester.path

tpkg_path = project_root.mkdir("tpkg")
tpkg_path = project_root / "tpkg"
tpkg_path.mkdir()

if options["create_manage_py"]:
project_root.ensure("manage.py")
project_root.joinpath("manage.py").touch()

tpkg_path.ensure("__init__.py")
tpkg_path.joinpath("__init__.py").touch()

app_source = REPOSITORY_ROOT / "../pytest_django_test/app"
test_app_path = tpkg_path.join("app")
test_app_path = tpkg_path / "app"

# Copy the test app to make it available in the new test run
shutil.copytree(str(app_source), str(test_app_path))
tpkg_path.join("the_settings.py").write(test_settings)
tpkg_path.joinpath("the_settings.py").write_text(test_settings)

monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.the_settings")

def create_test_module(test_code: str, filename: str = "test_the_test.py"):
r = tpkg_path.join(filename)
r.write(dedent(test_code), ensure=True)
def create_test_module(test_code: str, filename: str = "test_the_test.py") -> Path:
r = tpkg_path.joinpath(filename)
r.parent.mkdir(parents=True, exist_ok=True)
r.write_text(dedent(test_code))
return r

def create_app_file(code: str, filename: str):
r = test_app_path.join(filename)
r.write(dedent(code), ensure=True)
def create_app_file(code: str, filename: str) -> Path:
r = test_app_path.joinpath(filename)
r.parent.mkdir(parents=True, exist_ok=True)
r.write_text(dedent(code))
return r

testdir.create_test_module = create_test_module
testdir.create_app_file = create_app_file
testdir.project_root = project_root

testdir.makeini(
pytester.makeini(
"""
[pytest]
addopts = --strict-markers
console_output_style=classic
"""
)

return testdir
django_pytester_ = cast(DjangoPytester, pytester)
django_pytester_.create_test_module = create_test_module # type: ignore[method-assign]
django_pytester_.create_app_file = create_app_file # type: ignore[method-assign]
django_pytester_.project_root = project_root

return django_pytester_


@pytest.fixture
def django_testdir_initial(django_testdir):
"""A django_testdir fixture which provides initial_data."""
django_testdir.project_root.join("tpkg/app/migrations").remove()
django_testdir.makefile(
def django_pytester_initial(django_pytester: DjangoPytester) -> pytest.Pytester:
"""A django_pytester fixture which provides initial_data."""
shutil.rmtree(django_pytester.project_root.joinpath("tpkg/app/migrations"))
django_pytester.makefile(
".json",
initial_data="""
[{
Expand All @@ -165,4 +176,4 @@ def django_testdir_initial(django_testdir):
}]""",
)

return django_testdir
return django_pytester
17 changes: 17 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from pathlib import Path

import pytest


class DjangoPytester(pytest.Pytester): # type: ignore[misc]
project_root: Path

def create_test_module( # type: ignore[empty-body]
self,
test_code: str,
filename: str = ...,
) -> Path:
...

def create_app_file(self, code: str, filename: str) -> Path: # type: ignore[empty-body]
...
Loading

0 comments on commit e36a9bd

Please sign in to comment.