Back to index

moin  1.9.0~rc2
local.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     werkzeug.local
00004     ~~~~~~~~~~~~~~
00005 
00006     Sooner or later you have some things you want to have in every single view
00007     or helper function or whatever.  In PHP the way to go are global
00008     variables.  However that is not possible in WSGI applications without a
00009     major drawback:  As soon as you operate on the global namespace your
00010     application is not thread safe any longer.
00011 
00012     The python standard library comes with a utility called "thread locals".
00013     A thread local is a global object where you can put stuff in and get back
00014     later in a thread safe way.  That means whenever you set or get an object
00015     to / from a thread local object the thread local object checks in which
00016     thread you are and delivers the correct value.
00017 
00018     This however has a few disadvantages.  For example besides threads there
00019     are other ways to handle concurrency in Python.  A very popular approach
00020     are greenlets.  Also, whether every request gets its own thread is not
00021     guaranteed in WSGI.  It could be that a request is reusing a thread from
00022     before and data is left in the thread local object.
00023 
00024 
00025     Nutshell
00026     --------
00027 
00028     Here a simple example how you can use werkzeug.local::
00029 
00030         from werkzeug import Local, LocalManager
00031 
00032         local = Local()
00033         local_manager = LocalManager([local])
00034 
00035         def application(environ, start_response):
00036             local.request = request = Request(environ)
00037             ...
00038 
00039         application = local_manager.make_middleware(application)
00040 
00041     Now what this code does is binding request to `local.request`.  Every
00042     other piece of code executed after this assignment in the same context can
00043     safely access local.request and will get the same request object.  The
00044     `make_middleware` method on the local manager ensures that everything is
00045     cleaned up after the request.
00046 
00047     The same context means the same greenlet (if you're using greenlets) in
00048     the same thread and same process.
00049 
00050     If a request object is not yet set on the local object and you try to
00051     access it you will get an `AttributeError`.  You can use `getattr` to avoid
00052     that::
00053 
00054         def get_request():
00055             return getattr(local, 'request', None)
00056 
00057     This will try to get the request or return `None` if the request is not
00058     (yet?) available.
00059 
00060     Note that local objects cannot manage themselves, for that you need a local
00061     manager.  You can pass a local manager multiple locals or add additionals
00062     later by appending them to `manager.locals` and everytime the manager
00063     cleans up it will clean up all the data left in the locals for this
00064     context.
00065 
00066 
00067     :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
00068     :license: BSD, see LICENSE for more details.
00069 """
00070 try:
00071     from py.magic import greenlet
00072     get_current_greenlet = greenlet.getcurrent
00073     del greenlet
00074 except:
00075     # catch all, py.* fails with so many different errors.
00076     get_current_greenlet = int
00077 try:
00078     from thread import get_ident as get_current_thread, allocate_lock
00079 except ImportError:
00080     from dummy_thread import get_ident as get_current_thread, allocate_lock
00081 from werkzeug.utils import ClosingIterator
00082 from werkzeug._internal import _patch_wrapper
00083 
00084 
00085 # get the best ident function.  if greenlets are not installed we can
00086 # savely just use the builtin thread function and save a python methodcall
00087 # and the cost of calculating a hash.
00088 if get_current_greenlet is int:
00089     get_ident = get_current_thread
00090 else:
00091     get_ident = lambda: (get_current_thread(), get_current_greenlet())
00092 
00093 
00094 class Local(object):
00095     __slots__ = ('__storage__', '__lock__')
00096 
00097     def __init__(self):
00098         object.__setattr__(self, '__storage__', {})
00099         object.__setattr__(self, '__lock__', allocate_lock())
00100 
00101     def __iter__(self):
00102         return self.__storage__.iteritems()
00103 
00104     def __call__(self, proxy):
00105         """Create a proxy for a name."""
00106         return LocalProxy(self, proxy)
00107 
00108     def __getattr__(self, name):
00109         self.__lock__.acquire()
00110         try:
00111             try:
00112                 return self.__storage__[get_ident()][name]
00113             except KeyError:
00114                 raise AttributeError(name)
00115         finally:
00116             self.__lock__.release()
00117 
00118     def __setattr__(self, name, value):
00119         self.__lock__.acquire()
00120         try:
00121             ident = get_ident()
00122             storage = self.__storage__
00123             if ident in storage:
00124                 storage[ident][name] = value
00125             else:
00126                 storage[ident] = {name: value}
00127         finally:
00128             self.__lock__.release()
00129 
00130     def __delattr__(self, name):
00131         self.__lock__.acquire()
00132         try:
00133             try:
00134                 del self.__storage__[get_ident()][name]
00135             except KeyError:
00136                 raise AttributeError(name)
00137         finally:
00138             self.__lock__.release()
00139 
00140 
00141 class LocalManager(object):
00142     """Local objects cannot manage themselves. For that you need a local
00143     manager.  You can pass a local manager multiple locals or add them later
00144     by appending them to `manager.locals`.  Everytime the manager cleans up
00145     it, will clean up all the data left in the locals for this context.
00146     """
00147 
00148     def __init__(self, locals=None):
00149         if locals is None:
00150             self.locals = []
00151         elif isinstance(locals, Local):
00152             self.locals = [locals]
00153         else:
00154             self.locals = list(locals)
00155 
00156     def get_ident(self):
00157         """Return the context identifier the local objects use internally for
00158         this context.  You cannot override this method to change the behavior
00159         but use it to link other context local objects (such as SQLAlchemy's
00160         scoped sessions) to the Werkzeug locals.
00161         """
00162         return get_ident()
00163 
00164     def cleanup(self):
00165         """Manually clean up the data in the locals for this context.  Call
00166         this at the end of the request or use `make_middleware()`.
00167         """
00168         ident = self.get_ident()
00169         for local in self.locals:
00170             local.__storage__.pop(ident, None)
00171 
00172     def make_middleware(self, app):
00173         """Wrap a WSGI application so that cleaning up happens after
00174         request end.
00175         """
00176         def application(environ, start_response):
00177             return ClosingIterator(app(environ, start_response), self.cleanup)
00178         return application
00179 
00180     def middleware(self, func):
00181         """Like `make_middleware` but for decorating functions.
00182 
00183         Example usage::
00184 
00185             @manager.middleware
00186             def application(environ, start_response):
00187                 ...
00188 
00189         The difference to `make_middleware` is that the function passed
00190         will have all the arguments copied from the inner application
00191         (name, docstring, module).
00192         """
00193         return _patch_wrapper(func, self.make_middleware(func))
00194 
00195     def __repr__(self):
00196         return '<%s storages: %d>' % (
00197             self.__class__.__name__,
00198             len(self.locals)
00199         )
00200 
00201 
00202 class LocalProxy(object):
00203     """Acts as a proxy for a werkzeug local.  Forwards all operations to
00204     a proxied object.  The only operations not supported for forwarding
00205     are right handed operands and any kind of assignment.
00206 
00207     Example usage::
00208 
00209         from werkzeug import Local
00210         l = Local()
00211         request = l('request')
00212         user = l('user')
00213 
00214     Whenever something is bound to l.user / l.request the proxy objects
00215     will forward all operations.  If no object is bound a `RuntimeError`
00216     will be raised.
00217     """
00218     __slots__ = ('__local', '__dict__', '__name__')
00219 
00220     def __init__(self, local, name):
00221         object.__setattr__(self, '_LocalProxy__local', local)
00222         object.__setattr__(self, '__name__', name)
00223 
00224     def _get_current_object(self):
00225         """Return the current object.  This is useful if you want the real
00226         object behind the proxy at a time for performance reasons or because
00227         you want to pass the object into a different context.
00228         """
00229         try:
00230             return getattr(self.__local, self.__name__)
00231         except AttributeError:
00232             raise RuntimeError('no object bound to %s' % self.__name__)
00233     __current_object = property(_get_current_object)
00234 
00235     def __dict__(self):
00236         try:
00237             return self.__current_object.__dict__
00238         except RuntimeError:
00239             return AttributeError('__dict__')
00240     __dict__ = property(__dict__)
00241 
00242     def __repr__(self):
00243         try:
00244             obj = self.__current_object
00245         except RuntimeError:
00246             return '<%s unbound>' % self.__class__.__name__
00247         return repr(obj)
00248 
00249     def __nonzero__(self):
00250         try:
00251             return bool(self.__current_object)
00252         except RuntimeError:
00253             return False
00254 
00255     def __unicode__(self):
00256         try:
00257             return unicode(self.__current_object)
00258         except RuntimeError:
00259             return repr(self)
00260 
00261     def __dir__(self):
00262         try:
00263             return dir(self.__current_object)
00264         except RuntimeError:
00265             return []
00266 
00267     def __getattr__(self, name):
00268         if name == '__members__':
00269             return dir(self.__current_object)
00270         return getattr(self.__current_object, name)
00271 
00272     def __setitem__(self, key, value):
00273         self.__current_object[key] = value
00274 
00275     def __delitem__(self, key):
00276         del self.__current_object[key]
00277 
00278     def __setslice__(self, i, j, seq):
00279         self.__current_object[i:j] = seq
00280 
00281     def __delslice__(self, i, j):
00282         del self.__current_object[i:j]
00283 
00284     __setattr__ = lambda x, n, v: setattr(x.__current_object, n, v)
00285     __delattr__ = lambda x, n: delattr(x.__current_object, n)
00286     __str__ = lambda x: str(x.__current_object)
00287     __lt__ = lambda x, o: x.__current_object < o
00288     __le__ = lambda x, o: x.__current_object <= o
00289     __eq__ = lambda x, o: x.__current_object == o
00290     __ne__ = lambda x, o: x.__current_object != o
00291     __gt__ = lambda x, o: x.__current_object > o
00292     __ge__ = lambda x, o: x.__current_object >= o
00293     __cmp__ = lambda x, o: cmp(x.__current_object, o)
00294     __hash__ = lambda x: hash(x.__current_object)
00295     __call__ = lambda x, *a, **kw: x.__current_object(*a, **kw)
00296     __len__ = lambda x: len(x.__current_object)
00297     __getitem__ = lambda x, i: x.__current_object[i]
00298     __iter__ = lambda x: iter(x.__current_object)
00299     __contains__ = lambda x, i: i in x.__current_object
00300     __getslice__ = lambda x, i, j: x.__current_object[i:j]
00301     __add__ = lambda x, o: x.__current_object + o
00302     __sub__ = lambda x, o: x.__current_object - o
00303     __mul__ = lambda x, o: x.__current_object * o
00304     __floordiv__ = lambda x, o: x.__current_object // o
00305     __mod__ = lambda x, o: x.__current_object % o
00306     __divmod__ = lambda x, o: x.__current_object.__divmod__(o)
00307     __pow__ = lambda x, o: x.__current_object ** o
00308     __lshift__ = lambda x, o: x.__current_object << o
00309     __rshift__ = lambda x, o: x.__current_object >> o
00310     __and__ = lambda x, o: x.__current_object & o
00311     __xor__ = lambda x, o: x.__current_object ^ o
00312     __or__ = lambda x, o: x.__current_object | o
00313     __div__ = lambda x, o: x.__current_object.__div__(o)
00314     __truediv__ = lambda x, o: x.__current_object.__truediv__(o)
00315     __neg__ = lambda x: -(x.__current_object)
00316     __pos__ = lambda x: +(x.__current_object)
00317     __abs__ = lambda x: abs(x.__current_object)
00318     __invert__ = lambda x: ~(x.__current_object)
00319     __complex__ = lambda x: complex(x.__current_object)
00320     __int__ = lambda x: int(x.__current_object)
00321     __long__ = lambda x: long(x.__current_object)
00322     __float__ = lambda x: float(x.__current_object)
00323     __oct__ = lambda x: oct(x.__current_object)
00324     __hex__ = lambda x: hex(x.__current_object)
00325     __index__ = lambda x: x.__current_object.__index__()
00326     __coerce__ = lambda x, o: x.__coerce__(x, o)
00327     __enter__ = lambda x: x.__enter__()
00328     __exit__ = lambda x, *a, **kw: x.__exit__(*a, **kw)