Tidy up APISettings object to not rely on module state

This commit is contained in:
Tom Christie 2012-10-10 12:54:40 +01:00
parent db6b5a990b
commit 5c7f3e23ee

View File

@ -21,6 +21,8 @@ from django.conf import settings
from django.utils import importlib from django.utils import importlib
USER_SETTINGS = getattr(settings, 'REST_FRAMEWORK', None)
DEFAULTS = { DEFAULTS = {
'DEFAULT_RENDERERS': ( 'DEFAULT_RENDERERS': (
'rest_framework.renderers.JSONRenderer', '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, If the given setting is a string import notation,
then perform the necessary import or imports. then perform the necessary import or imports.
""" """
if val is None or not setting in IMPORT_STRINGS:
return val
if isinstance(val, basestring): if isinstance(val, basestring):
return import_from_string(val, setting) return import_from_string(val, setting_name)
elif isinstance(val, (list, tuple)): 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 return val
def import_from_string(val, setting): def import_from_string(val, setting_name):
""" """
Attempt to import a class from a string representation. 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) module = importlib.import_module(module_path)
return getattr(module, class_name) return getattr(module, class_name)
except: 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) raise ImportError(msg)
@ -117,19 +116,28 @@ class APISettings(object):
Any setting with string import paths will be automatically resolved Any setting with string import paths will be automatically resolved
and return the class, rather than the string literal. 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): def __getattr__(self, attr):
if attr not in DEFAULTS.keys(): if attr not in self.defaults.keys():
raise AttributeError("Invalid API setting: '%s'" % attr) raise AttributeError("Invalid API setting: '%s'" % attr)
try: try:
# Check if present in user settings # Check if present in user settings
val = perform_import(settings.REST_FRAMEWORK[attr], attr) val = self.user_settings[attr]
except (AttributeError, KeyError): except KeyError:
# Fall back to defaults # 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 # Cache the result
setattr(self, attr, val) setattr(self, attr, val)
return val return val
api_settings = APISettings() api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)