
    -eT                       d Z ddlmZ ddlZ ej        e          ZddlmZm	Z	m
Z
 ddlmZ erd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mZmZ ddlmZmZ ddlmZ ddlm Z m!Z! er(ddl"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/ dZ0 e!e          Z1dZ2	 	 d5d6d%Z3	 	 d7d8d(Z4	 	 	 	 	 	 d9d:d3Z5 G d4 d$          Z6dS );a   Provide a session object to service Bokeh documents in external Python
clients to a Bokeh server.

Use-Cases
~~~~~~~~~

A client session has two primary uses:

* Implementing automated testing infrastructure around Bokeh server
  applications.

* Creating and customizing specific sessions of a Bokeh server application
  (running *in the Bokeh server*) before passing them on to a specific
  viewer.

    )annotationsN)TYPE_CHECKINGAnyLiteral)
quote_plus)IOLoop   )ID)Document)DEFAULT_SERVER_HTTP_URLSessionCoordinates)	NEW_PARAMBrowserLikeBrowserTarget)generate_jwt_tokengenerate_session_id   )ErrorReason)server_url_for_websocket_urlwebsocket_url_for_server_url)DocumentPatchedEventSessionCallbackAddedSessionCallbackRemoved)	UIElement)	patch_doc)
ServerInfoDocumentCallbackGroupClientConnectiondefault)ClientSessionpull_sessionpush_sessionshow_session  @
session_id	ID | Noneurlstrio_loopIOLoop | None	argumentsdict[str, str] | Nonemax_message_sizeintreturnr"   c                    t          | |          }t          | t          |j                  |||          }|                                 |S )a   Create a session by loading the current server-side document.

    ``session.document`` will be a fresh document loaded from
    the server. While the connection to the server is open,
    changes made on the server side will be applied to this
    document, and changes made on the client side will be
    synced to the server.

    If you don't plan to modify ``session.document`` you probably
    don't need to use this function; instead you can directly
    ``show_session()`` or ``server_session()`` without downloading
    the session's document into your process first. It's much
    more efficient to avoid downloading the session if you don't need
    to.

    In a production scenario, the ``session_id`` should be
    unique for each browser tab, which keeps users from
    stomping on each other. It's neither scalable nor secure to
    use predictable session IDs or to share session IDs across
    users.

    For a notebook running on a single machine, ``session_id``
    could be something human-readable such as ``"default"`` for
    convenience.

    If you allow ``pull_session()`` to generate a unique
    ``session_id``, you can obtain the generated ID with the
    ``id`` property on the returned ``ClientSession``.

    Args:
        session_id (string, optional) :
            The name of the session, None to autogenerate a random one (default: None)

        url : (str, optional): The URL to a Bokeh application on a Bokeh server
                can also be `"default"` which will connect to the default app URL

        io_loop (``tornado.ioloop.IOLoop``, optional) :
            The ``IOLoop`` to use for the websocket

        arguments (dict[str, str], optional) :
            A dictionary of key/values to be passed as HTTP request arguments
            to Bokeh application code (default: None)

            Note that should only be provided when pulling new sessions.
            If ``session_id`` is not None, or a session with ``session_id``
            already exists, these arguments will have no effect.

        max_message_size (int, optional) :
            Configure the Tornado max websocket message size.
            (default: 20 MB)

    Returns:
        ClientSession :
            A new ``ClientSession`` connected to the server

    r'   r)   )r'   websocket_urlr+   r-   r/   )r   r"   r   r)   pull)r'   r)   r+   r-   r/   coordssessions          4lib/python3.11/site-packages/bokeh/client/session.pyr#   r#   P   s]    v  :3???F-I&*-U-U_fr{  O_` ` `GLLNNNN    documentr   c                    t          ||          }t          |j        t          |j                  ||          }|                    |            |S )a   Create a session by pushing the given document to the server,
    overwriting any existing server-side document.

    ``session.document`` in the returned session will be your supplied
    document. While the connection to the server is open, changes made on the
    server side will be applied to this document, and changes made on the
    client side will be synced to the server.

    In a production scenario, the ``session_id`` should be unique for each
    browser tab, which keeps users from stomping on each other. It's neither
    scalable nor secure to use predictable session IDs or to share session
    IDs across users.

    For a notebook running on a single machine, ``session_id`` could be
    something human-readable such as ``"default"`` for convenience.

    If you allow ``push_session()`` to generate a unique ``session_id``, you
    can obtain the generated ID with the ``id`` property on the returned
    ``ClientSession``.

    Args:
        document : (bokeh.document.Document)
            The document to be pushed and set as session.document

        session_id : (string, optional)
            The name of the session, None to autogenerate a random one (default: None)

        url : (str, optional): The URL to a Bokeh application on a Bokeh server
            can also be `"default"` which will connect to the default app URL

        io_loop : (tornado.ioloop.IOLoop, optional)
            The IOLoop to use for the websocket

        max_message_size (int, optional) :
            Configure the Tornado max websocket message size.
            (default: 20 MB)

    Returns:
        ClientSession
            A new ClientSession connected to the server

    r3   )r'   r4   r+   r/   )r   r"   r'   r   r)   push)r:   r'   r)   r+   r/   r6   r7   s          r8   r$   r$      sg    X  :3???Fv'8HdekeoHpHp  {B  Ue  f  f  fGLLNr9   tabr7   ClientSession | Nonebrowser
str | Nonenewr   
controllerBrowserLike | NoneNonec                   |!t          |j        j                  }|j        } nt	          | |          }|j        }|j        } |ddlm}  ||          }|                    |dz   t          |           z   t          |                    dS )a   Open a browser displaying a session document.

        If you have a session from ``pull_session()`` or ``push_session`` you
        can ``show_session(session=mysession)``. If you don't need to open a
        connection to the server yourself, you can show a new session in a
        browser by providing just the ``url``.

        Args:
            session_id (string, optional) :
               The name of the session, None to autogenerate a random one (default: None)

            url : (str, optional): The URL to a Bokeh application on a Bokeh server
                can also be `"default"` which will connect to the default app URL

            session (ClientSession, optional) : session to get session ID and server URL from
                If you specify this, you don't need to specify session_id and url

            browser (str, optional) : browser to show with (default: None)
                For systems that support it, the **browser** argument allows
                specifying which browser to display in, e.g. "safari", "firefox",
                "opera", "windows-default" (see the :doc:`webbrowser <python:library/webbrowser>`
                module documentation in the standard lib for more details).

            new (str, optional) : new file output mode (default: "tab")
                For file-based output, opens or raises the browser window
                showing the current output file.  If **new** is 'tab', then
                opens a new tab. If **new** is 'window', then opens a new window.

        Nr3   r   )get_browser_controller)r?   z?bokeh-session-id=)rA   )r   _connectionr)   idr   r'   bokeh.util.browserrF   openr   r   )	r'   r)   r7   r?   rA   rB   
server_urlr6   rF   s	            r8   r%   r%      s    H 5g6I6MNNJ JJ':3GGGFJ*JAAAAAA//@@@J
%99Jz<R<RR%cN 	 	, 	, 	, 	, 	,r9   c                     e Zd ZU dZded<   ded<   ded<   ded	<   d
ed
d
dfdLdZdMdZdNdZe	dOd             Z
e	dPd"            Ze	dQd$            Ze	dRd%            Ze	dRd&            Ze	dSd(            Ze	dTd)            Ze	dRd*            ZdUd+ZdVdWd.ZdUd/ZdUd0ZdUd1ZdXdYd3ZdZd5Z	 	 d[d\d=Zd]d>Zd^dAZed_dB            Zd`dEZdUdFZdUdGZ dadIZ!dbdKZ"d
S )cr"   a[   Represents a websocket connection to a server-side session.

    Each server session stores a Document, which is kept in sync with the
    corresponding Document for this ``ClientSession`` instance. Updates on
    either side of the connection will automatically propagate to the other
    side, as long as the connection is open.

    ClientSession objects can (and usually should) be used as a context manager
    so that the session is properly closed:

    .. code-block:: python

        with pull_session(url=app_url) as mysession:
            # customize session here
            script = server_session(session_id=mysession.id, url=app_url)
            return render_template("embed.html", script=script, template="Flask")

    If you do not use ``ClientSession`` in this way, it is up to you to ensure
    that ``mysession.close()`` is called.

    Document | None	_documentr
   _idr    rG   r   
_callbacksNr&   r'   r(   r4   r*   r+   r,   r-   r.   r/   r0   c                    d| _         |                     |          | _        ddlm}  || ||||          | _        ddlm}  || j        j                  | _	        dS )aJ   A connection which attaches to a particular named session on the
        server.

        Always call either pull() or push() immediately after creating the
        session (until these are called ``session.document`` will be ``None``).

        The :func:`~bokeh.client.session.push_session` and
        :func:`~bokeh.client.session.pull_session()` functions will construct a
        ``ClientSession`` and push or pull in one step, so they are a good way to
        obtain a ``ClientSession``.

        Args:
            session_id (str) :
                The name of the session or None to generate one

            websocket_url (str) :
                Websocket URL to connect to

            io_loop (IOLoop, optional) :
                The IOLoop to use for the websocket

            arguments (dict[str, str], optional) :
                A dictionary of key/values to be passed as HTTP request
                arguments to Bokeh application code (default: None)

                Note that should only be provided when pulling new sessions.
                If ``session_id`` is not None, or a session with ``session_id``
                already exists, these arguments will have no effect.

            max_message_size (int, optional) :
                Configure the Tornado max websocket message size.
                (default: 20 MB)

        Nr   r   )r7   r+   r4   r-   r/   r	   r   )
rN   _ensure_session_idrO   
connectionr    rG   server.callbacksr   r+   rP   )selfr'   r4   r+   r-   r/   r    r   s           r8   __init__zClientSession.__init__  s    H **:66000000++D'Yfr{  O_  `  `  `<<<<<<//0@0HIIr9   r1   c                    | S )


         rU   s    r8   	__enter__zClientSession.__enter__>  s	     r9   exc_typer   	exc_valueexc_tracebackrD   c                .    |                                   dS )rX   N)close)rU   r\   r]   r^   s       r8   __exit__zClientSession.__exit__D  s     	

r9   boolc                    | j         j        S )z. Whether this session is currently connected. )rG   	connectedrZ   s    r8   rd   zClientSession.connectedL  s     ))r9   ErrorReason | Nonec                    | j         j        S N)rG   error_reasonrZ   s    r8   rh   zClientSession.error_reasonQ      ,,r9   
int | Nonec                    | j         j        S rg   )rG   
error_coderZ   s    r8   rl   zClientSession.error_codeU  s    **r9   c                    | j         j        S rg   )rG   error_detailrZ   s    r8   rn   zClientSession.error_detailY  ri   r9   c                    | j         j        S rg   )rG   r)   rZ   s    r8   r)   zClientSession.url]  s    ##r9   r   c                    | j         S )z A |Document| that will be kept in sync with the corresponding
        ``Document`` on the server.

        This value is initialized when :func:`pull` or :func:`push` succeeds.
        It will be ``None`` until then.

        )rN   rZ   s    r8   r:   zClientSession.documenta  s     ~r9   c                    | j         S )z A unique ID for this session. )rO   rZ   s    r8   rH   zClientSession.idl  s     xr9   c                *    t          | j                  S )z* A JWT token to authenticate the session. )r   rH   rZ   s    r8   tokenzClientSession.tokenq  s     "$'***r9   c                8    | j                                          dS )z2 Connect to a Bokeh server at the configured URL. N)rG   connectrZ   s    r8   ru   zClientSession.connectx  s      """""r9   closedwhyc                :    | j                             |           dS )z% Close the connection to the server. N)rG   r`   )rU   rw   s     r8   r`   zClientSession.close|  s    s#####r9   c                8    | j                                          dS )a   Force a round-trip request/reply to the server, sometimes needed to
        avoid race conditions. Mostly useful for testing.

        Outside of test suites, this method hurts performance and should not be
        needed.

        Returns:
           None

        N)rG   force_roundtriprZ   s    r8   rz   zClientSession.force_roundtrip  s     	((*****r9   c                    | j         sc| j        t          j        u rA| j        dk    rt          d| j                   t          d| j         d| j                   t          d          dS )z Raises an error, when the connection could not have been
        established.

        Should be used, after a call to connect.

        Returns:
            None

        i  z:Check your application path! The given Path is not valid: z9We received an HTTP-Error. Disconnected with error code: z, given message: zWWe failed to connect to the server (to start the server, try the 'bokeh serve' command)N)rd   rh   r   
HTTP_ERRORrl   OSErrorr)   rn   rZ   s    r8   check_connection_errorsz%ClientSession.check_connection_errors  s     ~ 	u K$:::?c))!"i_c_g"i"ijjj  PZ^Zi  P  P  }A  }N  P  P  Q  Q  Qsttt	u 	ur9   c                    |                                   |                                  | j        t                      }n| j        }| j                            |           | j        |                     |           dS dS )a
   Pull the server's state and set it as session.document.

        If this is called more than once, session.document will be the same
        object instance but its contents will be overwritten.

        Automatically calls :func:`connect` before pulling.

        N)ru   r~   r:   r   rG   pull_doc_attach_document)rU   docs     r8   r5   zClientSession.pull  s~     	$$&&&= **CC-C!!#&&&= !!#&&&&& ! r9   r:   c                .   | j         |t                      }n|}n|| j         }nt          d          |                                  |                                  | j                            |           | j        |                     |           dS dS )a   Push the given document to the server and record it as ``session.document``.

        If this is called more than once, the Document has to be the same (or None
        to mean ``session.document``).

        .. note::
            Automatically calls :func:`~connect` before pushing.

        Args:
            document (|Document|, optional) :
                The document that will be kept in sync with the server document.
                None to use ``session.document`` or create a new document.

        NzACannot push() a different document from existing session.document)	r:   r   
ValueErrorru   r~   rG   push_docrN   r   )rU   r:   r   s      r8   r<   zClientSession.push  s     = jjm !deee$$&&&!!#&&&>!!!#&&&&& "!r9   r   c                4    | j                                         S )zq Ask for information about the server.

        Returns:
            A dictionary of server attributes.

        )rG   request_server_inforZ   s    r8   r   z!ClientSession.request_server_info  s     33555r9   r=   objUIElement | Noner?   r@   rA   Literal['tab', 'window']c                ~    |r(|| j         j        vr| j                             |           t          | ||           dS )a   Open a browser displaying this session.

        Args:
            obj (UIElement object, optional) : a Layout (Row/Column),
                Plot or Widget object to display. The object will be added
                to the session's document.

            browser (str, optional) : browser to show with (default: None)
                For systems that support it, the **browser** argument allows
                specifying which browser to display in, e.g. "safari", "firefox",
                "opera", "windows-default" (see the :doc:`webbrowser <python:library/webbrowser>`
                module documentation in the standard lib for more details).

            new (str, optional) : new file output mode (default: "tab")
                For file-based output, opens or raises the browser window
                showing the current output file.  If **new** is 'tab', then
                opens a new tab. If **new** is 'window', then opens a new window.

        )r7   r?   rA   N)r:   rootsadd_rootr%   )rU   r   r?   rA   s       r8   showzClientSession.show  sL    *  	(3dm111M""3'''T7<<<<<<r9   c                    || _         | j         j                            |            | j                            | j         j                   d S rg   )rN   	callbackson_change_dispatch_torP   add_session_callbackssession_callbacks)rU   r:   s     r8   r   zClientSession._attach_document  sC    ! 66t<<<--dn.NOOOOOr9   eventr   c                    |j         | u rt                              d           d S | j                            | j        |           d S )NzANot sending notification back to server for a change it requested)setterlogdebugrG   _send_patch_documentrO   rU   r   s     r8   _document_patchedzClientSession._document_patched  sJ    <4IIYZZZF 	--dh>>>>>r9   c                &    |t                      }|S rg   )r   )clsr'   s     r8   rR   z ClientSession._ensure_session_id  s    ,..Jr9   messager   c                <    |                     | j        |            d S rg   )apply_to_documentr:   )rU   r   s     r8   _handle_patchzClientSession._handle_patch  s     !!$-66666r9   c                8    | j                                          dS )z Execute a blocking loop that runs and executes event callbacks
        until the connection is closed (e.g. by hitting Ctrl-C).

        This function is intended to facilitate testing ONLY.

        N)rG   loop_until_closedrZ   s    r8   _loop_until_closedz ClientSession._loop_until_closed  s     	**,,,,,r9   c                ~    | j         5| j                             |            | j                                         dS dS )zR Called by the ClientConnection we are using to notify us of disconnect.

        N)r:   remove_on_changerP   remove_all_callbacksrZ   s    r8   _notify_disconnectedz"ClientSession._notify_disconnected  sD     =$M**4000O0022222 %$r9   r   c                D    | j                             |j                   d S rg   )rP   add_session_callbackcallbackr   s     r8   _session_callback_addedz%ClientSession._session_callback_added!  s     ,,U^<<<<<r9   r   c                D    | j                             |j                   d S rg   )rP   remove_session_callbackr   r   s     r8   _session_callback_removedz'ClientSession._session_callback_removed$  s     //?????r9   )
r'   r(   r4   r*   r+   r,   r-   r.   r/   r0   )r1   r"   )r\   r   r]   r   r^   r   r1   rD   )r1   rb   )r1   re   )r1   rj   )r1   r*   )r1   r   )r1   r
   )r1   rD   )rv   )rw   r*   r1   rD   rg   )r:   rM   r1   rD   )r1   r   )NNr=   )r   r   r?   r@   rA   r   r1   rD   )r:   r   r1   rD   )r   r   r1   rD   )r'   r(   r1   r
   )r   r   r1   rD   )r   r   r1   rD   )r   r   r1   rD   )#__name__
__module____qualname____doc____annotations__DEFAULT_SERVER_WEBSOCKET_URLrV   r[   ra   propertyrd   rh   rl   rn   r)   r:   rH   rs   ru   r`   rz   r~   r5   r<   r   r   r   r   classmethodrR   r   r   r   r   r   rY   r9   r8   r"   r"      s         , GGG!!!!%%%%/3Jf%)dlx+J +J +J +J +JZ       * * * X* - - - X- + + + X+ - - - X- $ $ $ X$    X    X + + + X+# # # #$ $ $ $ $+ + + +u u u u"' ' ' '(' ' ' ' '@6 6 6 6 HL,1= = = = =6P P P P	? 	? 	? 	?    [
7 7 7 7- - - -3 3 3 3= = = =@ @ @ @ @ @r9   )Nr!   NNr&   )r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r"   )Nr!   Nr&   )r:   r   r'   r(   r)   r*   r+   r,   r/   r0   r1   r"   )Nr!   NNr=   N)r'   r(   r)   r*   r7   r>   r?   r@   rA   r   rB   rC   r1   rD   )7r   
__future__r   logging	getLoggerr   r   typingr   r   r   urllib.parser   tornado.ioloopr   
core.typesr
   r:   r   	resourcesr   r   util.browserr   r   r   
util.tokenr   r   statesr   utilr   r   document.eventsr   r   r   	models.uir   protocol.messages.patch_docr   #protocol.messages.server_info_replyr   rT   r   rS   r    DEFAULT_SESSION_IDr   __all__r#   r$   r%   r"   rY   r9   r8   <module>r      s   ( # " " " " " g!! / . . . . . . . . . # # # # # #  &%%%%%%             C C C C C C C C @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @       L L L L L L L L -dddddddddd%%%%%%777777@@@@@@888888,,,,,,  ;;<STT  _cIU? ? ? ? ?B OX?K/ / / / /d %) ,0"&!&-11, 1, 1, 1, 1,fp@ p@ p@ p@ p@ p@ p@ p@ p@ p@r9   