diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 4ee10155c..5ebe7ba53 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -21,6 +21,8 @@ from django.conf import settings from django.utils import importlib +USER_SETTINGS = getattr(settings, 'REST_FRAMEWORK', None) + DEFAULTS = { 'DEFAULT_RENDERERS': ( 'rest_framework.renderers.JSONRenderer', @@ -76,22 +78,19 @@ IMPORT_STRINGS = ( ) -def perform_import(val, setting): +def perform_import(val, setting_name): """ If the given setting is a string import notation, then perform the necessary import or imports. """ - if val is None or not setting in IMPORT_STRINGS: - return val - if isinstance(val, basestring): - return import_from_string(val, setting) + return import_from_string(val, setting_name) elif isinstance(val, (list, tuple)): - return [import_from_string(item, setting) for item in val] + return [import_from_string(item, setting_name) for item in val] return val -def import_from_string(val, setting): +def import_from_string(val, setting_name): """ Attempt to import a class from a string representation. """ @@ -102,7 +101,7 @@ def import_from_string(val, setting): module = importlib.import_module(module_path) return getattr(module, class_name) except: - msg = "Could not import '%s' for API setting '%s'" % (val, setting) + msg = "Could not import '%s' for API setting '%s'" % (val, setting_name) raise ImportError(msg) @@ -117,19 +116,28 @@ class APISettings(object): Any setting with string import paths will be automatically resolved and return the class, rather than the string literal. """ + def __init__(self, user_settings=None, defaults=None, import_strings=None): + self.user_settings = user_settings or {} + self.defaults = defaults or {} + self.import_strings = import_strings or () + def __getattr__(self, attr): - if attr not in DEFAULTS.keys(): + if attr not in self.defaults.keys(): raise AttributeError("Invalid API setting: '%s'" % attr) try: # Check if present in user settings - val = perform_import(settings.REST_FRAMEWORK[attr], attr) - except (AttributeError, KeyError): + val = self.user_settings[attr] + except KeyError: # Fall back to defaults - val = perform_import(DEFAULTS[attr], attr) + val = self.defaults[attr] + + # Coerce import strings into classes + if val and attr in self.import_strings: + val = perform_import(val, attr) # Cache the result setattr(self, attr, val) return val -api_settings = APISettings() +api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)