diff --git a/django/conf/__init__.py b/django/conf/__init__.py index 062975b1c6..a380806485 100644 --- a/django/conf/__init__.py +++ b/django/conf/__init__.py @@ -9,9 +9,11 @@ for a list of all possible variables. import importlib import os import time +import traceback import warnings from pathlib import Path +import django from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured from django.utils.deprecation import RemovedInDjango30Warning @@ -19,6 +21,8 @@ from django.utils.functional import LazyObject, empty ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" +DEFAULT_CONTENT_TYPE_DEPRECATED_MSG = 'The DEFAULT_CONTENT_TYPE setting is deprecated.' + class LazySettings(LazyObject): """ @@ -93,6 +97,20 @@ class LazySettings(LazyObject): """Return True if the settings have already been configured.""" return self._wrapped is not empty + @property + def DEFAULT_CONTENT_TYPE(self): + stack = traceback.extract_stack() + # Show a warning if the setting is used outside of Django. + # Stack index: -1 this line, -2 the caller. + filename, _line_number, _function_name, _text = stack[-2] + if not filename.startswith(os.path.dirname(django.__file__)): + warnings.warn( + DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, + RemovedInDjango30Warning, + stacklevel=2, + ) + return self.__getattr__('DEFAULT_CONTENT_TYPE') + class Settings: def __init__(self, settings_module): @@ -126,7 +144,7 @@ class Settings: raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.") if self.is_overridden('DEFAULT_CONTENT_TYPE'): - warnings.warn('The DEFAULT_CONTENT_TYPE setting is deprecated.', RemovedInDjango30Warning) + warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) if hasattr(time, 'tzset') and self.TIME_ZONE: # When we can, attempt to validate the timezone. If we can't find @@ -172,7 +190,7 @@ class UserSettingsHolder: def __setattr__(self, name, value): self._deleted.discard(name) if name == 'DEFAULT_CONTENT_TYPE': - warnings.warn('The DEFAULT_CONTENT_TYPE setting is deprecated.', RemovedInDjango30Warning) + warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) super().__setattr__(name, value) def __delattr__(self, name): diff --git a/tests/view_tests/tests/test_default_content_type.py b/tests/view_tests/tests/test_default_content_type.py index db5f364f26..ece88f4b19 100644 --- a/tests/view_tests/tests/test_default_content_type.py +++ b/tests/view_tests/tests/test_default_content_type.py @@ -1,13 +1,13 @@ import sys from types import ModuleType -from django.conf import Settings +from django.conf import DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, Settings, settings from django.test import SimpleTestCase, ignore_warnings from django.utils.deprecation import RemovedInDjango30Warning class DefaultContentTypeTests(SimpleTestCase): - msg = 'The DEFAULT_CONTENT_TYPE setting is deprecated.' + msg = DEFAULT_CONTENT_TYPE_DEPRECATED_MSG @ignore_warnings(category=RemovedInDjango30Warning) def test_default_content_type_is_text_html(self): @@ -42,3 +42,17 @@ class DefaultContentTypeTests(SimpleTestCase): Settings('fake_settings_module') finally: del sys.modules['fake_settings_module'] + + def test_access_warning(self): + with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): + settings.DEFAULT_CONTENT_TYPE + # Works a second time. + with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): + settings.DEFAULT_CONTENT_TYPE + + @ignore_warnings(category=RemovedInDjango30Warning) + def test_access(self): + with self.settings(DEFAULT_CONTENT_TYPE='text/xml'): + self.assertEqual(settings.DEFAULT_CONTENT_TYPE, 'text/xml') + # Works a second time. + self.assertEqual(settings.DEFAULT_CONTENT_TYPE, 'text/xml')