a
    nar@                     @  s  d Z ddlmZ ddlZeeZddlZddlm	Z	m
Z
mZmZmZ ddlZddlmZ e	rddlmZ ddlmZ dd	lmZ d
dlmZmZ d
dlmZ ddlmZ edZdZ dd Z!G dd dZ"G dd de"e#Z$G dd de"e%Z&G dd de&Z'dS )a   Provide special versions of list and dict, that can automatically notify
about changes when used for property values.

Mutations to these values are detected, and the properties owning the
collection is notified of the changes. Consider the following model
definition:

.. code-block:: python

    class SomeModel(Model):

        options = List(String)

If we have an instance of this model, ``m`` then we can set the entire
value of the ``options`` property at once:

.. code-block:: python

    m.options = ["foo", "bar"]

When we do this in the context of a Bokeh server application that is being
viewed in a browser, this change is automatically noticed, and the
corresponding BokehJS property in the browser is synchronized, possibly
causing some change in the visual state of the application in the browser.

But it is also desirable that changes *inside* the ``options`` list also
be detected. That is, the following kinds of operations should also be
automatically synchronized between BokehJS and a Bokeh server:

.. code-block:: python

    m.options.append("baz")

    m.options[2] = "quux"

    m.options.insert(0, "bar")

The classes in this module provide this functionality.

.. note::
    These classes form part of the very low-level machinery that implements
    the Bokeh model and property system. It is unlikely that any of these
    classes or their methods will be applicable to any standard usage or to
    anyone who is not directly developing on Bokeh's own infrastructure.

    )annotationsN)TYPE_CHECKINGAnyDictSetTuple   )import_optional)Document)DocumentPatchedEvent)ColumnarDataSource   )HasPropsSetter)Unknown   )PropertyDescriptorZpandas)notify_ownerPropertyValueContainerPropertyValueListPropertyValueDictPropertyValueColumnDatac                   s     fdd}d j  d|_|S )af   A decorator for mutating methods of property container classes
    that notifies owners of the property container about mutating changes.

    Args:
        func (callable) : the container method to wrap in a notification

    Returns:
        wrapped method

    Examples:

        A ``__setitem__`` could be wrapped like this:

        .. code-block:: python

            # x[i] = y
            @notify_owner
            def __setitem__(self, i, y):
                return super().__setitem__(i, y)

    The returned wrapped method will have a docstring indicating what
    original method it is wrapping.

    c                   s,   |   } | g|R i |}| | |S N)_saved_copy_notify_owners)selfargskwargsoldresultfunc ;lib/python3.9/site-packages/bokeh/core/property/wrappers.pywrapper   s    
znotify_owner.<locals>.wrapperzContainer method ``z)`` instrumented to notify property owners)__name____doc__)r!   r$   r"   r    r#   r   p   s    r   c                      sp   e Zd ZU dZded< dd fddZdd	dd
ddZdd	dd
ddZdddddddZdd Z	  Z
S )r   ab   A base class for property container classes that support change
    notifications on mutating operations.

    This class maintains an internal list of property owners, and also
    provides a private mechanism for methods wrapped with
    :func:`~bokeh.core.property.wrappers.notify_owners` to update
    those owners when mutating changes occur.

    z-Set[Tuple[HasProps, PropertyDescriptor[Any]]]_ownersNonereturnc                   s   t  | _t j|i | d S r   )setr'   super__init__r   r   r   	__class__r"   r#   r-      s    zPropertyValueContainer.__init__r   zPropertyDescriptor[Any])owner
descriptorr*   c                 C  s   | j ||f d S r   )r'   addr   r1   r2   r"   r"   r#   _register_owner   s    z&PropertyValueContainer._register_ownerc                 C  s   | j ||f d S r   )r'   discardr4   r"   r"   r#   _unregister_owner   s    z(PropertyValueContainer._unregister_ownerNr   zDocumentPatchedEvent | None)r   hintr*   c                 C  s$   | j D ]\}}|j|||d qd S )Nr8   )r'   _notify_mutated)r   r   r8   r1   r2   r"   r"   r#   r      s    z%PropertyValueContainer._notify_ownersc                 C  s   t dd S )Nz2Subtypes must implement this to make a backup copy)RuntimeErrorr   r"   r"   r#   r      s    z"PropertyValueContainer._saved_copy)N)r%   
__module____qualname__r&   __annotations__r-   r5   r7   r   r   __classcell__r"   r"   r/   r#   r      s   
	r   c                      s   e Zd ZdZdd fddZdd Ze fdd	Ze fd
dZe fddZ	e fddZ
e fddZe fddZe fddZed fdd	Ze fddZe fddZe fddZ  ZS ) r   a   A list property value container that supports change notifications on
    mutating operations.

    When a Bokeh model has a ``List`` property, the ``PropertyValueLists`` are
    transparently created to wrap those values. These ``PropertyValueList``
    values are subject to normal property validation. If the property type
    ``foo = List(Str)`` then attempting to set ``x.foo[0] = 10`` will raise
    an error.

    Instances of ``PropertyValueList`` can be explicitly created by passing
    any object that the standard list initializer accepts, for example:

    .. code-block:: python

        >>> PropertyValueList([10, 20])
        [10, 20]

        >>> PropertyValueList((10, 20))
        [10, 20]

    The following mutating operations on lists automatically trigger
    notifications:

    .. code-block:: python

        del x[y]
        del x[i:j]
        x += y
        x *= y
        x[i] = y
        x[i:j] = y
        x.append
        x.extend
        x.insert
        x.pop
        x.remove
        x.reverse
        x.sort

    r(   r)   c                   s   t  j|i |S r   r,   r-   r.   r/   r"   r#   r-      s    zPropertyValueList.__init__c                 C  s   t | S r   )listr<   r"   r"   r#   r      s    zPropertyValueList._saved_copyc                   s   t  |S r   r,   __delitem__r   yr/   r"   r#   rD      s    zPropertyValueList.__delitem__c                   s   t  |S r   )r,   __iadd__rE   r/   r"   r#   rG      s    zPropertyValueList.__iadd__c                   s   t  |S r   )r,   __imul__rE   r/   r"   r#   rH      s    zPropertyValueList.__imul__c                   s   t  ||S r   r,   __setitem__r   irF   r/   r"   r#   rJ      s    zPropertyValueList.__setitem__c                   s   t  |S r   )r,   appendr   objr/   r"   r#   rM      s    zPropertyValueList.appendc                   s   t  |S r   )r,   extend)r   iterabler/   r"   r#   rP      s    zPropertyValueList.extendc                   s   t  ||S r   )r,   insert)r   indexrO   r/   r"   r#   rR      s    zPropertyValueList.insertc                   s   t  |S r   r,   pop)r   rS   r/   r"   r#   rV      s    zPropertyValueList.popc                   s   t  |S r   )r,   removerN   r/   r"   r#   rW     s    zPropertyValueList.removec                   s
   t   S r   )r,   reverser<   r/   r"   r#   rX     s    zPropertyValueList.reversec                   s   t  jf i |S r   )r,   sort)r   r   r/   r"   r#   rY   
  s    zPropertyValueList.sort)rT   )r%   r=   r>   r&   r-   r   r   rD   rG   rH   rJ   rM   rP   rR   rV   rW   rX   rY   r@   r"   r"   r/   r#   r      s2   )r   c                      s   e Zd ZdZdd fddZdd Ze fdd	Ze fd
dZe fddZ	e fddZ
e fddZe fddZe fddZ  ZS )r   a1   A dict property value container that supports change notifications on
    mutating operations.

    When a Bokeh model has a ``List`` property, the ``PropertyValueLists`` are
    transparently created to wrap those values. These ``PropertyValueList``
    values are subject to normal property validation. If the property type
    ``foo = Dict(Str, Str)`` then attempting to set ``x.foo['bar'] = 10`` will
    raise an error.

    Instances of ``PropertyValueDict`` can be eplicitly created by passing
    any object that the standard dict initializer accepts, for example:

    .. code-block:: python

        >>> PropertyValueDict(dict(a=10, b=20))
        {'a': 10, 'b': 20}

        >>> PropertyValueDict(a=10, b=20)
        {'a': 10, 'b': 20}

        >>> PropertyValueDict([('a', 10), ['b', 20]])
        {'a': 10, 'b': 20}

    The following mutating operations on dicts automatically trigger
    notifications:

    .. code-block:: python

        del x[y]
        x[i] = y
        x.clear
        x.pop
        x.popitem
        x.setdefault
        x.update

    r(   r)   c                   s   t  j|i |S r   rA   r.   r/   r"   r#   r-   4  s    zPropertyValueDict.__init__c                 C  s   t | S r   )dictr<   r"   r"   r#   r   7  s    zPropertyValueDict._saved_copyc                   s   t  |S r   rC   rE   r/   r"   r#   rD   ;  s    zPropertyValueDict.__delitem__c                   s   t  ||S r   rI   rK   r/   r"   r#   rJ   @  s    zPropertyValueDict.__setitem__c                   s
   t   S r   )r,   clearr<   r/   r"   r#   r[   D  s    zPropertyValueDict.clearc                   s   t  j| S r   rU   r   r   r/   r"   r#   rV   H  s    zPropertyValueDict.popc                   s
   t   S r   )r,   popitemr<   r/   r"   r#   r]   L  s    zPropertyValueDict.popitemc                   s   t  j| S r   )r,   
setdefaultr\   r/   r"   r#   r^   P  s    zPropertyValueDict.setdefaultc                   s   t  j|i |S r   )r,   updater.   r/   r"   r#   r_   T  s    zPropertyValueDict.update)r%   r=   r>   r&   r-   r   r   rD   rJ   r[   rV   r]   r^   r_   r@   r"   r"   r/   r#   r     s"   %r   c                   @  sd   e Zd ZdZdd Zdd Zi fddZdd	 ZddddddddddZddddddddZ	d
S )r   a   A property value container for ColumnData that supports change
    notifications on mutating operations.

    This property value container affords specialized code paths for
    updating the .data dictionary for ColumnDataSource. When possible,
    more efficient ColumnDataChangedEvent hints are generated to perform
    the updates:

    .. code-block:: python

        x[i] = y
        x.update

    c                 C  s   |  ||fgS r   )r_   rK   r"   r"   r#   rJ   j  s    z#PropertyValueColumnData.__setitem__c                 C  s   t t| S r   )r   rZ   r<   r"   r"   r#   __copy__m  s    z PropertyValueColumnData.__copy__c                 C  s   t tt| |S r   )r   copydeepcopyrZ   )r   Zmemodictr"   r"   r#   __deepcopy__p  s    z$PropertyValueColumnData.__deepcopy__c                 O  s   |   }tj| g|R i |}ddlm} t| }t|dkrz|d }t|drh|t| O }n|dd |D O }| j	D ],\}}	||j
|t|d}
|	j|||
d	 q|S )
Nr   )ColumnDataChangedEventr   r   keysc                 S  s   h | ]}|d  qS )r   r"   ).0xr"   r"   r#   	<setcomp>      z1PropertyValueColumnData.update.<locals>.<setcomp>)colsr9   )r   rZ   r_   document.eventsrd   r+   re   lenhasattrr'   documentrB   r:   )r   r   r   r   r   rd   rj   Er1   r2   r8   r"   r"   r#   r_   t  s    
zPropertyValueColumnData.updateNr
   r   zDict[str, Any]z
int | NonezSetter | Noner(   )docsourcenew_datarolloversetterr*   c                 C  s   |   }| D ]\}}t| | tjs8t|| tjrzt| | || }	|rjt|	|krj|	| d }	t| ||	 q| | }
|
	||  |dur|
d| = qddl
m} | j|||||||d dS )a_   Internal implementation to handle special-casing stream events
        on ``ColumnDataSource`` columns.

        Normally any changes to the ``.data`` dict attribute on a
        ``ColumnDataSource`` triggers a notification, causing all of the data
        to be synchronized between server and clients.

        The ``.stream`` method on column data sources exists to provide a
        more efficient way to perform streaming (i.e. append-only) updates
        to a data source, without having to perform a full synchronization,
        which would needlessly re-send all the data.

        To accomplish this, this function bypasses the wrapped methods on
        ``PropertyValueDict`` and uses the unwrapped versions on the dict
        superclass directly. It then explicitly makes a notification, adding
        a special ``ColumnsStreamedEvent`` hint to the message containing
        only the small streamed data that BokehJS needs in order to
        efficiently synchronize.

        .. warning::
            This function assumes the integrity of ``new_data`` has already
            been verified.

        Nr   )ColumnsStreamedEventr9   )r   items
isinstancenpZndarrayrM   rl   rZ   rJ   rP   rk   ru   r   )r   rp   rq   rr   rs   rt   r   kvdataLru   r"   r"   r#   _stream  s     zPropertyValueColumnData._stream)rp   rq   rt   r*   c                 C  s   |   }| D ]\}}|D ]v\}}	t|ttfr@|	| | |< q| | |d  t|dd  j}
tj|	dd	|
| | |d  t|dd < qqddl
m} | j||||||d dS )	a[   Internal implementation to handle special-casing patch events
        on ``ColumnDataSource`` columns.

        Normally any changes to the ``.data`` dict attribute on a
        ``ColumnDataSource`` triggers a notification, causing all of the data
        to be synchronized between server and clients.

        The ``.patch`` method on column data sources exists to provide a
        more efficient way to perform patching (i.e. random access) updates
        to a data source, without having to perform a full synchronization,
        which would needlessly re-send all the data.

        To accomplish this, this function bypasses the wrapped methods on
        ``PropertyValueDict`` and uses the unwrapped versions on the dict
        superclass directly. It then explicitly makes a notification, adding
        a special ``ColumnsPatchedEvent`` hint to the message containing
        only the small patched data that BokehJS needs in order to efficiently
        synchronize.

        .. warning::
            This function assumes the integrity of ``patches`` has already
            been verified.

        r   r   NF)ra   r   )ColumnsPatchedEventr9   )r   rv   rw   intslicetupleshaperx   ZarrayZreshaperk   r~   r   )r   rp   rq   Zpatchesrt   r   nameZpatchZindvaluer   r~   r"   r"   r#   _patch  s    "4zPropertyValueColumnData._patch)NN)N)
r%   r=   r>   r&   rJ   r`   rc   r_   r}   r   r"   r"   r"   r#   r   X  s    2r   )(r&   Z
__future__r   ZloggingZ	getLoggerr%   logra   typingr   r   r   r   r   Znumpyrx   Zutil.dependenciesr	   rn   r
   rk   r   Zmodels.sourcesr   Z	has_propsr   r   typesr   Zdescriptorsr   Zpd__all__r   r   rB   r   rZ   r   r   r"   r"   r"   r#   <module>   s*   2
	!`J