Ticket #1268: current_user.diff

File current_user.diff, 7.8 KB (added by jkocherhans, 14 years ago)

initial attempt

  • django/utils/threading.py

     
     1# Copy of _thread_local.py from python 2.4. Used for python 2.3 support.
     2"""Thread-local objects
     3
     4(Note that this module provides a Python version of thread
     5 threading.local class.  Depending on the version of Python you're
     6 using, there may be a faster one available.  You should always import
     7 the local class from threading.)
     8
     9Thread-local objects support the management of thread-local data.
     10If you have data that you want to be local to a thread, simply create
     11a thread-local object and use its attributes:
     12
     13  >>> mydata = local()
     14  >>> mydata.number = 42
     15  >>> mydata.number
     16  42
     17
     18You can also access the local-object's dictionary:
     19
     20  >>> mydata.__dict__
     21  {'number': 42}
     22  >>> mydata.__dict__.setdefault('widgets', [])
     23  []
     24  >>> mydata.widgets
     25  []
     26
     27What's important about thread-local objects is that their data are
     28local to a thread. If we access the data in a different thread:
     29
     30  >>> log = []
     31  >>> def f():
     32  ...     items = mydata.__dict__.items()
     33  ...     items.sort()
     34  ...     log.append(items)
     35  ...     mydata.number = 11
     36  ...     log.append(mydata.number)
     37
     38  >>> import threading
     39  >>> thread = threading.Thread(target=f)
     40  >>> thread.start()
     41  >>> thread.join()
     42  >>> log
     43  [[], 11]
     44
     45we get different data.  Furthermore, changes made in the other thread
     46don't affect data seen in this thread:
     47
     48  >>> mydata.number
     49  42
     50
     51Of course, values you get from a local object, including a __dict__
     52attribute, are for whatever thread was current at the time the
     53attribute was read.  For that reason, you generally don't want to save
     54these values across threads, as they apply only to the thread they
     55came from.
     56
     57You can create custom local objects by subclassing the local class:
     58
     59  >>> class MyLocal(local):
     60  ...     number = 2
     61  ...     initialized = False
     62  ...     def __init__(self, **kw):
     63  ...         if self.initialized:
     64  ...             raise SystemError('__init__ called too many times')
     65  ...         self.initialized = True
     66  ...         self.__dict__.update(kw)
     67  ...     def squared(self):
     68  ...         return self.number ** 2
     69
     70This can be useful to support default values, methods and
     71initialization.  Note that if you define an __init__ method, it will be
     72called each time the local object is used in a separate thread.  This
     73is necessary to initialize each thread's dictionary.
     74
     75Now if we create a local object:
     76
     77  >>> mydata = MyLocal(color='red')
     78
     79Now we have a default number:
     80
     81  >>> mydata.number
     82  2
     83
     84an initial color:
     85
     86  >>> mydata.color
     87  'red'
     88  >>> del mydata.color
     89
     90And a method that operates on the data:
     91
     92  >>> mydata.squared()
     93  4
     94
     95As before, we can access the data in a separate thread:
     96
     97  >>> log = []
     98  >>> thread = threading.Thread(target=f)
     99  >>> thread.start()
     100  >>> thread.join()
     101  >>> log
     102  [[('color', 'red'), ('initialized', True)], 11]
     103
     104without affecting this thread's data:
     105
     106  >>> mydata.number
     107  2
     108  >>> mydata.color
     109  Traceback (most recent call last):
     110  ...
     111  AttributeError: 'MyLocal' object has no attribute 'color'
     112
     113Note that subclasses can define slots, but they are not thread
     114local. They are shared across threads:
     115
     116  >>> class MyLocal(local):
     117  ...     __slots__ = 'number'
     118
     119  >>> mydata = MyLocal()
     120  >>> mydata.number = 42
     121  >>> mydata.color = 'red'
     122
     123So, the separate thread:
     124
     125  >>> thread = threading.Thread(target=f)
     126  >>> thread.start()
     127  >>> thread.join()
     128
     129affects what we see:
     130
     131  >>> mydata.number
     132  11
     133
     134>>> del mydata
     135"""
     136
     137# Threading import is at end
     138
     139class _localbase(object):
     140    __slots__ = '_local__key', '_local__args', '_local__lock'
     141
     142    def __new__(cls, *args, **kw):
     143        self = object.__new__(cls)
     144        key = '_local__key', 'thread.local.' + str(id(self))
     145        object.__setattr__(self, '_local__key', key)
     146        object.__setattr__(self, '_local__args', (args, kw))
     147        object.__setattr__(self, '_local__lock', RLock())
     148
     149        if args or kw and (cls.__init__ is object.__init__):
     150            raise TypeError("Initialization arguments are not supported")
     151
     152        # We need to create the thread dict in anticipation of
     153        # __init__ being called, to make sire we don't cal it
     154        # again ourselves.
     155        dict = object.__getattribute__(self, '__dict__')
     156        currentThread().__dict__[key] = dict
     157
     158        return self
     159
     160def _patch(self):
     161    key = object.__getattribute__(self, '_local__key')
     162    d = currentThread().__dict__.get(key)
     163    if d is None:
     164        d = {}
     165        currentThread().__dict__[key] = d
     166        object.__setattr__(self, '__dict__', d)
     167
     168        # we have a new instance dict, so call out __init__ if we have
     169        # one
     170        cls = type(self)
     171        if cls.__init__ is not object.__init__:
     172            args, kw = object.__getattribute__(self, '_local__args')
     173            cls.__init__(self, *args, **kw)
     174    else:
     175        object.__setattr__(self, '__dict__', d)
     176
     177class local(_localbase):
     178
     179    def __getattribute__(self, name):
     180        lock = object.__getattribute__(self, '_local__lock')
     181        lock.acquire()
     182        try:
     183            _patch(self)
     184            return object.__getattribute__(self, name)
     185        finally:
     186            lock.release()
     187
     188    def __setattr__(self, name, value):
     189        lock = object.__getattribute__(self, '_local__lock')
     190        lock.acquire()
     191        try:
     192            _patch(self)
     193            return object.__setattr__(self, name, value)
     194        finally:
     195            lock.release()
     196
     197    def __delattr__(self, name):
     198        lock = object.__getattribute__(self, '_local__lock')
     199        lock.acquire()
     200        try:
     201            _patch(self)
     202            return object.__delattr__(self, name)
     203        finally:
     204            lock.release()
     205
     206
     207    def __del__():
     208        threading_enumerate = enumerate
     209        __getattribute__ = object.__getattribute__
     210
     211        def __del__(self):
     212            key = __getattribute__(self, '_local__key')
     213
     214            try:
     215                threads = list(threading_enumerate())
     216            except:
     217                # if enumerate fails, as it seems to do during
     218                # shutdown, we'll skip cleanup under the assumption
     219                # that there is nothing to clean up
     220                return
     221
     222            for thread in threads:
     223                try:
     224                    __dict__ = thread.__dict__
     225                except AttributeError:
     226                    # Thread is dying, rest in peace
     227                    continue
     228
     229                if key in __dict__:
     230                    try:
     231                        del __dict__[key]
     232                    except KeyError:
     233                        pass # didn't have anything in this thread
     234
     235        return __del__
     236    __del__ = __del__()
     237
     238from threading import currentThread, enumerate, RLock
  • django/contrib/auth/middleware.py

     
     1from django.contrib.auth import set_user
     2
     3class AuthMiddleware:
     4    def process_request(self, request):
     5        set_user(request.user)
  • django/contrib/auth/__init__.py

     
     1try:
     2    # only exists in python 2.4+
     3    from threading import local
     4except ImportError:
     5    # import copy of _thread_local.py from python 2.4
     6    from django.utils.threading import local
     7
     8thread_locals = local()
     9
     10def get_user():
     11    return thread_locals.user
     12
     13def set_user(user):
     14    thread_locals.user = user
     15 No newline at end of file
Back to Top