1import threading
2
3
4class ClassProperty(property):
5    """
6    Use a classmethod as a property
7    http://stackoverflow.com/a/1383402/1258307
8    """
9
10    def __get__(self, cls, owner):
11        return self.fget.__get__(None, owner)()  # pylint: disable=no-member
12
13
14class RequestContext:
15    """
16    A context manager that saves some per-thread state globally.
17    Intended for use with Tornado's StackContext.
18    https://gist.github.com/simon-weber/7755289
19    Simply import this class into any module and access the current request handler by this
20    class's class method property 'current'. If it returns None, there's no active request.
21    .. code:: python
22        from raas.utils.ctx import RequestContext
23        current_request_handler = RequestContext.current
24    """
25
26    _state = threading.local()
27    _state.current_request = {}
28
29    def __init__(self, current_request):
30        self._current_request = current_request
31
32    @ClassProperty
33    @classmethod
34    def current(cls):
35        if not hasattr(cls._state, "current_request"):
36            return {}
37        return cls._state.current_request
38
39    def __enter__(self):
40        self._prev_request = self.__class__.current
41        self.__class__._state.current_request = self._current_request
42
43    def __exit__(self, *exc):
44        self.__class__._state.current_request = self._prev_request
45        del self._prev_request
46        return False
47
48    def __call__(self):
49        return self
50