"""Threading primitives and utilities."""importosimportsocketimportsysimportthreadingimporttracebackfromcontextlibimportcontextmanagerfromthreadingimportTIMEOUT_MAXasTHREAD_TIMEOUT_MAXfromcelery.localimportProxytry:fromgreenletimportgetcurrentasget_identexceptImportError:try:from_threadimportget_identexceptImportError:try:fromthreadimportget_identexceptImportError:try:from_dummy_threadimportget_identexceptImportError:fromdummy_threadimportget_ident__all__=('bgThread','Local','LocalStack','LocalManager','get_ident','default_socket_timeout',)USE_FAST_LOCALS=os.environ.get('USE_FAST_LOCALS')
[文档]@contextmanagerdefdefault_socket_timeout(timeout):"""Context temporarily setting the default socket timeout."""prev=socket.getdefaulttimeout()socket.setdefaulttimeout(timeout)yieldsocket.setdefaulttimeout(prev)
[文档]classbgThread(threading.Thread):"""Background service thread."""def__init__(self,name=None,**kwargs):super().__init__()self.__is_shutdown=threading.Event()self.__is_stopped=threading.Event()self.daemon=Trueself.name=nameorself.__class__.__name__
[文档]defrun(self):body=self.bodyshutdown_set=self.__is_shutdown.is_settry:whilenotshutdown_set():try:body()exceptExceptionasexc:# pylint: disable=broad-excepttry:self.on_crash('{0!r} crashed: {1!r}',self.name,exc)self._set_stopped()finally:sys.stderr.flush()os._exit(1)# exiting by normal means won't workfinally:self._set_stopped()
def_set_stopped(self):try:self.__is_stopped.set()exceptTypeError:# pragma: no cover# we lost the race at interpreter shutdown,# so gc collected built-in modules.pass
defrelease_local(local):"""Release the contents of the local for the current context. This makes it possible to use locals without a manager. With this function one can release :class:`Local` objects as well as :class:`StackLocal` objects. However it's not possible to release data held by proxies that way, one always has to retain a reference to the underlying local object in order to be able to release it. Example: >>> loc = Local() >>> loc.foo = 42 >>> release_local(loc) >>> hasattr(loc, 'foo') False """local.__release_local__()
[文档]classLocal:"""Local object."""__slots__=('__storage__','__ident_func__')def__init__(self):object.__setattr__(self,'__storage__',{})object.__setattr__(self,'__ident_func__',get_ident)def__iter__(self):returniter(self.__storage__.items())def__call__(self,proxy):"""Create a proxy for a name."""returnProxy(self,proxy)def__release_local__(self):self.__storage__.pop(self.__ident_func__(),None)def__getattr__(self,name):try:returnself.__storage__[self.__ident_func__()][name]exceptKeyError:raiseAttributeError(name)def__setattr__(self,name,value):ident=self.__ident_func__()storage=self.__storage__try:storage[ident][name]=valueexceptKeyError:storage[ident]={name:value}def__delattr__(self,name):try:delself.__storage__[self.__ident_func__()][name]exceptKeyError:raiseAttributeError(name)
class_LocalStack:"""Local stack. This class works similar to a :class:`Local` but keeps a stack of objects instead. This is best explained with an example:: >>> ls = LocalStack() >>> ls.push(42) >>> ls.top 42 >>> ls.push(23) >>> ls.top 23 >>> ls.pop() 23 >>> ls.top 42 They can be force released by using a :class:`LocalManager` or with the :func:`release_local` function but the correct way is to pop the item from the stack after using. When the stack is empty it will no longer be bound to the current context (and as such released). By calling the stack without arguments it will return a proxy that resolves to the topmost item on the stack. """def__init__(self):self._local=Local()def__release_local__(self):self._local.__release_local__()def_get__ident_func__(self):returnself._local.__ident_func__def_set__ident_func__(self,value):object.__setattr__(self._local,'__ident_func__',value)__ident_func__=property(_get__ident_func__,_set__ident_func__)del_get__ident_func__,_set__ident_func__def__call__(self):def_lookup():rv=self.topifrvisNone:raiseRuntimeError('object unbound')returnrvreturnProxy(_lookup)defpush(self,obj):"""Push a new item to the stack."""rv=getattr(self._local,'stack',None)ifrvisNone:# pylint: disable=assigning-non-slot# This attribute is defined now.self._local.stack=rv=[]rv.append(obj)returnrvdefpop(self):"""Remove the topmost item from the stack. Note: Will return the old value or `None` if the stack was already empty. """stack=getattr(self._local,'stack',None)ifstackisNone:returnNoneeliflen(stack)==1:release_local(self._local)returnstack[-1]else:returnstack.pop()def__len__(self):stack=getattr(self._local,'stack',None)returnlen(stack)ifstackelse0@propertydefstack(self):# get_current_worker_task uses this to find# the original task that was executed by the worker.stack=getattr(self._local,'stack',None)ifstackisnotNone:returnstackreturn[]@propertydeftop(self):"""The topmost item on the stack. Note: If the stack is empty, :const:`None` is returned. """try:returnself._local.stack[-1]except(AttributeError,IndexError):returnNone
[文档]classLocalManager:"""Local objects cannot manage themselves. For that you need a local manager. You can pass a local manager multiple locals or add them later by appending them to ``manager.locals``. Every time the manager cleans up, it will clean up all the data left in the locals for this context. The ``ident_func`` parameter can be added to override the default ident function for the wrapped locals. """def__init__(self,locals=None,ident_func=None):iflocalsisNone:self.locals=[]elifisinstance(locals,Local):self.locals=[locals]else:self.locals=list(locals)ifident_funcisnotNone:self.ident_func=ident_funcforlocalinself.locals:object.__setattr__(local,'__ident_func__',ident_func)else:self.ident_func=get_ident
[文档]defget_ident(self):"""Return context identifier. This is the identifier the local objects use internally for this context. You cannot override this method to change the behavior but use it to link other context local objects (such as SQLAlchemy's scoped sessions) to the Werkzeug locals. """returnself.ident_func()
[文档]defcleanup(self):"""Manually clean up the data in the locals for this context. Call this at the end of the request or use ``make_middleware()``. """forlocalinself.locals:release_local(local)
class_FastLocalStack(threading.local):def__init__(self):self.stack=[]self.push=self.stack.appendself.pop=self.stack.popsuper().__init__()@propertydeftop(self):try:returnself.stack[-1]except(AttributeError,IndexError):returnNonedef__len__(self):returnlen(self.stack)ifUSE_FAST_LOCALS:# pragma: no coverLocalStack=_FastLocalStackelse:# pragma: no cover# - See #706# since each thread has its own greenlet we can just use those as# identifiers for the context. If greenlets aren't available we# fall back to the current thread ident.LocalStack=_LocalStack