1. Alexander Solovyov
  2. svarga

Commits

Alexander Solovyov  committed f252bd6

use OrderedDict in contrib.auth and stop using ugly backend.name

  • Participants
  • Parent commits b3bc822
  • Branches default

Comments (0)

Files changed (15)

File requirements.txt

View file
 Jinja2 > 2.4
 WTForms
 amalgam
+ordereddict

File svarga/apps/__init__.py

View file
 import os.path as op
 
+from ordereddict import OrderedDict
+
 from svarga.core.env import Environment
 from svarga.utils.imports import import_module, import_attribute
 from svarga.core.exceptions import ImproperlyConfigured
-from svarga.utils.ordereddict import OrderedDict
 
 
 class AppSettings(object):

File svarga/contrib/admin/admin.py

View file
-from werkzeug import redirect
+from werkzeug.utils import redirect
 
 from svarga import env
 

File svarga/contrib/admin/view.py

View file
 import re
 
-from werkzeug import redirect, url_quote
+from werkzeug.urls import url_quote
+from werkzeug.utils import redirect
 
 from svarga import env
 from svarga.shortcuts.bundle import expose, Bundle

File svarga/contrib/auth/__init__.py

View file
 import datetime
 
+from ordereddict import OrderedDict
+
 from svarga.core.env import env
-from svarga.utils.imports import import_attribute
+from svarga.utils.imports import import_attribute, module_not_found
 
 from svarga.contrib.auth import middleware
 from svarga.contrib.auth import shared
 
 class AuthHandler(object):
     def __init__(self, env_class):
-        # Get list of backends
-        bs = getattr(env_class.settings, 'AUTH_BACKENDS',
-                     ['svarga.contrib.auth.backends.db.AuthBackend'])
-
-        if not bs:
+        if not env_class.settings.AUTH_BACKENDS:
             raise Exception('AUTH_BACKENDS is missing or empty')
 
-        try:
-            backends = list(import_attribute(n) for n in bs)
-        except (ImportError, AttributeError), ex:
-            raise Exception('Failed to import auth backend', ex)
+        self._backends = OrderedDict()
 
-        self.__backends = []
-        self.__backend_ids = {}
-
-        # TODO: Use SortedDict of some form instead of list+dict
-        for backend in backends:
-            nb = backend()
-            self.__backends.append(nb)
-            self.__backend_ids[nb.name] = len(backends) - 1
+        for name in env_class.settings.AUTH_BACKENDS:
+            try:
+                backend = import_attribute(name)
+            except (ImportError, AttributeError), e:
+                if isinstance(e, ImportError) and not module_not_found(1):
+                    raise
+                raise Exception('Failed to import auth backend %s' % name)
+            self._backends[name] = backend()
 
     def get_backend(self, name=None):
         if name is None:
-            return self.__backends[0]
+            return next(self._backends.itervalues())
 
-        if name not in self.__backend_ids:
-            raise Exception('Auth backend ''%s'' was not registered' % name)
+        if not isinstance(name, basestring):
+            return name
 
-        return self.__backends[self.__backend_ids[name]]
+        if name not in self._backends:
+            raise Exception('Auth backend ''%s'' is not registered' % name)
+
+        return self._backends[name]
 
     def authenticate(self, **kwargs):
         def auth_backend(b):
             try:
                 user = b.authenticate(**kwargs)
             except TypeError:
-                # This backend doesn't accept these credentials as arguments. Try the next one.
-                return None
+                # This backend doesn't accept these credentials as
+                # arguments. Try the next one.
+                return
 
             if user is None:
-                return None
+                return
 
             # Annotate the user object with the path of the backend.
-            user.backend = b.name
+            user.backend = b
 
             return user
 
             return auth_backend(b)
 
         # Enumerate through all backends
-        for b in self.__backends:
+        for b in self._backends.values():
             user = auth_backend(b)
 
             if user is not None:
             b = self.get_backend(backend)
             return check_backend(b)
 
-        for b in self.__backends:
+        for b in self._backends.values():
             exists = check_backend(b)
 
             if exists:
         else:
             env.session.cycle_key()
 
+        backend_name = next(name for name, b in self._backends.iteritems()
+                            if b == user.backend)
+
         env.session[SESSION_KEY] = user.id
-        env.session[BACKEND_KEY] = user.backend
+        env.session[BACKEND_KEY] = backend_name
         env.user = user
 
         # Notify backend
         if user.backend:
-            b = self.get_backend(user.backend)
-            if b:
-                b.notify_login(user)
+            user.backend.notify_login(user)
 
     def logout(self):
         # Notify backend
         if env.user.backend:
-            b = self.get_backend(env.user.backend)
-            if b:
-                b.notify_logout(env.user)
+            env.user.backend.notify_logout(env.user)
 
         # Flush session and drop user
         env.session.flush()
         user = b.create_user(**kwargs)
 
         if user is not None:
-            user.backend = b.name
+            user.backend = b
 
         return user
 
             b = self.get_backend(backend)
             user = b.get_user(user_id) or shared.AnonymousUser()
 
-            user.backend = b.name
-        except (KeyError):
+            user.backend = b
+        except KeyError:
             user = shared.AnonymousUser()
 
         return user
     # Requirements
     settings.require('svarga.contrib.sessions')
     settings.default('LOGIN_URL', '/login/')
+    settings.default('AUTH_BACKENDS',
+                     ['svarga.contrib.auth.backends.db.AuthBackend'])
 
     from svarga.contrib.auth.models import __bootstrap__
     __bootstrap__()

File svarga/contrib/auth/backends/db.py

View file
 from svarga.contrib.auth import models
 
 class AuthBackend(object):
-    name = 'db'
-
     def authenticate(self, email, password):
         try:
             user = models.User.query.filter_by(email=email).one()

File svarga/contrib/auth/decorators.py

View file
-from werkzeug import redirect, url_quote
+from werkzeug.urls import url_quote
+from werkzeug.utils import redirect
 
 from svarga.core.env import env
 from svarga.contrib.auth import REDIRECT_FIELD_NAME

File svarga/core/commands.py

View file
 import logging
 from subprocess import call
 
-from werkzeug import SharedDataMiddleware
+from werkzeug.wsgi import SharedDataMiddleware
 from opster import command
 
 from svarga import env, db

File svarga/core/env.py

View file
-from werkzeug import Local, LocalManager, LocalProxy
+from werkzeug.local import Local, LocalManager, LocalProxy
 
 from svarga.core.conf import Settings
 from svarga.utils.imports import import_attribute

File svarga/core/exceptions.py

View file
 "Global Svarga exceptions"
 
-from werkzeug import redirect
+from werkzeug.utils import redirect
 from werkzeug.exceptions import HTTPException
 from jinja2.exceptions import TemplateError as _TemplateError
 

File svarga/core/handler.py

View file
-from werkzeug import ClosingIterator
+from werkzeug.wsgi import ClosingIterator
 from werkzeug.exceptions import HTTPException
 from werkzeug.routing import RequestRedirect
 

File svarga/shortcuts/__init__.py

View file
     import simplejson as json
 
 from opster import wraps
-from werkzeug import Response
+from werkzeug.wrappers import Response
 from svarga.core.env import env
 
 

File svarga/shortcuts/rest.py

View file
 except ImportError:
     import simplejson as json
 
-from werkzeug import Response, routing
+from werkzeug import routing
+from werkzeug.wrappers import Response
 from svarga.core.env import env
 from svarga.core.routing import Rule, get_endpoint
 from svarga.shortcuts import render_to_response

File svarga/utils/imports.py

View file
 def import_attribute(name):
     """
     Import attribute using string reference.
-    Example:
-    import_attribute('a.b.c.foo')
+
+    Example::
+
+      import_attribute('a.b.c.foo')
+
     Throws ImportError or AttributeError if module or attribute do not exist.
     """
     path, attr = name.rsplit('.', 1)
     '''Checks if ImportError was raised because module does not exist or
     something inside it raised ImportError
 
-     - additional_depth - supply int of depth of your call if you're not doing
-       import on the same level of code - f.e., if you call function, which is
-       doing import, you should pass 1 for single additional level of depth
+    - additional_depth - supply int of depth of your call if you're not doing
+      import on the same level of code - f.e., if you call function, which is
+      doing import, you should pass 1 for single additional level of depth
     '''
     tb = sys.exc_info()[2]
     if len(traceback.extract_tb(tb)) > (1 + additional_depth):

File svarga/utils/ordereddict.py

-# Copyright (c) 2009 Raymond Hettinger
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-#     The above copyright notice and this permission notice shall be
-#     included in all copies or substantial portions of the Software.
-#
-#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-#     OTHER DEALINGS IN THE SOFTWARE.
-
-from UserDict import DictMixin
-
-class OrderedDict(dict, DictMixin):
-
-    def __init__(self, *args, **kwds):
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__end
-        except AttributeError:
-            self.clear()
-        self.update(*args, **kwds)
-
-    def clear(self):
-        self.__end = end = []
-        end += [None, end, end]         # sentinel node for doubly linked list
-        self.__map = {}                 # key --> [key, prev, next]
-        dict.clear(self)
-
-    def __setitem__(self, key, value):
-        if key not in self:
-            end = self.__end
-            curr = end[1]
-            curr[2] = end[1] = self.__map[key] = [key, curr, end]
-        dict.__setitem__(self, key, value)
-
-    def __delitem__(self, key):
-        dict.__delitem__(self, key)
-        key, prev, next = self.__map.pop(key)
-        prev[2] = next
-        next[1] = prev
-
-    def __iter__(self):
-        end = self.__end
-        curr = end[2]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[2]
-
-    def __reversed__(self):
-        end = self.__end
-        curr = end[1]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[1]
-
-    def popitem(self, last=True):
-        if not self:
-            raise KeyError('dictionary is empty')
-        if last:
-            key = reversed(self).next()
-        else:
-            key = iter(self).next()
-        value = self.pop(key)
-        return key, value
-
-    def __reduce__(self):
-        items = [[k, self[k]] for k in self]
-        tmp = self.__map, self.__end
-        del self.__map, self.__end
-        inst_dict = vars(self).copy()
-        self.__map, self.__end = tmp
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def keys(self):
-        return list(self)
-
-    setdefault = DictMixin.setdefault
-    update = DictMixin.update
-    pop = DictMixin.pop
-    values = DictMixin.values
-    items = DictMixin.items
-    iterkeys = DictMixin.iterkeys
-    itervalues = DictMixin.itervalues
-    iteritems = DictMixin.iteritems
-
-    def __repr__(self):
-        if not self:
-            return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, self.items())
-
-    def copy(self):
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        if isinstance(other, OrderedDict):
-            if len(self) != len(other):
-                return False
-            for p, q in  zip(self.items(), other.items()):
-                if p != q:
-                    return False
-            return True
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other