o 6a@s:ddlZddlZddlZddlZddlZGdddZdS)Ncs\eZdZdZddeddfddZdd Zd d Zd d ZddZ fddZ ddZ Z S)Locala A drop-in replacement for threading.locals that also works with asyncio Tasks (via the current_task asyncio method), and passes locals through sync_to_async and async_to_sync. Specifically: - Locals work per-coroutine on any thread not spawned using asgiref - Locals work per-thread on any thread not spawned using asgiref - Locals are shared with the parent coroutine when using sync_to_async - Locals are shared with the parent thread when using async_to_sync (and if that thread was launched using sync_to_async, with its parent coroutine as well, with this working for indefinite levels of nesting) Set thread_critical to True to not allow locals to pass from an async Task to a thread it spawns. This is needed for code that truly needs thread-safety, as opposed to things used for helpful context (e.g. sqlite does not like being called from a different thread to the one it is from). Thread-critical code will still be differentiated per-Task within a thread as it is expected it does not like concurrent access. This doesn't use contextvars as it needs to support 3.6. Once it can support 3.7 only, we can then reimplement the storage more nicely. Fthread_criticalreturnNcCsD||_t|_t|_dt|d ddt dD|_ dS)Nz_asgiref_local_impl_{}_{}css|] }ttjVqdSN)randomchoicestring ascii_letters).0ir //usr/lib/python3/dist-packages/asgiref/local.py )sz!Local.__init__..) _thread_critical threadingRLock _thread_lockweakrefWeakSet _context_refsformatidjoinrange _attr_name)selfrr r r__init__!s   zLocal.__init__c Csddlm}m}|}d}|durt}d}|jr|Stt D] }z|r0|j |}d}n|j |}d}Wq#t yCY|Swt d)zC Get the ID we should use for looking up variables ) AsyncToSync SyncToAsyncTNFzInfinite launch_map loops) syncr r!get_current_taskrcurrent_threadrrsysgetrecursionlimit launch_mapKeyError RuntimeError)rr r! context_idcontext_is_asyncr r r r_get_context_id,s*   zLocal._get_context_idcCs:|}t||jst||ji|j|t||jSr)r,hasattrrsetattrraddgetattrr context_objr r r _get_storagePs    zLocal._get_storagec CsJz|jD]}zt||jWqtyYqwWdSty$YdSwr)rdelattrrAttributeError TypeErrorr1r r r__del__Ws   z Local.__del__cCsT|j|}||vr||WdSt|d|1s#wYdSNz object has no attribute rr3r5rkeystorager r r __getattr__cszLocal.__getattr__csR|dvr t||S|j|}|||<WddS1s"wYdS)N)rrrr)super __setattr__rr3)rr;valuer< __class__r rr?ks  "zLocal.__setattr__cCsV|j|}||vr||=n t|d|WddS1s$wYdSr8r9r:r r r __delattr__rs"zLocal.__delattr__)F) __name__ __module__ __qualname____doc__boolrr,r3r7r=r?rC __classcell__r r rArrs $ r)rr r%rrrr r r rs