| # -*- coding: utf-8 -*- |
| """ |
| webapp2_extras.local |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| This module implements thread-local utilities. |
| |
| This implementation comes from werkzeug.local. |
| |
| :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details. |
| :license: BSD, see LICENSE for more details. |
| """ |
| try: |
| from greenlet import getcurrent as get_current_greenlet |
| except ImportError: # pragma: no cover |
| try: |
| from py.magic import greenlet |
| get_current_greenlet = greenlet.getcurrent |
| del greenlet |
| except: |
| # catch all, py.* fails with so many different errors. |
| get_current_greenlet = int |
| try: |
| from thread import get_ident as get_current_thread, allocate_lock |
| except ImportError: # pragma: no cover |
| from dummy_thread import get_ident as get_current_thread, allocate_lock |
| |
| |
| # get the best ident function. if greenlets are not installed we can |
| # safely just use the builtin thread function and save a python methodcall |
| # and the cost of calculating a hash. |
| if get_current_greenlet is int: # pragma: no cover |
| get_ident = get_current_thread |
| else: |
| get_ident = lambda: (get_current_thread(), get_current_greenlet()) |
| |
| |
| class Local(object): |
| """A container for thread-local objects. |
| |
| Attributes are assigned or retrieved using the current thread. |
| """ |
| |
| __slots__ = ('__storage__', '__lock__') |
| |
| def __init__(self): |
| object.__setattr__(self, '__storage__', {}) |
| object.__setattr__(self, '__lock__', allocate_lock()) |
| |
| def __iter__(self): |
| return self.__storage__.iteritems() |
| |
| def __call__(self, proxy): |
| """Creates a proxy for a name.""" |
| return LocalProxy(self, proxy) |
| |
| def __release_local__(self): |
| self.__storage__.pop(get_ident(), None) |
| |
| def __getattr__(self, name): |
| self.__lock__.acquire() |
| try: |
| try: |
| return self.__storage__[get_ident()][name] |
| except KeyError: |
| raise AttributeError(name) |
| finally: |
| self.__lock__.release() |
| |
| def __setattr__(self, name, value): |
| self.__lock__.acquire() |
| try: |
| ident = get_ident() |
| storage = self.__storage__ |
| if ident in storage: |
| storage[ident][name] = value |
| else: |
| storage[ident] = {name: value} |
| finally: |
| self.__lock__.release() |
| |
| def __delattr__(self, name): |
| self.__lock__.acquire() |
| try: |
| try: |
| del self.__storage__[get_ident()][name] |
| except KeyError: |
| raise AttributeError(name) |
| finally: |
| self.__lock__.release() |
| |
| |
| class LocalProxy(object): |
| """Acts as a proxy for a local object. |
| |
| Forwards all operations to a proxied object. The only operations not |
| supported for forwarding are right handed operands and any kind of |
| assignment. |
| |
| Example usage:: |
| |
| from webapp2_extras import Local |
| l = Local() |
| |
| # these are proxies |
| request = l('request') |
| user = l('user') |
| |
| Whenever something is bound to l.user or l.request the proxy objects |
| will forward all operations. If no object is bound a :exc:`RuntimeError` |
| will be raised. |
| |
| To create proxies to :class:`Local` object, call the object as shown above. |
| If you want to have a proxy to an object looked up by a function, you can |
| pass a function to the :class:`LocalProxy` constructor:: |
| |
| route_kwargs = LocalProxy(lambda: webapp2.get_request().route_kwargs) |
| """ |
| |
| __slots__ = ('__local', '__dict__', '__name__') |
| |
| def __init__(self, local, name=None): |
| object.__setattr__(self, '_LocalProxy__local', local) |
| object.__setattr__(self, '__name__', name) |
| |
| def _get_current_object(self): |
| """Return the current object. This is useful if you want the real |
| object behind the proxy at a time for performance reasons or because |
| you want to pass the object into a different context. |
| """ |
| if not hasattr(self.__local, '__release_local__'): |
| return self.__local() |
| try: |
| return getattr(self.__local, self.__name__) |
| except AttributeError: |
| raise RuntimeError('no object bound to %s' % self.__name__) |
| |
| @property |
| def __dict__(self): |
| try: |
| return self._get_current_object().__dict__ |
| except RuntimeError: |
| return AttributeError('__dict__') |
| |
| def __repr__(self): |
| try: |
| obj = self._get_current_object() |
| except RuntimeError: |
| return '<%s unbound>' % self.__class__.__name__ |
| return repr(obj) |
| |
| def __nonzero__(self): |
| try: |
| return bool(self._get_current_object()) |
| except RuntimeError: |
| return False |
| |
| def __unicode__(self): |
| try: |
| return unicode(self._get_current_object()) |
| except RuntimeError: |
| return repr(self) |
| |
| def __dir__(self): |
| try: |
| return dir(self._get_current_object()) |
| except RuntimeError: |
| return [] |
| |
| def __getattr__(self, name): |
| if name == '__members__': |
| return dir(self._get_current_object()) |
| return getattr(self._get_current_object(), name) |
| |
| def __setitem__(self, key, value): |
| self._get_current_object()[key] = value |
| |
| def __delitem__(self, key): |
| del self._get_current_object()[key] |
| |
| def __setslice__(self, i, j, seq): |
| self._get_current_object()[i:j] = seq |
| |
| def __delslice__(self, i, j): |
| del self._get_current_object()[i:j] |
| |
| __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v) |
| __delattr__ = lambda x, n: delattr(x._get_current_object(), n) |
| __str__ = lambda x: str(x._get_current_object()) |
| __lt__ = lambda x, o: x._get_current_object() < o |
| __le__ = lambda x, o: x._get_current_object() <= o |
| __eq__ = lambda x, o: x._get_current_object() == o |
| __ne__ = lambda x, o: x._get_current_object() != o |
| __gt__ = lambda x, o: x._get_current_object() > o |
| __ge__ = lambda x, o: x._get_current_object() >= o |
| __cmp__ = lambda x, o: cmp(x._get_current_object(), o) |
| __hash__ = lambda x: hash(x._get_current_object()) |
| __call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw) |
| __len__ = lambda x: len(x._get_current_object()) |
| __getitem__ = lambda x, i: x._get_current_object()[i] |
| __iter__ = lambda x: iter(x._get_current_object()) |
| __contains__ = lambda x, i: i in x._get_current_object() |
| __getslice__ = lambda x, i, j: x._get_current_object()[i:j] |
| __add__ = lambda x, o: x._get_current_object() + o |
| __sub__ = lambda x, o: x._get_current_object() - o |
| __mul__ = lambda x, o: x._get_current_object() * o |
| __floordiv__ = lambda x, o: x._get_current_object() // o |
| __mod__ = lambda x, o: x._get_current_object() % o |
| __divmod__ = lambda x, o: x._get_current_object().__divmod__(o) |
| __pow__ = lambda x, o: x._get_current_object() ** o |
| __lshift__ = lambda x, o: x._get_current_object() << o |
| __rshift__ = lambda x, o: x._get_current_object() >> o |
| __and__ = lambda x, o: x._get_current_object() & o |
| __xor__ = lambda x, o: x._get_current_object() ^ o |
| __or__ = lambda x, o: x._get_current_object() | o |
| __div__ = lambda x, o: x._get_current_object().__div__(o) |
| __truediv__ = lambda x, o: x._get_current_object().__truediv__(o) |
| __neg__ = lambda x: -(x._get_current_object()) |
| __pos__ = lambda x: +(x._get_current_object()) |
| __abs__ = lambda x: abs(x._get_current_object()) |
| __invert__ = lambda x: ~(x._get_current_object()) |
| __complex__ = lambda x: complex(x._get_current_object()) |
| __int__ = lambda x: int(x._get_current_object()) |
| __long__ = lambda x: long(x._get_current_object()) |
| __float__ = lambda x: float(x._get_current_object()) |
| __oct__ = lambda x: oct(x._get_current_object()) |
| __hex__ = lambda x: hex(x._get_current_object()) |
| __index__ = lambda x: x._get_current_object().__index__() |
| __coerce__ = lambda x, o: x.__coerce__(x, o) |
| __enter__ = lambda x: x.__enter__() |
| __exit__ = lambda x, *a, **kw: x.__exit__(*a, **kw) |