U
    ARdpf                     @  s  U d dl mZ d dlZd dlZd dlZd dlZd dlmZmZ d dl	m
Z
 d dlmZ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 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# 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l0m1Z1 d dl2m3Z3 d dl4m5Z5m6Z6m7Z7m8Z8m9Z9 d dl:m;Z;m<Z< d dl=m>Z> d dl?m@Z@ d dlAmBZB d dlCmDZD erd dlEmFZF dZGdeHd< eeIZJdeHd< G d d! d!eKZLed"d#G d$d% d%ZMG d&d' d'e
ZNG d(d) d)eZOG d*d+ d+ZPdS ),    )annotationsN)	dataclassfield)Enum)TYPE_CHECKING	AwaitableDict
NamedTupleOptionalTupleType)Finalconfig)
get_logger)BackMsg)
ForwardMsg)
AppSession)get_data_cache_stats_provider!get_resource_cache_stats_provider)LocalDiskCacheStorageManager)ForwardMsgCachecreate_reference_msgpopulate_hash_if_needed)_mem_caches)MediaFileManager)MediaFileStorage)MemorySessionStorage)is_cacheable_msg)
ScriptData)ActiveSessionInfoSessionClientSessionClientDisconnectedErrorSessionManagerSessionStorage)SCRIPT_RUN_WITHOUT_ERRORS_KEYSessionStateStatProvider)StatsManager)UploadedFileManager)WebsocketSessionManager)LocalSourcesWatcher)CacheStorageManager<   r   SCRIPT_RUN_CHECK_TIMEOUTLOGGERc                   @  s   e Zd ZdZdS )RuntimeStoppedErrorz;Raised by operations on a Runtime instance that is stopped.N)__name__
__module____qualname____doc__ r4   r4   =/tmp/pip-unpacked-wheel-b9et7o5g/streamlit/runtime/runtime.pyr/   K   s   r/   T)frozenc                   @  sZ   e Zd ZU dZded< ded< ded< eedZd	ed
< eZ	ded< ee
dZded< dS )RuntimeConfigz$Config options for StreamlitRuntime.strscript_pathOptional[str]command_liner   media_file_storage)default_factoryr+   cache_storage_managerzType[SessionManager]session_manager_classr$   session_storageN)r0   r1   r2   r3   __annotations__r   r   r>   r)   r?   r   r@   r4   r4   r4   r5   r7   O   s   
r7   c                   @  s    e Zd ZdZdZdZdZdZdS )RuntimeStateINITIALNO_SESSIONS_CONNECTEDONE_OR_MORE_SESSIONS_CONNECTEDSTOPPINGSTOPPEDN)r0   r1   r2   rC   rD   rE   rF   rG   r4   r4   r4   r5   rB   i   s
   rB   c                   @  sB   e Zd ZU dZded< ded< ded< ded< ded	< ded
< dS )AsyncObjectszContainer for all asyncio objects that Runtime manages.
    These cannot be initialized until the Runtime's eventloop is assigned.
    zasyncio.AbstractEventLoop	eventloopzasyncio.Event	must_stophas_connectionneed_send_datazasyncio.Future[None]startedstoppedN)r0   r1   r2   r3   rA   r4   r4   r4   r5   rH   q   s   
rH   c                   @  s   e Zd ZU dZded< ed dddZedddd	Zd
dddZe	ddddZ
e	ddddZe	ddddZe	ddddZe	ddddZe	ddddZe	d dd!d"Zd#d$d%d&d'Zd#d(d%d)d*Zd(dd+d,Zd(dd-d.Zd#dd%d/d0Zd[d1d2d3d#d4d5d6Zd\d1d2d3d#d4d7d8Zd#d(d%d9d:Zd#d(d%d;d<Zd#d=d(d>d?d@Zd#dAd(dBdCdDZe	dEddFdGZdEddHdIZdd(dJdKdLZd(ddMdNZdOdPd(dQdRdSZ d(ddTdUZ!dVddWdXZ"d(ddYdZZ#dS )]RuntimeNzOptional[Runtime]	_instance)returnc                 C  s   | j dkrtd| j S )znReturn the singleton Runtime instance. Raise an Error if the
        Runtime hasn't been created yet.
        NzRuntime hasn't been created!)rP   RuntimeErrorclsr4   r4   r5   instance   s    
zRuntime.instanceboolc                 C  s
   | j dk	S )a2  True if the singleton Runtime instance has been created.

        When a Streamlit app is running in "raw mode" - that is, when the
        app is run via `python app.py` instead of `streamlit run app.py` -
        the Runtime will not exist, and various Streamlit functions need
        to adapt.
        N)rP   rS   r4   r4   r5   exists   s    	zRuntime.existsr7   r   c                 C  s   t jdk	rtd| t _d| _d| _|j| _|jp4d| _t	j
| _t | _t | _| jj| j t|jd| _|j| _|j|j| j| jd| _t | _| jt  | jt   | jt! | j| j | j| j | jt"| j dS )a   Create a Runtime instance. It won't be started yet.

        Runtime is *not* thread-safe. Its public methods are generally
        safe to call only on the same thread that its event loop runs on.

        Parameters
        ----------
        config
            Config options.
        Nz Runtime instance already exists! )Zstorage)r@   uploaded_file_managermessage_enqueued_callback)#rO   rP   rR   _async_objs_loop_coroutine_taskr9   _main_script_pathr;   _command_linerB   rC   _stater   _message_cacher(   _uploaded_file_mgrZon_files_updatedconnect_on_files_updatedr   r<   _media_file_mgrr>   _cache_storage_managerr?   r@   _enqueued_some_message_session_mgrr'   
_stats_mgrZregister_providerr   r   r   r&   )selfr   r4   r4   r5   __init__   s2    
zRuntime.__init__rB   c                 C  s   | j S N)r_   ri   r4   r4   r5   state   s    zRuntime.stater   c                 C  s   | j S rk   )r`   rl   r4   r4   r5   message_cache   s    zRuntime.message_cacher(   c                 C  s   | j S rk   )ra   rl   r4   r4   r5   uploaded_file_mgr   s    zRuntime.uploaded_file_mgrr+   c                 C  s   | j S rk   )re   rl   r4   r4   r5   r>      s    zRuntime.cache_storage_managerr   c                 C  s   | j S rk   )rd   rl   r4   r4   r5   media_file_mgr   s    zRuntime.media_file_mgrr'   c                 C  s   | j S rk   )rh   rl   r4   r4   r5   	stats_mgr   s    zRuntime.stats_mgrzAwaitable[None]c                 C  s
   |   jS )z?A Future that completes when the Runtime's run loop has exited.)_get_async_objsrN   rl   r4   r4   r5   rN      s    zRuntime.stoppedr8   zOptional[SessionClient])
session_idrQ   c                 C  s   | j |}|dkrdS |jS )zGet the SessionClient for the given session_id, or None
        if no such session exists.

        Notes
        -----
        Threading: SAFE. May be called on any thread.
        N)rg   get_active_session_infoclient)ri   rs   session_infor4   r4   r5   
get_client   s    zRuntime.get_clientNonec                 C  s   | j |s| j| dS )zEvent handler for UploadedFileManager.on_file_added.
        Ensures that uploaded files from stale sessions get deleted.

        Notes
        -----
        Threading: SAFE. May be called on any thread.
        N)rg   is_active_sessionra   Zremove_session_filesri   rs   r4   r4   r5   rc      s    zRuntime._on_files_updatedc                   sr   t t t t t t t d}|| _tjdkrRtj| 	 dd| _
nt| 	 | _
|jI dH  dS )a  Start the runtime. This must be called only once, before
        any other functions are called.

        When this coroutine returns, Streamlit is ready to accept new sessions.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        )rI   rJ   rK   rL   rM   rN   )      r   zRuntime.loop_coroutine)nameN)rH   asyncioZget_running_loopEventZFuturer[   sysversion_infocreate_task_loop_coroutiner\   rM   ri   
async_objsr4   r4   r5   start  s     
 
zRuntime.startc                   s&       fdd} j| dS )zRequest that Streamlit close all sessions and stop running.
        Note that Streamlit won't stop running immediately.

        Notes
        -----
        Threading: SAFE. May be called from any thread.
        c                     s:   j tjtjfkrd S td tj  j  d S )NzRuntime stopping...)	r_   rB   rF   rG   r.   debug
_set_staterJ   setr4   r   ri   r4   r5   stop_on_eventloop:  s
    
z'Runtime.stop.<locals>.stop_on_eventloopN)rr   rI   call_soon_threadsafe)ri   r   r4   r   r5   stop/  s    	zRuntime.stopc                 C  s   | j |S )zTrue if the session_id belongs to an active session.

        Notes
        -----
        Threading: SAFE. May be called on any thread.
        )rg   ry   rz   r4   r4   r5   ry   D  s    zRuntime.is_active_sessionr!   zDict[str, Optional[str]]r:   )ru   	user_infoexisting_session_idrQ   c                 C  sd   | j tjtjfkr$td| j  d| jj|t| j| j	p:d||d}| 
tj |  j  |S )a  Create a new session (or connect to an existing one) and return its unique ID.

        Parameters
        ----------
        client
            A concrete SessionClient implementation for communicating with
            the session's client.
        user_info
            A dict that contains information about the session's user. For now,
            it only (optionally) contains the user's email address.

            {
                "email": "example@example.com"
            }

        Returns
        -------
        str
            The session's unique string ID.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        zCan't connect_session (state=)rX   )ru   script_datar   r   )r_   rB   rF   rG   r/   rg   connect_sessionr   r]   r^   r   rE   rr   rK   r   )ri   ru   r   r   rs   r4   r4   r5   r   M  s    zRuntime.connect_sessionc                 C  s   t d | j|||dS )zCreate a new session (or connect to an existing one) and return its unique ID.

        Notes
        -----
        This method is simply an alias for connect_session added for backwards
        compatibility.
        z:create_session is deprecated! Use connect_session instead.)ru   r   r   )r.   warningr   )ri   ru   r   r   r4   r4   r5   create_sessiony  s    
  zRuntime.create_sessionc                 C  s   | j | |   dS )a9  Close and completely shut down a session.

        This differs from disconnect_session in that it always completely shuts down a
        session, permanently losing any associated state (session state, uploaded files,
        etc.).

        This function may be called multiple times for the same session,
        which is not an error. (Subsequent calls just no-op.)

        Parameters
        ----------
        session_id
            The session's unique ID.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        N)rg   close_session_on_session_disconnectedrz   r4   r4   r5   r     s    zRuntime.close_sessionc                 C  s   | j | |   dS )aZ  Disconnect a session. It will stop producing ForwardMsgs.

        Differs from close_session because disconnected sessions can be reconnected to
        for a brief window (depending on the SessionManager/SessionStorage
        implementations used by the runtime).

        This function may be called multiple times for the same session,
        which is not an error. (Subsequent calls just no-op.)

        Parameters
        ----------
        session_id
            The session's unique ID.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        N)rg   disconnect_sessionr   rz   r4   r4   r5   r     s    zRuntime.disconnect_sessionr   )rs   msgrQ   c                 C  sX   | j tjtjfkr$td| j  d| j|}|dkrHtd| dS |j	
| dS )a+  Send a BackMsg to an active session.

        Parameters
        ----------
        session_id
            The session's unique ID.
        msg
            The BackMsg to deliver to the session.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        zCan't handle_backmsg (state=r   Nz3Discarding BackMsg for disconnected session (id=%s))r_   rB   rF   rG   r/   rg   rt   r.   r   sessionhandle_backmsg)ri   rs   r   rv   r4   r4   r5   r     s     zRuntime.handle_backmsgBaseException)rs   excrQ   c                 C  sX   | j tjtjfkr$td| j  d| j|}|dkrHtd| dS |j	
| dS )a.  Handle an Exception raised during deserialization of a BackMsg.

        Parameters
        ----------
        session_id
            The session's unique ID.
        exc
            The Exception.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        z6Can't handle_backmsg_deserialization_exception (state=r   Nz=Discarding BackMsg Exception for disconnected session (id=%s))r_   rB   rF   rG   r/   rg   rt   r.   r   r   Zhandle_backmsg_exception)ri   rs   r   rv   r4   r4   r5   (handle_backmsg_deserialization_exception  s    z0Runtime.handle_backmsg_deserialization_exceptionzTuple[bool, str]c                   s   | j tjtjtjfkrdS dS )N)Tok)Funavailable)r_   rB   rC   rF   rG   rl   r4   r4   r5   is_ready_for_browser_connection  s    z'Runtime.is_ready_for_browser_connectionc                   s   t t| j| j| j| jt| jddid}zr|d t	
 }t|jkrjt	
 | tk rjtdI dH  q>t|jkr|W &dS |jt }|rdnd}||fW S |  X dS )	aJ  Load and execute the app's script to verify it runs without an error.

        Returns
        -------
        (True, "ok") if the script completes without error, or (False, err_msg)
        if the script raises an exception.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        emailztest@test.com)r   rY   rZ   Zlocal_sources_watcherr   Ng?)Ftimeoutr   error)r   r   r]   r^   ra   rf   r*   shutdownZrequest_reruntimeperf_counterr%   Zsession_stater-   r~   sleep)ri   r   nowr   r   r4   r4   r5   does_script_run_without_error  s*    


z%Runtime.does_script_run_without_error)	new_staterQ   c                 C  s   t d| j| || _d S )NzRuntime state: %s -> %s)r.   r   r_   )ri   r   r4   r4   r5   r   &  s    zRuntime._set_statec              
     s  |   }z| jtjkr&| tj n| jtjkr4ntd| j |j	d |j
 sj| jtjkrtjt|j
 t|j ftjdI dH  n| jtjkrj|j  | j D ]`}|j }|D ]L}z| || W n& tk
r
   | j|jj Y nX tdI dH  qqtdI dH  nqjtjt|j
 t|j ftjdI dH  qP| j D ]}| j|jj qt| tj |j	d W nB t k
r } z"|j!| t"#  t$%d W 5 d}~X Y nX dS )zThe main Runtime loop.

        This function won't exit until `stop` is called.

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        zBad Runtime state at start: N)Zreturn_whenr   g{Gz?zJ
Please report this bug at https://github.com/streamlit/streamlit/issues.
)&rr   r_   rB   rC   r   rD   rE   rR   rM   Z
set_resultrJ   is_setr~   waitr   rK   ZFIRST_COMPLETEDrL   clearrg   Zlist_active_sessionsr   Zflush_browser_queue_send_messager"   r   idr   Zlist_sessionsr   rG   rN   	ExceptionZset_exception	traceback	print_excr.   info)ri   r   Zactive_session_infoZmsg_listr   rv   er4   r4   r5   r   *  s\    



	zRuntime._loop_coroutiner    r   )rv   r   rQ   c                 C  s   t ||j_|}|jjrlt| | j||j|jrJt	d|j
 t|}t	d|j
 | j||j|j |ddkr|jtjkrt	dtd | jd7  _| j|j|j |j| dS )	a  Send a message to a client.

        If the client is likely to have already cached the message, we may
        instead send a "reference" message that contains only the hash of the
        message.

        Parameters
        ----------
        session_info : ActiveSessionInfo
            The ActiveSessionInfo associated with websocket
        msg : ForwardMsg
            The message to send to the client

        Notes
        -----
        Threading: UNSAFE. Must be called on the eventloop thread.
        z$Sending cached message ref (hash=%s)zCaching message (hash=%s)typescript_finishedzYScript run finished successfully; removing expired entries from MessageCache (max_age=%s)zglobal.maxCachedMessageAge   N)r   metadata	cacheabler   r`   Zhas_message_referencer   Zscript_run_countr.   r   hashr   Zadd_messageZ
WhichOneofr   r   ZFINISHED_SUCCESSFULLYr   
get_optionZremove_expired_session_entriesru   Zwrite_forward_msg)ri   rv   r   Zmsg_to_sendr4   r4   r5   r   ~  s>        
 zRuntime._send_messagec                 C  s   |   }|j|jj dS )a  Callback called by AppSession after the AppSession has enqueued a
        message. Sets the "needs_send_data" event, which causes our core
        loop to wake up and flush client message queues.

        Notes
        -----
        Threading: SAFE. May be called on any thread.
        N)rr   rI   r   rL   r   r   r4   r4   r5   rf     s    	zRuntime._enqueued_some_messagerH   c                 C  s   | j dkrtd| j S )zpReturn our AsyncObjects instance. If the Runtime hasn't been
        started, this will raise an error.
        NzRuntime hasn't started yet!)r[   rR   rl   r4   r4   r5   rr     s    
zRuntime._get_async_objsc                 C  s8   | j tjkr4| j dkr4|  j  | tj	 dS )zlSet the runtime state to NO_SESSIONS_CONNECTED if the last active
        session was disconnected.
        r   N)
r_   rB   rE   rg   Znum_active_sessionsrr   rK   r   r   rD   rl   r4   r4   r5   r     s    
z Runtime._on_session_disconnected)N)N)$r0   r1   r2   rP   rA   classmethodrU   rW   rj   propertyrm   rn   ro   r>   rp   rq   rN   rw   rc   r   r   ry   r   r   r   r   r   r   r   r   r   r   r   rf   rr   r   r4   r4   r4   r5   rO      sT   

0
" 0 
+T;rO   )Q
__future__r   r~   r   r   r   Zdataclassesr   r   enumr   typingr   r   r   r	   r
   r   r   Ztyping_extensionsr   Z	streamlitr   Zstreamlit.loggerr   Zstreamlit.proto.BackMsg_pb2r   Zstreamlit.proto.ForwardMsg_pb2r   Zstreamlit.runtime.app_sessionr   Zstreamlit.runtime.cachingr   r   Z:streamlit.runtime.caching.storage.local_disk_cache_storager   Z#streamlit.runtime.forward_msg_cacher   r   r   Z(streamlit.runtime.legacy_caching.cachingr   Z$streamlit.runtime.media_file_managerr   Z$streamlit.runtime.media_file_storager   Z(streamlit.runtime.memory_session_storager   Zstreamlit.runtime.runtime_utilr   Zstreamlit.runtime.script_datar   Z!streamlit.runtime.session_managerr    r!   r"   r#   r$   Zstreamlit.runtime.stater%   r&   Zstreamlit.runtime.statsr'   Z'streamlit.runtime.uploaded_file_managerr(   Z+streamlit.runtime.websocket_session_managerr)   Zstreamlit.watcherr*   Z!streamlit.runtime.caching.storager+   r-   rA   r0   r.   r   r/   r7   rB   rH   rO   r4   r4   r4   r5   <module>   sN    $