diff --git a/rest_framework/settings.py b/rest_framework/settings.py index d9e3a2942..478a5229f 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -200,6 +200,7 @@ class APISettings(object): self._user_settings = self.__check_user_settings(user_settings) self.defaults = defaults or DEFAULTS self.import_strings = import_strings or IMPORT_STRINGS + self._cached_attrs = set() @property def user_settings(self): @@ -223,6 +224,7 @@ class APISettings(object): val = perform_import(val, attr) # Cache the result + self._cached_attrs.add(attr) setattr(self, attr, val) return val @@ -233,15 +235,21 @@ class APISettings(object): raise RuntimeError("The '%s' setting has been removed. Please refer to '%s' for available settings." % (setting, SETTINGS_DOC)) return user_settings + def reload(self): + for attr in self._cached_attrs: + delattr(self, attr) + self._cached_attrs.clear() + if hasattr(self, '_user_settings'): + delattr(self, '_user_settings') + api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) def reload_api_settings(*args, **kwargs): - global api_settings - setting, value = kwargs['setting'], kwargs['value'] + setting = kwargs['setting'] if setting == 'REST_FRAMEWORK': - api_settings = APISettings(value, DEFAULTS, IMPORT_STRINGS) + api_settings.reload() setting_changed.connect(reload_api_settings) diff --git a/tests/test_settings.py b/tests/test_settings.py index 9ba552d28..51e9751b2 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,8 +1,8 @@ from __future__ import unicode_literals -from django.test import TestCase +from django.test import TestCase, override_settings -from rest_framework.settings import APISettings +from rest_framework.settings import APISettings, api_settings class TestSettings(TestCase): @@ -28,6 +28,23 @@ class TestSettings(TestCase): 'MAX_PAGINATE_BY': 100 }) + def test_compatibility_with_override_settings(self): + """ + Ref #5658 & #2466: Documented usage of api_settings + is bound at import time: + + from rest_framework.settings import api_settings + + setting_changed signal hook must ensure bound instance + is refreshed. + """ + assert api_settings.PAGE_SIZE is None, "Checking a known default should be None" + + with override_settings(REST_FRAMEWORK={'PAGE_SIZE': 10}): + assert api_settings.PAGE_SIZE == 10, "Setting should have been updated" + + assert api_settings.PAGE_SIZE is None, "Setting should have been restored" + class TestSettingTypes(TestCase): def test_settings_consistently_coerced_to_list(self):