Skip to content
Merged
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
11 changes: 11 additions & 0 deletions django/test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,17 @@ def disable(self):
)


requires_gil = skipUnless(
# sys._is_gil_enabled() is available on Python 3.13+, and only returns
# False on a free-threaded build with the GIL disabled. Assume the GIL is
# enabled otherwise.
getattr(sys, "_is_gil_enabled", lambda: True)(),
"This test relies on CPython's reference counting to free objects as soon "
"as they become unreachable, which isn't guaranteed on a free-threaded "
"build where the cyclic garbage collector may reclaim them instead.",
)


@contextmanager
def extend_sys_path(*paths):
"""Context manager to temporarily add paths to sys.path."""
Expand Down
4 changes: 2 additions & 2 deletions docs/ref/contrib/gis/gdal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2091,9 +2091,9 @@ supported. You can use them by prepending the provided path with the
appropriate ``/vsi*/`` prefix. See the `GDAL Virtual Filesystems
documentation`_ for more details.

.. warning:
.. warning::

Rasters with names starting with `/vsi*/` will be treated as rasters from
Rasters with names starting with ``/vsi*/`` will be treated as rasters from
the GDAL virtual filesystems. Django doesn't perform any extra validation.

Compressed rasters
Expand Down
3 changes: 2 additions & 1 deletion tests/backends/base/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
skipUnlessDBFeature,
)
from django.test.runner import DebugSQLTextTestResult
from django.test.utils import CaptureQueriesContext, override_settings
from django.test.utils import CaptureQueriesContext, override_settings, requires_gil

from ..models import Person, Square

Expand Down Expand Up @@ -62,6 +62,7 @@ def test_check_database_version_supported_with_none_as_database_version(self):
with patch.object(connection.features, "minimum_database_version", None):
connection.check_database_version_supported()

@requires_gil
def test_release_memory_without_garbage_collection(self):
# Schedule the restore of the garbage collection settings.
self.addCleanup(gc.set_debug, 0)
Expand Down
3 changes: 2 additions & 1 deletion tests/model_regress/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from django.db.models.base import ModelState, ModelStateFieldsCacheDescriptor
from django.test import SimpleTestCase
from django.test.utils import garbage_collect
from django.test.utils import garbage_collect, requires_gil

from .models import Worker, WorkerProfile

Expand All @@ -11,6 +11,7 @@ class ModelStateTests(SimpleTestCase):
def test_fields_cache_descriptor(self):
self.assertIsInstance(ModelState.fields_cache, ModelStateFieldsCacheDescriptor)

@requires_gil
def test_one_to_one_field_cycle_collection(self):
self.addCleanup(gc.set_debug, gc.get_debug())
gc.set_debug(gc.DEBUG_SAVEALL)
Expand Down
13 changes: 9 additions & 4 deletions tests/select_related/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.core.exceptions import FieldError
from django.db.models import FETCH_PEERS
from django.test import SimpleTestCase, TestCase
from django.test.utils import garbage_collect, ignore_warnings
from django.test.utils import garbage_collect, ignore_warnings, requires_gil
from django.utils.deprecation import RemovedInDjango70Warning

from .models import (
Expand Down Expand Up @@ -62,15 +62,19 @@ def setUpTestData(cls):
)

def setup_gc_debug(self):
self.addCleanup(gc.garbage.clear)
self.addCleanup(gc.set_debug, 0)
self.addCleanup(gc.enable)
gc.disable()
garbage_collect()
gc.set_debug(gc.DEBUG_SAVEALL)

def assert_no_memory_leaks(self):
def assert_no_local_function_leaks(self):
garbage_collect()
self.assertEqual(gc.garbage, [])
local_functions_leaked = [
obj for obj in gc.garbage if "<locals>" in getattr(obj, "__qualname__", "")
]
self.assertEqual(local_functions_leaked, [])

def test_access_fks_without_select_related(self):
"""
Expand Down Expand Up @@ -157,10 +161,11 @@ def test_select_related_with_extra(self):
)
self.assertEqual(s.id + 10, s.a)

@requires_gil
def test_select_related_memory_leak(self):
self.setup_gc_debug()
list(Species.objects.select_related("genus"))
self.assert_no_memory_leaks()
self.assert_no_local_function_leaks()

def test_certain_fields(self):
"""
Expand Down
Loading