diff --git a/django/template/base.py b/django/template/base.py index b87291746b..5e541c3960 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -52,13 +52,12 @@ times with multiple contexts) import inspect import logging -import os import re import warnings from enum import Enum -import django from django.template.context import BaseContext +from django.utils.deprecation import django_file_prefixes from django.utils.formats import localize from django.utils.html import conditional_escape from django.utils.regex_helper import _lazy_re_compile @@ -329,7 +328,7 @@ class PartialTemplate: "PartialTemplate.source is only available when template " "debugging is enabled.", RuntimeWarning, - skip_file_prefixes=(os.path.dirname(django.__file__),), + skip_file_prefixes=django_file_prefixes(), ) return self.find_partial_source(template.source) diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py index 7d5289bd3c..376eb33fae 100644 --- a/django/utils/deprecation.py +++ b/django/utils/deprecation.py @@ -9,6 +9,15 @@ from asgiref.sync import iscoroutinefunction, markcoroutinefunction, sync_to_asy import django +@functools.cache +def django_file_prefixes(): + try: + file = django.__file__ + except AttributeError: + return () + return (os.path.dirname(file),) + + class RemovedInDjango61Warning(DeprecationWarning): pass @@ -237,7 +246,7 @@ def deprecate_posargs(deprecation_warning, remappable_names, /): f"Passing positional argument(s) {remapped_names_str} to {func_name}() " "is deprecated. Use keyword arguments instead.", deprecation_warning, - skip_file_prefixes=(os.path.dirname(django.__file__),), + skip_file_prefixes=django_file_prefixes(), ) return remaining_args, updated_kwargs diff --git a/tests/deprecation/tests.py b/tests/deprecation/tests.py index 66f6a4d922..3d384b38b7 100644 --- a/tests/deprecation/tests.py +++ b/tests/deprecation/tests.py @@ -1,7 +1,32 @@ +import os import warnings +import django from django.test import SimpleTestCase -from django.utils.deprecation import RemovedAfterNextVersionWarning, RenameMethodsBase +from django.utils.deprecation import ( + RemovedAfterNextVersionWarning, + RenameMethodsBase, + django_file_prefixes, +) + + +class DjangoFilePrefixesTests(SimpleTestCase): + def setUp(self): + django_file_prefixes.cache_clear() + + def test_no_file(self): + orig_file = django.__file__ + try: + del django.__file__ + self.assertEqual(django_file_prefixes(), ()) + finally: + django.__file__ = orig_file + + def test_with_file(self): + prefixes = django_file_prefixes() + self.assertIsInstance(prefixes, tuple) + self.assertEqual(len(prefixes), 1) + self.assertTrue(prefixes[0].endswith(f"{os.path.sep}django")) class RenameManagerMethods(RenameMethodsBase):