Skip to content

Commit

Permalink
Expose available_apps in django_db marker (#1071)
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivan-sean committed Oct 25, 2023
1 parent f68f888 commit bf9c965
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 8 deletions.
16 changes: 16 additions & 0 deletions docs/helpers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ dynamically in a hook or fixture.

Note that this will slow down that test suite by approximately 3x.

:type available_apps: Union[List[str], None]
:param available_apps:
.. caution::

This argument is **experimental** and is subject to change without
deprecation.

The ``available_apps`` argument defines a subset of apps that are enabled
for a specific set of tests. Setting ``available_apps`` configures models
for which types/permissions will be created before each test, and which
model tables will be emptied after each test (this truncation may cascade
to unavailable apps models).

For details see :py:attr:`django.test.TransactionTestCase.available_apps`


.. note::

If you want access to the Django database inside a *fixture*, this marker may
Expand Down
24 changes: 16 additions & 8 deletions pytest_django/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import django

_DjangoDbDatabases = Optional[Union["Literal['__all__']", Iterable[str]]]
# transaction, reset_sequences, databases, serialized_rollback
_DjangoDb = Tuple[bool, bool, _DjangoDbDatabases, bool]
_DjangoDbAvailableApps = Optional[List[str]]
# transaction, reset_sequences, databases, serialized_rollback, available_apps
_DjangoDb = Tuple[bool, bool, _DjangoDbDatabases, bool, _DjangoDbAvailableApps]


__all__ = [
Expand Down Expand Up @@ -156,14 +157,16 @@ def _django_db_helper(
reset_sequences,
databases,
serialized_rollback,
available_apps,
) = validate_django_db(marker)
else:
(
transactional,
reset_sequences,
databases,
serialized_rollback,
) = False, False, None, False
available_apps,
) = False, False, None, False, None

transactional = transactional or reset_sequences or (
"transactional_db" in request.fixturenames
Expand All @@ -190,12 +193,15 @@ def _django_db_helper(
_reset_sequences = reset_sequences
_serialized_rollback = serialized_rollback
_databases = databases
_available_apps = available_apps

class PytestDjangoTestCase(test_case_class): # type: ignore[misc,valid-type]
reset_sequences = _reset_sequences
serialized_rollback = _serialized_rollback
if _databases is not None:
databases = _databases
if _available_apps is not None:
available_apps = _available_apps

# For non-transactional tests, skip executing `django.test.TestCase`'s
# `setUpClass`/`tearDownClass`, only execute the super class ones.
Expand Down Expand Up @@ -237,20 +243,22 @@ def validate_django_db(marker) -> "_DjangoDb":
"""Validate the django_db marker.
It checks the signature and creates the ``transaction``,
``reset_sequences``, ``databases`` and ``serialized_rollback`` attributes on
the marker which will have the correct values.
``reset_sequences``, ``databases``, ``serialized_rollback`` and
``available_apps`` attributes on the marker which will have the correct
values.
Sequence reset and serialized_rollback are only allowed when combined with
transaction.
Sequence reset, serialized_rollback, and available_apps are only allowed
when combined with transaction.
"""

def apifun(
transaction: bool = False,
reset_sequences: bool = False,
databases: "_DjangoDbDatabases" = None,
serialized_rollback: bool = False,
available_apps: "_DjangoDbAvailableApps" = None,
) -> "_DjangoDb":
return transaction, reset_sequences, databases, serialized_rollback
return transaction, reset_sequences, databases, serialized_rollback, available_apps

return apifun(*marker.args, **marker.kwargs)

Expand Down
1 change: 1 addition & 0 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ def get_order_number(test: pytest.Item) -> int:
reset_sequences,
databases,
serialized_rollback,
available_apps,
) = validate_django_db(marker_db)
uses_db = True
transactional = transaction or reset_sequences
Expand Down
29 changes: 29 additions & 0 deletions tests/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,35 @@ def test_serialized_rollback_enabled(self, request):
marker = request.node.get_closest_marker("django_db")
assert marker.kwargs["serialized_rollback"]

@pytest.mark.django_db
def test_available_apps_disabled(self, request) -> None:
marker = request.node.get_closest_marker("django_db")
assert not marker.kwargs

@pytest.mark.django_db(available_apps=['pytest_django_test.app'])
def test_available_apps_enabled(self, request) -> None:
marker = request.node.get_closest_marker("django_db")
assert marker.kwargs["available_apps"] == ['pytest_django_test.app']

@pytest.mark.django_db
def test_available_apps_default(self, request) -> None:
from django.apps import apps
from django.conf import settings

for app in settings.INSTALLED_APPS:
assert apps.is_installed(app)

@pytest.mark.django_db(available_apps=['pytest_django_test.app'])
def test_available_apps_limited(self, request) -> None:
from django.apps import apps
from django.conf import settings

assert apps.is_installed("pytest_django_test.app")

for app in settings.INSTALLED_APPS:
if app != "pytest_django_test.app":
assert not apps.is_installed(app)


def test_unittest_interaction(django_testdir) -> None:
"Test that (non-Django) unittests cannot access the DB."
Expand Down

0 comments on commit bf9c965

Please sign in to comment.