root / trunk / twisted / python / context.py

Revision 13744, 2.2 kB (checked in by exarkun, 4 years ago)

merge /b/e/threadableless-2 - simplifies threadable.py, other general thread-related cleanups

Reviewed by glyph. Resolves 994

Line 
1 # -*- test-case-name: twisted.test.test_context -*-
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 #
6
7 """
8 Dynamic pseudo-scoping for Python.
9
10 Call functions with context.call({key: value}, func); func and
11 functions that it calls will be able to use 'context.get(key)' to
12 retrieve 'value'.
13
14 This is thread-safe.
15 """
16
17 try:
18     from threading import local
19 except ImportError:
20     local = None
21
22 from twisted.python import threadable
23
24 defaultContextDict = {}
25
26 setDefault = defaultContextDict.__setitem__
27
28 class ContextTracker:
29     def __init__(self):
30         self.contexts = [defaultContextDict]
31
32     def callWithContext(self, ctx, func, *args, **kw):
33         newContext = self.contexts[-1].copy()
34         newContext.update(ctx)
35         self.contexts.append(newContext)
36         try:
37             return func(*args,**kw)
38         finally:
39             self.contexts.pop()
40
41     def getContext(self, key, default=None):
42         return self.contexts[-1].get(key, default)
43
44
45 class _ThreadedContextTracker:
46     def __init__(self):
47         self.threadId = threadable.getThreadID
48         self.contextPerThread = {}
49
50     def currentContext(self):
51         tkey = self.threadId()
52         try:
53             return self.contextPerThread[tkey]
54         except KeyError:
55             ct = self.contextPerThread[tkey] = ContextTracker()
56             return ct
57
58     def callWithContext(self, ctx, func, *args, **kw):
59         return self.currentContext().callWithContext(ctx, func, *args, **kw)
60
61     def getContext(self, key, default=None):
62         return self.currentContext().getContext(key, default)
63
64
65 class _TLSContextTracker(_ThreadedContextTracker):
66     def __init__(self):
67         self.storage = local()
68
69     def currentContext(self):
70         try:
71             return self.storage.ct
72         except AttributeError:
73             ct = self.storage.ct = ContextTracker()
74             return ct
75
76 if local is None:
77     ThreadedContextTracker = _ThreadedContextTracker
78 else:
79     ThreadedContextTracker = _TLSContextTracker
80
81 def installContextTracker(ctr):
82     global theContextTracker
83     global call
84     global get
85
86     theContextTracker = ctr
87     call = theContextTracker.callWithContext
88     get = theContextTracker.getContext
89
90 installContextTracker(ThreadedContextTracker())
Note: See TracBrowser for help on using the browser.