U
    ڲg                     @   sT   d dl Z d dlZd dlZd dlZd dlmZmZmZ G dd dZG dd dZ	dS )    N)AnyDictUnionc                       sP   e Zd ZdZddddZdd Zeedd fd	d
ZeddddZ	  Z
S )_CVarzStorage utility for Local.N)returnc                 C   s   t d| _d S )Nzasgiref.local)contextvarsZ
ContextVar_dataself r   1/tmp/pip-unpacked-wheel-hay1n6u8/asgiref/local.py__init__   s    z_CVar.__init__c                 C   sB   | j i }z
|| W S  tk
r<   t| d|Y nX d S Nz object has no attribute )r   getKeyErrorAttributeErrorr
   keystorage_objectr   r   r   __getattr__   s
    
z_CVar.__getattr__)r   valuer   c                    s:   |dkrt  ||S | ji }|||< | j| d S )Nr   )super__setattr__r   r   set)r
   r   r   r   	__class__r   r   r      s
    z_CVar.__setattr__)r   r   c                 C   s>   | j i }||kr(||= | j | nt| d|d S r   )r   r   r   r   r   r   r   r   __delattr__   s
    z_CVar.__delattr__)__name__
__module____qualname____doc__r   r   strr   r   r   __classcell__r   r   r   r   r      s
   r   c                       sP   e Zd ZdZdeddddZejdd Zd	d
 Z	 fddZ
dd Z  ZS )Locala  Local storage for async tasks.

    This is a namespace object (similar to `threading.local`) where data is
    also local to the current async task (if there is one).

    In async threads, local means in the same sense as the `contextvars`
    module - i.e. a value set in an async frame will be visible:

    - to other async code `await`-ed from this frame.
    - to tasks spawned using `asyncio` utilities (`create_task`, `wait_for`,
      `gather` and probably others).
    - to code scheduled in a sync thread using `sync_to_async`

    In "sync" threads (a thread with no async event loop running), the
    data is thread-local, but additionally shared with async code executed
    via the `async_to_sync` utility, which schedules async code in a new thread
    and copies context across to that thread.

    If `thread_critical` is True, then the local will only be visible per-thread,
    behaving exactly like `threading.local` if the thread is sync, and as
    `contextvars` if the thread is async. This allows genuinely thread-sensitive
    code (such as DB handles) to be kept stricly to their initial thread and
    disable the sharing across `sync_to_async` and `async_to_sync` wrapped calls.

    Unlike plain `contextvars` objects, this utility is threadsafe.
    FN)thread_criticalr   c                 C   s0   || _ t | _|  |r$t | _nt | _d S N)_thread_critical	threadingRLock_thread_locklocal_storager   )r
   r$   r   r   r   r   D   s    
zLocal.__init__c              	   c   sp   | j rRzt  W n tk
r.   | jV  Y qlX t| jdsFt | j_| jjV  n| j | jV  W 5 Q R X d S )Ncvar)	r&   asyncioZget_running_loopRuntimeErrorr+   hasattrr   r,   r)   r	   r   r   r   _lock_storageQ   s    
zLocal._lock_storagec              
   C   s*   |   }t||W  5 Q R  S Q R X d S r%   )r0   getattrr
   r   storager   r   r   r   t   s    
zLocal.__getattr__c              	      s:   |dkrt  ||S |  }t||| W 5 Q R X d S )N)_localr+   r&   r)   )r   r   r0   setattr)r
   r   r   r3   r   r   r   r   x   s    
zLocal.__setattr__c              	   C   s"   |   }t|| W 5 Q R X d S r%   )r0   delattrr2   r   r   r   r   ~   s    
zLocal.__delattr__)F)r   r   r   r    boolr   
contextlibcontextmanagerr0   r   r   r   r"   r   r   r   r   r#   (   s   
"r#   )
r-   r8   r   r'   typingr   r   r   r   r#   r   r   r   r   <module>   s    