blob: e4f7e9fd9365d32aba25a5522ae261e8f0b2a3b6 [file] [log] [blame]
# -*- 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())