L i dZddlmZddlZddlZddlmZddlmZm Z ddl m Z ddl m Z erddlmZmZd Zd Zdd d  dd ZdddZddZddZddZe dZ ddZddZy)zA 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) TYPE_CHECKINGTypeVar)StreamlitMaxRetriesError)calc_md5)Callable Generatorg?F) glob_patternallow_nonexistentc^|r;tjjsjd}t|Stjj r,|xsd}t |jd}t|St fdttf}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. zUTF-8*ctSN)_get_file_contentpaths\/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/streamlit/watcher/util.pyz0calc_md5_with_blocking_retries..Cs %d+) osrexistsencodeisdir_stable_dir_identifier_do_with_retriesFileNotFoundErrorPermissionErrorr)rr r contents` rcalc_md5_with_blocking_retriesr!)s !5++g& G  t #*s (|<CCGL G  # +  0   G rc||r tjjsytfdtt fS)aReturn 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. gcBtjjSr)rstatst_mtimersrrz(path_modification_time.._s &&r)rrrrrr)rr s` rpath_modification_timer&Ks7!5 & O,  rcft|d5}|jcdddS#1swYyxYw)Nrb)openread) file_pathfs rrres, i !vvxs'0ct|}t|j|Dcgc]*}|jj dr|j,c}}dj |Scc}w)N.+)rsortedglobname startswithjoin)dir_pathr pr, filenamess r _dirfilesr8jsX XA -LAQVV5F5Fs5KLI 88I  Ms A+A+cpt||}tD]}t||}||k(rn|}|d|S)abWait 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". r/)r8 _retry_dance)r5r dirfiles_ new_dirfiless rrrrsP.<0H ^  <8 | #   Zq ##rTctD] } |cStd|#|$r%}|tdz k\rtd||Yd}~Ad}~wwxYw)aHelper for retrying a function. Calls `orig_fn`. If any exception in `exceptions` 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), exceptions=(ExceptionType1, ExceptionType2), file_path, # For pretty error message. ) z!Unable to access file or folder: N)r: _MAX_RETRIESr)orig_fn exceptionsriexs rrrsu,^ 9  #%Ftf#M NN L1$$.7v>% s'AA  Ac#nKttD]}|tjt!yw)aHelper 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)rangerAtimesleep_RETRY_WAIT_SECS)rDs rr:r:s.$< % #$%s35)rstrr z str | Noner boolreturnrK)F)rrKr rLrMfloat)r+rKrMbytes)r5rKr rKrMrK)rBzCallable[[], T]rCz-type[Exception] | tuple[type[Exception], ...]rz str | PathrMr>)rMzGenerator[int, None, None])__doc__ __future__rrrHpathlibrtypingrrstreamlit.errorsrstreamlit.utilrcollections.abcr r rArJr!r&rr8rr>rr:rrrXs # )5#3  $#     D4  $F CL O  O= O  O OF%r