# -*- test-case-name: twisted.test.test_context -*- # Copyright (c) 2001-2004 Twisted Matrix Laboratories. # See LICENSE for details. # """ Dynamic pseudo-scoping for Python. Call functions with context.call({key: value}, func); func and functions that it calls will be able to use 'context.get(key)' to retrieve 'value'. This is thread-safe. """ try: from threading import local except ImportError: local = None from twisted.python import threadable defaultContextDict = {} setDefault = defaultContextDict.__setitem__ class ContextTracker: def __init__(self): self.contexts = [defaultContextDict] def callWithContext(self, ctx, func, *args, **kw): newContext = self.contexts[-1].copy() newContext.update(ctx) self.contexts.append(newContext) try: return func(*args,**kw) finally: self.contexts.pop() def getContext(self, key, default=None): return self.contexts[-1].get(key, default) class _ThreadedContextTracker: def __init__(self): self.threadId = threadable.getThreadID self.contextPerThread = {} def currentContext(self): tkey = self.threadId() try: return self.contextPerThread[tkey] except KeyError: ct = self.contextPerThread[tkey] = ContextTracker() return ct def callWithContext(self, ctx, func, *args, **kw): return self.currentContext().callWithContext(ctx, func, *args, **kw) def getContext(self, key, default=None): return self.currentContext().getContext(key, default) class _TLSContextTracker(_ThreadedContextTracker): def __init__(self): self.storage = local() def currentContext(self): try: return self.storage.ct except AttributeError: ct = self.storage.ct = ContextTracker() return ct if local is None: ThreadedContextTracker = _ThreadedContextTracker else: ThreadedContextTracker = _TLSContextTracker def installContextTracker(ctr): global theContextTracker global call global get theContextTracker = ctr call = theContextTracker.callWithContext get = theContextTracker.getContext installContextTracker(ThreadedContextTracker())