Armin Ronacher avatar Armin Ronacher committed 09fc1c8

The local manager can now accept custom ident functions in the
constructor that are forwarded to the wrapped local objects.

Comments (0)

Files changed (3)

   methods for a given path.
 - The routing system now accepts a parameter to change the encoding
   error behaviour.
+- The local manager can now accept custom ident functions in the
+  constructor that are forwarded to the wrapped local objects.
 
 Version 0.6.2
 -------------

tests/test_local.py

     ls.append(42)
     assert ls == [23, 42]
     assert foo == [23, 42]
+
+
+def test_custom_idents():
+    """Local manager supports custom ident functions"""
+    ident = 0
+    local = Local()
+    stack = LocalStack()
+    mgr = LocalManager([local, stack], ident_func=lambda: ident)
+
+    local.foo = 42
+    stack.push({'foo': 42})
+    ident = 1
+    local.foo = 23
+    stack.push({'foo': 23})
+    ident = 0
+    assert local.foo == 42
+    assert stack.top['foo'] == 42
+    stack.pop()
+    assert stack.top is None
+    ident = 1
+    assert local.foo == 23
+    assert stack.top['foo'] == 23
+    stack.pop()
+    assert stack.top is None

werkzeug/local.py

 
 
 class Local(object):
-    __slots__ = ('__storage__', '__lock__')
+    __slots__ = ('__storage__', '__lock__', '__ident_func__')
 
     def __init__(self):
         object.__setattr__(self, '__storage__', {})
         object.__setattr__(self, '__lock__', allocate_lock())
+        object.__setattr__(self, '__ident_func__', get_ident)
 
     def __iter__(self):
         return self.__storage__.iteritems()
         return LocalProxy(self, proxy)
 
     def __release_local__(self):
-        self.__storage__.pop(get_ident(), None)
+        self.__storage__.pop(self.__ident_func__(), None)
 
     def __getattr__(self, name):
         self.__lock__.acquire()
         try:
             try:
-                return self.__storage__[get_ident()][name]
+                return self.__storage__[self.__ident_func__()][name]
             except KeyError:
                 raise AttributeError(name)
         finally:
     def __setattr__(self, name, value):
         self.__lock__.acquire()
         try:
-            ident = get_ident()
+            ident = self.__ident_func__()
             storage = self.__storage__
             if ident in storage:
                 storage[ident][name] = value
         self.__lock__.acquire()
         try:
             try:
-                del self.__storage__[get_ident()][name]
+                del self.__storage__[self.__ident_func__()][name]
             except KeyError:
                 raise AttributeError(name)
         finally:
     def __release_local__(self):
         self._local.__release_local__()
 
+    def _get__ident_func__(self):
+        return self._local.__ident_func__
+    def _set__ident_func__(self, value):
+        object.__setattr__(self._local, '__ident_func__', value)
+    __ident_func__ = property(_get__ident_func__, _set__ident_func__)
+    del _get__ident_func__, _set__ident_func__
+
     def __call__(self):
         def _lookup():
             rv = self.top
     by appending them to `manager.locals`.  Everytime the manager cleans up
     it, will clean up all the data left in the locals for this context.
 
+    The `ident_func` parameter can be added to override the default ident
+    function for the wrapped locals.
+
     .. versionchanged:: 0.6.1
        Instead of a manager the :func:`release_local` function can be used
        as well.
+
+    .. versionchanged:: 0.7
+       `ident_func` was added.
     """
 
-    def __init__(self, locals=None):
+    def __init__(self, locals=None, ident_func=None):
         if locals is None:
             self.locals = []
         elif isinstance(locals, Local):
             self.locals = [locals]
         else:
             self.locals = list(locals)
+        if ident_func is not None:
+            self.ident_func = ident_func
+            for local in self.locals:
+                object.__setattr__(local, '__ident_func__', ident_func)
+        else:
+            self.ident_func = get_ident
 
     def get_ident(self):
         """Return the context identifier the local objects use internally for
         this context.  You cannot override this method to change the behavior
         but use it to link other context local objects (such as SQLAlchemy's
         scoped sessions) to the Werkzeug locals.
+
+        .. versionchanged:: 0.7
+           Yu can pass a different ident function to the local manager that
+           will then be propagated to all the locals passed to the
+           constructor.
         """
-        return get_ident()
+        return self.ident_func()
 
     def cleanup(self):
         """Manually clean up the data in the locals for this context.  Call
         this at the end of the request or use `make_middleware()`.
         """
-        ident = self.get_ident()
         for local in self.locals:
             release_local(local)
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.