From: Stephen McDonald Date: Thu, 29 Dec 2011 01:40:54 +0000 (+1100) Subject: Refactored loading of BACKENDS to provide a proper entry point (get_backends) respons... X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=2e828c9d56d412a8af71d5f50e871afed4e3dff4;p=django-social-auth.git Refactored loading of BACKENDS to provide a proper entry point (get_backends) responsible for populating BACKENDS where required. --- diff --git a/social_auth/backends/__init__.py b/social_auth/backends/__init__.py index 83713ca..8baaf7a 100644 --- a/social_auth/backends/__init__.py +++ b/social_auth/backends/__init__.py @@ -618,12 +618,12 @@ if setting('SOCIAL_AUTH_IMPORT_BACKENDS'): # Cache for discovered backends. BACKENDS = {} -def get_backend(name, *args, **kwargs): - """Returns a backend by name. Backends are stored in the BACKENDS - cache dict. If not found, each of the modules referenced in +def get_backends(force_load=False): + """ + Entry point to the BACKENDS cache. If BACKENDS hasn't been + populated, each of the modules referenced in AUTHENTICATION_BACKENDS is imported and checked for a BACKENDS - definition. If the named backend is found in the module's BACKENDS - definition, it's then stored in the cache for future access. + definition and if enabled, added to the cache. Previously all backends were attempted to be loaded at import time of this module, which meant that backends that subclass @@ -633,24 +633,35 @@ def get_backend(name, *args, **kwargs): This new approach ensures that backends are allowed to subclass from bases in this module and still be picked up. + + A force_load boolean arg is also provided so that get_backend + below can retry a requested backend that may not yet be discovered. + """ + if not BACKENDS or force_load: + for auth_backend in settings.AUTHENTICATION_BACKENDS: + module = import_module(auth_backend.rsplit(".", 1)[0]) + backends = getattr(module, "BACKENDS", {}) + for name, backend in backends.items(): + if backend.enabled(): + BACKENDS[name] = backend + return BACKENDS + + +def get_backend(name, *args, **kwargs): + """Returns a backend by name. Backends are stored in the BACKENDS + cache dict. If not found, each of the modules referenced in + AUTHENTICATION_BACKENDS is imported and checked for a BACKENDS + definition. If the named backend is found in the module's BACKENDS + definition, it's then stored in the cache for future access. """ try: # Cached backend which has previously been discovered. return BACKENDS[name](*args, **kwargs) except KeyError: - pass - # Look for a BACKENDS definition on each of the modules for - # AUTHENTICATION_BACKENDS. - for auth_backend in settings.AUTHENTICATION_BACKENDS: - module = import_module(auth_backend.rsplit(".", 1)[0]) - backends = getattr(module, "BACKENDS", {}) + # Force a reload of BACKENDS to ensure a missing + # backend hasn't been missed. + get_backends(force_load=True) try: - backend = backends[name] + return BACKENDS[name](*args, **kwargs) except KeyError: - pass - else: - # If the backend is enabled, add it to the cache and - # return it. - if backend.enabled(): - BACKENDS[name] = backend - return backend(*args, **kwargs) + return None diff --git a/social_auth/context_processors.py b/social_auth/context_processors.py index d1e9f18..47bf4c6 100644 --- a/social_auth/context_processors.py +++ b/social_auth/context_processors.py @@ -1,4 +1,4 @@ -from social_auth.backends import BACKENDS +from social_auth.backends import get_backends from social_auth.utils import group_backend_by_type from social_auth.models import User @@ -34,7 +34,7 @@ def social_auth_by_name_backends(request): with a hyphen have the hyphen replaced with an underscore, e.g. google-oauth2 becomes google_oauth2 when referenced in templates. """ - keys = BACKENDS.keys() + keys = get_backends().keys() accounts = dict(zip(keys, [None] * len(keys))) if isinstance(request.user, User) and request.user.is_authenticated(): @@ -56,7 +56,7 @@ def backends_data(user): If user is not authenticated, then first list is empty, and there's no difference between the second and third lists. """ - available = BACKENDS.keys() + available = get_backends().keys() values = {'associated': [], 'not_associated': available, 'backends': available} diff --git a/social_auth/utils.py b/social_auth/utils.py index 9e3ea49..ec5c09e 100644 --- a/social_auth/utils.py +++ b/social_auth/utils.py @@ -65,12 +65,12 @@ def group_backend_by_type(items, key=lambda x: x): # Beware of cyclical imports! from social_auth.backends import \ - BACKENDS, OpenIdAuth, BaseOAuth, BaseOAuth2 + get_backends, OpenIdAuth, BaseOAuth, BaseOAuth2 result = defaultdict(list) for item in items: - backend = BACKENDS[key(item)] + backend = get_backends()[key(item)] if issubclass(backend, OpenIdAuth): result['openid'].append(item) elif issubclass(backend, BaseOAuth2):