o
    沪g                     @  s   d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZ ddlmZ dZd	Zdd
dd-ddZd.d/ddZd0ddZd1ddZd1dd Ze
d!Zd2d'd(Zd)d* ZG d+d, d,eZdS )3zA bunch of useful utilities for the watcher.

These are functions that only make sense within the watcher. In particular,
functions that use streamlit.config can go here to avoid a dependency cycle.
    )annotationsN)Path)CallableTypeVar)Error)HASHLIB_KWARGS   g?F)glob_patternallow_nonexistentpathstrr	   
str | Noner
   boolreturnc                  sx   |rt j s d}nt j r!|pd}t |d}n
t fddt }tj	di t
}|| | S )a{  Calculate the MD5 checksum of a given path.

    For a file, this means calculating the md5 of the file's contents. For a
    directory, we concatenate the directory's path with the names of all the
    files in it and calculate the md5 of that.

    IMPORTANT: This method calls time.sleep(), which blocks execution. So you
    should only use this outside the main thread.
    zUTF-8*c                     s   t  S N)_get_file_content r   r   R/var/www/html/chatdoc2/venv/lib/python3.10/site-packages/streamlit/watcher/util.py<lambda>A   s    z0calc_md5_with_blocking_retries.<locals>.<lambda>Nr   )osr   existsencodeisdir_stable_dir_identifier_do_with_retriesFileNotFoundErrorhashlibmd5r   update	hexdigest)r   r	   r
   contentr   r   r   r   calc_md5_with_blocking_retries'   s   

r#   floatc                   s(   |r
t j s
dS t fddt S )a  Return the modification time of a path (file or directory).

    If allow_nonexistent is True and the path does not exist, we return 0.0 to
    guarantee that any file/dir later created at the path has a later
    modification time than the last time returned by this function for that
    path.

    If allow_nonexistent is False and no file/dir exists at the path, a
    FileNotFoundError is raised (by os.stat).

    For any path that does correspond to an existing file/dir, we return its
    modification time.
    g        c                     s   t  jS r   )r   statst_mtimer   r   r   r   r   a   s    z(path_modification_time.<locals>.<lambda>)r   r   r   r   r   )r   r
   r   r   r   path_modification_timeM   s   
r'   	file_pathbytesc                 C  s6   t | d}| W  d    S 1 sw   Y  d S )Nrb)openread)r(   fr   r   r   r   g   s   $r   dir_pathc                 C  s*   t | }tdd ||D }d|S )Nc                 S  s   g | ]}|j d s|j qS ).)name
startswith).0r-   r   r   r   
<listcomp>o   s    z_dirfiles.<locals>.<listcomp>+)r   sortedglobjoin)r.   r	   p	filenamesr   r   r   	_dirfilesl   s
   
r:   c                 C  s>   t | |}t D ]}t | |}||kr n|}q|  d| S )ab  Wait for the files in a directory to look stable-ish before returning an id.

    We do this to deal with problems that would otherwise arise from many tools
    (e.g. git) and editors (e.g. vim) "editing" files (from the user's
    perspective) by doing some combination of deleting, creating, and moving
    various files under the hood.

    Because of this, we're unable to rely on FileSystemEvents that we receive
    from watchdog to determine when a file has been added to or removed from a
    directory.

    This is a bit of an unfortunate situation, but the approach we take here is
    most likely fine as:
      - The worst thing that can happen taking this approach is a false
        positive page added/removed notification, which isn't too disastrous
        and can just be ignored.
      - It is impossible (that is, I'm fairly certain that the problem is
        undecidable) to know whether a file created/deleted/moved event
        corresponds to a legitimate file creation/deletion/move or is part of
        some sequence of events that results in what the user sees as a file
        "edit".
    r4   )r:   _retry_dance)r.   r	   dirfiles_new_dirfilesr   r   r   r   t   s   


r   Torig_fnCallable[[], T]	exceptiontype[Exception]
str | Pathc              	   C  sH   t  D ]}z|  W   S  |y   |td kr 	 Y qw td| )a  Helper for retrying a function.

    Calls `orig_fn`. If `exception` is raised, retry.

    To use this, just replace things like this...

        result = thing_to_do(file_path, a, b, c)

    ...with this:

        result = _do_with_retries(
            lambda: thing_to_do(file_path, a, b, c),
            exception: ExceptionThatWillCauseARetry,
            file_path, # For pretty error message.
        )
       z!Unable to access file or folder: )r;   _MAX_RETRIESMaxRetriesError)r@   rB   r   ir   r   r   r      s   
r   c                  c  s$    t tD ]
} | V  tt qdS )a  Helper for writing a retry loop.

    This is useful to make sure all our retry loops work the same way. For example,
    prior to this helper, some loops had time.sleep() *before the first try*, which just
    slowed things down for no reason.

    Usage:

    for i in _retry_dance():
        # Do the thing you want to retry automatically.
        the_thing_worked = do_thing()

        # Don't forget to include a break/return when the thing you're trying to do
        # works.
        if the_thing_worked:
            break
    N)rangerF   timesleep_RETRY_WAIT_SECS)rH   r   r   r   r;      s
   r;   c                   @  s   e Zd ZdS )rG   N)__name__
__module____qualname__r   r   r   r   rG      s    rG   )r   r   r	   r   r
   r   r   r   )F)r   r   r
   r   r   r$   )r(   r   r   r)   )r.   r   r	   r   r   r   )r@   rA   rB   rC   r   rD   r   r?   )__doc__
__future__r   r   r   rJ   pathlibr   typingr   r   streamlit.errorsr   streamlit.utilr   rF   rL   r#   r'   r   r:   r   r?   r   r;   rG   r   r   r   r   <module>   s,   &


#
"