U
    /e2"                     @  s   d Z ddlmZ ddlZeeZddlZddlZddl	m
Z
mZmZmZmZmZ ddlmZ ddlmZ ddlmZ e
rd	d
lmZ dZG dd dZdS )zR Encapulate the management of Document models with a DocumentModelManager
class.

    )annotationsN)TYPE_CHECKINGDict	GeneratorIteratorListSet   )ID)Model)MultiValuedDict   )Document)DocumentModelManagerc                   @  sJ  e Zd ZU dZded< ded< ded< ded	< e Zd
ed< ddddZddddZdddddZ	ddddddZ
dddddZddd d!Zddd"d#Zejd$dd%d&Zd'd(d)d*d+Zdd,dd-d.Zd'd,d)d/d0Zddd1d2Zddd3d4Zdddd5d6Zdd7d7dd8d9d:Zddd;d<Zddd=d>Zd?S )@r   z Manage and provide access to all of the models that belong to a Bokeh
    Document.

    The set of "all models" means specifically all the models reachable from
    references form a Document's roots.

    zweakref.ReferenceType[Document]	_documentint_freeze_countzDict[ID, Model]_modelszMultiValuedDict[str, Model]_models_by_namezSet[ID]_seen_model_idsr   )documentc                 C  s,   t || _d| _i | _t | _t | _dS )z

        Args:
            document (Document): A Document to manage models for
                A weak reference to the Document will be retained

        r   N)	weakrefrefr   r   r   r   r   setr   )selfr    r   9/tmp/pip-unpacked-wheel-f5fndrjf/bokeh/document/models.py__init__G   s
    zDocumentModelManager.__init__)returnc                 C  s
   t | jS N)lenr   r   r   r   r   __len__U   s    zDocumentModelManager.__len__r
   r   )idr   c                 C  s
   | j | S r   r   r   r#   r   r   r   __getitem__X   s    z DocumentModelManager.__getitem__None)r#   modelr   c                 C  s   || j |< d S r   r$   )r   r#   r(   r   r   r   __setitem__[   s    z DocumentModelManager.__setitem__boolc                 C  s
   || j kS r   r$   r%   r   r   r   __contains__^   s    z!DocumentModelManager.__contains__zIterator[Model]c                 C  s   t | j S r   )iterr   valuesr!   r   r   r   __iter__a   s    zDocumentModelManager.__iter__c                 C  s$   | j  D ]}|  q
| ` | `dS )z6 Clean up references to the Documents models

        N)r   r-   destroyr   )r   mr   r   r   r/   d   s    
zDocumentModelManager.destroyzGenerator[(None, None, None)]c                 c  s   |    dV  |   dS )a   Defer expensive model recompuation until intermediate updates are
        complete.

        Making updates to the model graph might trigger events that cause more
        updates. This context manager can be used to prevent expensive model
        recompuation from happening until all events have finished and the
        Document state is quiescent.

        Example:

        .. code-block:: python

            with models.freeze():
                # updates that might change the model graph, that might trigger
                # updates that change the model graph, etc. Recompuation will
                # happen once at the end.

        N)_push_freeze_pop_freezer!   r   r   r   freezeq   s    zDocumentModelManager.freezestrzList[Model])namer   c                 C  s   | j |S )z Find all the models for this Document with a given name.

        Args:
            name (str) : the name of a model to search for

        Returns
            A list of models

        )r   get_allr   r5   r   r   r   get_all_by_name   s    
z$DocumentModelManager.get_all_by_namezModel | Nonec                 C  s   | j |dS )z Find the model for this Document with a given ID.

        Args:
            id (ID) : model ID to search for
                If no model with the given ID exists, returns None

        Return:
            a Model or None

        N)r   getr%   r   r   r   	get_by_id   s    zDocumentModelManager.get_by_idc                 C  s   | j |d| dS )a   Find a single model for this Document with a given name.

        If multiple models are found with the name, an error is raised.

        Args:
            name (str) : the name of a model to search for

        Returns
            A model with the given name, or None

        z!Found more than one model named '')r   Zget_oner7   r   r   r   get_one_by_name   s    z$DocumentModelManager.get_one_by_namec                 C  s   | j dkr|   dS )zf Recompute the set of all models, if not currently frozen

        Returns:
            None

        r   Nr   	recomputer!   r   r   r   
invalidate   s    
zDocumentModelManager.invalidatec                 C  s   |   }|dkrdS t }|jD ]}|| O }q t| j }|| }|| }i }t }|D ]&}	|	||	j< |	jdk	r^|	|	j|	 q^|D ]}
| j
|
j |
  q|D ]}|| q|| _|| _dS )a   Recompute the set of all models based on references reachable from
        the Document's current roots.

        This computation can be expensive. Use ``freeze`` to wrap operations
        that update the model object graph to avoid over-recompuation

        .. note::
            Any models that remove during recomputation will be noted as
            "previously seen"

        N)r   r   rootsZ
referencesr   r-   r   r#   r5   	add_valuer   addZ_detach_documentZ_attach_documentr   )r   r   Z
new_modelsmrZ
old_modelsZ	to_detachZ	to_attachZ
recomputedZrecomputed_by_namemnZmdmar   r   r   r>      s,    



zDocumentModelManager.recomputec                 C  s
   || j kS )z Report whether a model id has ever previously belonged to this
        Document.

        Args:
            id (ID) : the model id of a model to check

        Returns:
            bool

        )r   r%   r   r   r   seen   s    zDocumentModelManager.seenz
str | None)r(   old_namenew_namer   c                 C  s0   |dk	r| j || |dk	r,| j || dS )aD   Update the name for a model.

        .. note::
            This function and the internal name mapping exist to support
            optimizing the common case of name lookup for models. Keeping a
            dedicated name index is faster than using generic ``bokeh.query``
            functions with a name selector

        Args:
            model (Model) : a model to update the name for

            old_name(str, None) : a previous name for the model, or None

            new_name(str, None) : a new name for the model, or None

        Returns:
            None

        N)r   Zremove_valuerA   )r   r(   rG   rH   r   r   r   update_name   s    z DocumentModelManager.update_namec                 C  s   |  j d7  _ d S )Nr   )r   r!   r   r   r   r1     s    z!DocumentModelManager._push_freezec                 C  s$   |  j d8  _ | j dkr |   d S )Nr   r   r=   r!   r   r   r   r2     s    
z DocumentModelManager._pop_freezeN)__name__
__module____qualname____doc____annotations__r   r   r   r"   r&   r)   r+   r.   r/   
contextlibcontextmanagerr3   r8   r:   r<   r?   r>   rF   rI   r1   r2   r   r   r   r   r   8   s0   

.r   )rM   
__future__r   logging	getLoggerrJ   logrO   r   typingr   r   r   r   r   r   Z
core.typesr
   r(   r   Zutil.datatypesr   r   r   __all__r   r   r   r   r   <module>   s   
 
