summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2026-01-14 08:25:37 -0500
committerGitHub <noreply@github.com>2026-01-14 08:25:37 -0500
commit6a596373d464d1d8e9014d952286ab5f6d2a9983 (patch)
treee08e4ab29c97a6612a6d2c8c6c334add51047ea5
parent040bb3eba72eb45020dd025d3f83094a0fcaf22f (diff)
Fixed #35402 -- Fixed crash in DatabaseFeatures.django_test_skips when running a subset of tests.
Thanks Tim Graham for the report and the review.
-rw-r--r--django/db/backends/base/creation.py48
-rw-r--r--tests/backends/base/test_creation.py5
2 files changed, 35 insertions, 18 deletions
diff --git a/django/db/backends/base/creation.py b/django/db/backends/base/creation.py
index ed2b0738a5..5087f80b7e 100644
--- a/django/db/backends/base/creation.py
+++ b/django/db/backends/base/creation.py
@@ -358,27 +358,39 @@ class BaseDatabaseCreation:
Mark tests in Django's test suite which are expected failures on this
database and test which should be skipped on this database.
"""
- # Only load unittest if we're actually testing.
- from unittest import expectedFailure, skip
-
for test_name in self.connection.features.django_test_expected_failures:
- test_case_name, _, test_method_name = test_name.rpartition(".")
- test_app = test_name.split(".")[0]
- # Importing a test app that isn't installed raises RuntimeError.
- if test_app in settings.INSTALLED_APPS:
- test_case = import_string(test_case_name)
- test_method = getattr(test_case, test_method_name)
- setattr(test_case, test_method_name, expectedFailure(test_method))
+ self._mark_test(test_name)
for reason, tests in self.connection.features.django_test_skips.items():
for test_name in tests:
- test_case_name, _, test_method_name = test_name.rpartition(".")
- test_app = test_name.split(".")[0]
- # Importing a test app that isn't installed raises
- # RuntimeError.
- if test_app in settings.INSTALLED_APPS:
- test_case = import_string(test_case_name)
- test_method = getattr(test_case, test_method_name)
- setattr(test_case, test_method_name, skip(reason)(test_method))
+ self._mark_test(test_name, reason)
+
+ def _mark_test(self, test_name, skip_reason=None):
+ # Only load unittest during testing.
+ from unittest import expectedFailure, skip
+
+ module_or_class_name, _, name_to_mark = test_name.rpartition(".")
+ test_app = test_name.split(".")[0]
+ # Importing a test app that isn't installed raises RuntimeError.
+ if test_app in settings.INSTALLED_APPS:
+ try:
+ test_frame = import_string(module_or_class_name)
+ except ImportError:
+ # import_string() can raise ImportError if a submodule's parent
+ # module hasn't already been imported during test discovery.
+ # This can happen in at least two cases:
+ # 1. When running a subset of tests in a module, the test
+ # runner won't import tests in that module's other
+ # submodules.
+ # 2. When the parallel test runner spawns workers with an empty
+ # import cache.
+ test_to_mark = import_string(test_name)
+ test_frame = sys.modules.get(test_to_mark.__module__)
+ else:
+ test_to_mark = getattr(test_frame, name_to_mark)
+ if skip_reason:
+ setattr(test_frame, name_to_mark, skip(skip_reason)(test_to_mark))
+ else:
+ setattr(test_frame, name_to_mark, expectedFailure(test_to_mark))
def sql_table_creation_suffix(self):
"""
diff --git a/tests/backends/base/test_creation.py b/tests/backends/base/test_creation.py
index 2542407f0b..8fd8f490b2 100644
--- a/tests/backends/base/test_creation.py
+++ b/tests/backends/base/test_creation.py
@@ -1,6 +1,7 @@
import copy
import datetime
import os
+import sys
from unittest import mock
from django.db import DEFAULT_DB_ALIAS, connection, connections
@@ -333,6 +334,10 @@ class TestMarkTests(SimpleTestCase):
"backends.base.test_creation.skip_test_function",
},
}
+ # Emulate the scenario where the parent module for
+ # backends.base.test_creation has not been imported yet.
+ popped_module = sys.modules.pop("backends.base")
+ self.addCleanup(sys.modules.__setitem__, "backends.base", popped_module)
creation.mark_expected_failures_and_skips()
self.assertIs(
expected_failure_test_function.__unittest_expecting_failure__,