
    4i=9                        U d Z ddlmZ ddlZddlmZmZmZmZ ddl	m
Z
 erddlmZ ddlmZ  e
e      Zded	<    G d
 de      Z G d d      Zy)a  Component file watching utilities.

This module provides the `ComponentFileWatcher`, a utility that watches
component asset directories for changes and notifies a caller-provided callback
with the affected component names. It abstracts the underlying path-watcher
implementation and ensures exception-safe startup and cleanup.

Why this exists
---------------
Streamlit supports advanced Custom Components that ship a package of static
assets (for example, a Vite/Webpack build output). While a user develops their
app, those frontend files may change. The component registry for Custom
Components v2 must stay synchronized with the on-disk assets so that the server
can resolve the up-to-date files.

This watcher exists to keep the registry in sync by listening for changes in
component asset roots and notifying a higher-level manager that can re-resolve
the affected component definitions.

Notes
-----
- Watching is directory-based with a recursive glob ("**/*").
- Common noisy directories (e.g., ``node_modules``) are ignored in callbacks.
- Startup is exception-safe and does not leak partially created watchers.

See Also
--------
- :class:`streamlit.watcher.local_sources_watcher.LocalSourcesWatcher` - watches
  app source files per session to trigger reruns.
- :class:`streamlit.components.v2.component_registry.BidiComponentRegistry` -
  the server-side store of Custom Component v2 definitions that reacts to
  watcher notifications.
    )annotationsN)TYPE_CHECKINGFinalProtocolcast)
get_logger)CallablePathr   _LOGGERc                      e Zd ZddZy)	_HasClosec                     y N selfs    x/home/obispo/Crisostomo_bridge/mision_env/lib/python3.12/site-packages/streamlit/components/v2/component_file_watcher.pyclosez_HasClose.closeB   s        NreturnNone)__name__
__module____qualname__r   r   r   r   r   r   A   s     r   r   c                      e Zd ZdZddZedd       ZddZddZddZ	ddZ
	 	 	 	 ddZ	 	 	 	 	 	 dd	Z	 	 	 	 	 	 	 	 dd
ZddZddZddZddZy)ComponentFileWatchera#  Handle file watching for component asset directories.

    Parameters
    ----------
    component_update_callback : Callable[[list[str]], None]
        Callback invoked when files change under any watched directory. It
        receives a list of component names affected by the change.
    c                    || _         t        j                         | _        i | _        g | _        d| _        i | _        d| _        y)a  Initialize the file watcher.

        Parameters
        ----------
        component_update_callback : Callable[[list[str]], None]
            Callback function to call when components under watched roots change.
            Signature: (affected_component_names)
        F)__pycache__z.cachez.gitz.hgz.mypy_cachez.pytest_cachez.ruff_cachez.svnz.swcz.yarncoveragenode_modulesvenvN)	_component_update_callback	threadingLock_lock_watched_directories_path_watchers_watching_active_asset_watch_roots_ignored_dirs)r   component_update_callbacks     r   __init__zComponentFileWatcher.__init__O   sN     +D'^^%

  	! 02 % 46/
r   c                    | j                   S )zCheck if file watching is currently active.

        Returns
        -------
        bool
            True if file watching is active, False otherwise
        )r*   r   s    r   is_watching_activez'ComponentFileWatcher.is_watching_activev   s     $$$r   c                F    | j                          | j                  |       y)a{  Start file watching for asset roots.

        Parameters
        ----------
        asset_watch_roots : dict[str, Path]
            Mapping of component names to asset root directories to watch.

        Notes
        -----
        The method is idempotent: it stops any active watchers first, then
        re-initializes watchers for the provided ``asset_watch_roots``.
        N)stop_file_watching_start_file_watching)r   asset_watch_rootss     r   start_file_watchingz(ComponentFileWatcher.start_file_watching   s     	!!!"34r   c                   | j                   5  | j                  s
	 ddd       y| j                  D ]  }	 |j                           | j                  j                          | j                  j                          | j                  j                          d| _        t
        j                  d       ddd       y# t        $ r t
        j                  d       Y w xY w# 1 sw Y   yxY w)zStop file watching and clean up watchers.

        Notes
        -----
        This method is safe to call multiple times and will no-op if
        watching is not active.
        NzFailed to close path watcherFz,Stopped file watching for component registry)r'   r*   r)   r   	Exceptionr   	exceptionclearr(   r+   debug)r   watchers     r   r2   z'ComponentFileWatcher.stop_file_watching   s     ZZ 	J((	J 	J
  .. FFMMOF %%'%%++-##))+$)D!MMHI!	J 	J ! F%%&DEF	J 	Js4   CCB9A,C9CCCCC&c                   | j                   5  | j                  r
	 ddd       y|st        j                  d       	 ddd       y	 | j	                         }|
	 ddd       y| j                  |      }| j                  ||      \  }}|r| j                  |||       nt        j                  d       ddd       y# t        $ r t        j                  d       Y )w xY w# 1 sw Y   yxY w)a  Internal method to start file watching with the given roots.

        This method is exception-safe: in case of failures while creating
        watchers, any previously created watcher instances are closed and no
        internal state is committed.
        NzNo asset roots to watchz-No directories were watched; staying inactivezFailed to start file watching)
r'   r*   r   r:   _get_default_path_watcher_class_prepare_directories_to_watch_build_watchers_for_directories_commit_watch_stater7   r8   )r   r4   path_watcher_classdirectories_to_watchnew_watchersnew_watched_dirss         r   r3   z)ComponentFileWatcher._start_file_watching   s    ZZ 	C$$	C 	C %78	C 	CC%)%I%I%K"%-	C 	C (,'I'I%($ 261U1U&(<2..
  ,,$&68I MM"QR9	C 	C:  C!!"ABC;	C 	Cs5   C C B<"AB<<CC CC  C)c                X    ddl m}m}  |       }||u rt        j	                  d       y|S )a  Return the default path watcher class.

        Returns
        -------
        type | None
            The concrete path watcher class to instantiate, or ``None`` if
            the NoOp watcher is configured and file watching should be
            skipped.
        r   )NoOpPathWatcherget_default_path_watcher_classz8NoOpPathWatcher in use; skipping component file watchingN)streamlit.watcher.path_watcherrF   rG   r   r:   )r   rF   rG   rA   s       r   r=   z4ComponentFileWatcher._get_default_path_watcher_class   s0    	

 <=0MMTU!!r   c                    i }|j                         D ]C  \  }}t        |j                               }||vrg ||<   |||   vs0||   j                  |       E |S )a  Build a mapping of directory to component names.

        Parameters
        ----------
        asset_watch_roots : dict[str, Path]
            Mapping of component names to their asset root directories.

        Returns
        -------
        dict[str, list[str]]
            A map from absolute directory path to a deduplicated list of
            component names contained in that directory.
        )itemsstrresolveappend)r   r4   rB   	comp_nameroot	directorys         r   r>   z2ComponentFileWatcher._prepare_directories_to_watch   su      680668 	BOItDLLN+I 4424$Y/ 4Y ??$Y/66yA	B $#r   c                <   g }i }|j                         D ]c  \  }}	 | j                  t        |            } |||dd      }|j                  t	        d|             |||<   t
        j                  d||       e ||fS # t        $ r | j                  |        w xY w)a  Create watchers for directories with rollback on failure.

        Parameters
        ----------
        path_watcher_class : type
            The path watcher class to instantiate for each directory.
        directories_to_watch : dict[str, list[str]]
            A map of directory to the associated component name list.

        Returns
        -------
        tuple[list[_HasClose], dict[str, list[str]]]
            The list of created watcher instances and the watched directory
            mapping.

        Raises
        ------
        Exception
            Propagates any exception during watcher creation after closing
            already-created watchers.
        z**/*F)glob_patternallow_nonexistentr   z2Prepared watcher for directory %s (components: %s))	rJ   _make_directory_callbacktuplerM   r   r   r:   r7   _rollback_watchers)	r   rA   rB   rC   rD   rP   component_namescbr;   s	            r   r?   z4ComponentFileWatcher._build_watchers_for_directories  s    0 )+13*>*D*D*F 	&I2253IJ -!'&+	 ##Dg$>?.= +H#	. ---  ''5s   AA??Bc                    || _         || _        t        |      | _        d| _        t
        j                  dt        | j                               y)a  Commit created watchers and mark watching active.

        Parameters
        ----------
        new_watchers : list[_HasClose]
            Fully initialized watcher instances.
        new_watched_dirs : dict[str, list[str]]
            Mapping from directory to component names.
        asset_watch_roots : dict[str, Path]
            The asset roots used to initialize watchers; stored for reference.
        Tz(Started file watching for %d directoriesN)r)   r(   dictr+   r*   r   r:   len)r   rC   rD   r4   s       r   r@   z(ComponentFileWatcher._commit_watch_state6  sF    " +$4!"&'8"9 $6D<U<U8V	
r   c                |    |D ]  }	 |j                           y# t        $ r t        j                  d       Y 7w xY w)zClose any created watchers when setup fails.

        Parameters
        ----------
        watchers : list[_HasClose]
            Watcher instances that were successfully created before a failure.
        z,Failed to close path watcher during rollbackN)r   r7   r   r8   )r   watchersws      r   rV   z'ComponentFileWatcher._rollback_watchersO  sF      	RAR		R  R!!"PQRs   ;;c                     d fd}|S )zHCreate a callback for a directory watcher that captures component names.c                    j                  |       rt        j                  d|        y t        j                  d|        j                  t	                     y )Nz&Ignoring change in noisy directory: %sz6Directory change detected: %s, checking components: %s)_is_in_ignored_directoryr   r:   _handle_component_changelist)changed_pathcompsr   s    r   callbackz?ComponentFileWatcher._make_directory_callback.<locals>.callback`  sL    ,,\:FUMMH
 ))$u+6r   )rd   rK   r   r   r   )r   re   rf   s   `` r   rT   z-ComponentFileWatcher._make_directory_callback]  s    		7 r   c                    | j                   sy	 | j                  |       y# t        $ r t        j	                  d       Y yw xY w)zHandle component changes for both directory and file events.

        Parameters
        ----------
        affected_components : list[str]
            List of component names affected by the change
        Nz Component update callback raised)r*   r$   r7   r   r8   )r   affected_componentss     r   rb   z-ComponentFileWatcher._handle_component_changem  sE     $$	B++,?@ 	B@A	Bs   ! AAc                    	 ddl m} t         ||      j                         j                        t        fd| j                  D              S # t        $ r Y yw xY w)ae  Return True if the changed path is inside an ignored directory.

        Parameters
        ----------
        changed_path : str
            The filesystem path that triggered the change event.

        Returns
        -------
        bool
            True if the path is located inside one of the ignored directories,
            False otherwise.
        r   r
   c              3  &   K   | ]  }|v  
 y wr   r   ).0ignoredpartss     r   	<genexpr>z@ComponentFileWatcher._is_in_ignored_directory.<locals>.<genexpr>  s     JGw%'Js   F)pathlibr   setrL   rm   anyr,   r7   )r   rd   _Pathrm   s      @r   ra   z-ComponentFileWatcher._is_in_ignored_directory  sR    	-l+335;;<EJt7I7IJJJ 		s   AA 	AAN)r-   zCallable[[list[str]], None]r   r   )r   bool)r4   dict[str, Path]r   r   r   )r   ztype | None)r4   rt   r   dict[str, list[str]])rA   typerB   ru   r   z,tuple[list[_HasClose], dict[str, list[str]]])rC   list[_HasClose]rD   ru   r4   rt   r   r   )r]   rw   r   r   )re   ztuple[str, ...]r   zCallable[[str], None])rh   z	list[str]r   r   )rd   rK   r   rs   )r   r   r   __doc__r.   propertyr0   r5   r2   r3   r=   r>   r?   r@   rV   rT   rb   ra   r   r   r   r   r   E   s    %
N % %5$J4%CN"*$!0$	$22."&2.>R2.	52.h
%
 /
 +	

 

2R B$r   r   )rx   
__future__r   r%   typingr   r   r   r   streamlit.loggerr   collections.abcr	   ro   r   r   r   __annotations__r   r   r   r   r   <module>r      sN     D #  7 7 '( H% %! !N Nr   