Ë
    úmxiðQ  ã                  ó®  — U d Z ddlm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 ddlmZmZ ddlZddlmZ dd	lmZ dd
lmZ ddlmZ  ee«      Zded<   dd„Ze G d„ d«      «       Ze G 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+	 d)	 	 	 d*d„Z,y)+a‡  Discovery utilities for Component v2 manifests in installed packages.

The scanner searches installed distributions for a ``pyproject.toml`` with
``[tool.streamlit.component]`` configuration and extracts the component
manifests along with their package roots.

The implementation prioritizes efficiency and safety by filtering likely
candidates and avoiding excessive filesystem operations.
é    )ÚannotationsN)ÚThreadPoolExecutorÚas_completed)Ú	dataclass)ÚPath)ÚAnyÚFinal)Úutils)ÚComponentPathUtils)ÚStreamlitComponentRegistryError)Ú
get_loggerr	   Ú_LOGGERc                ó&   — | j                  dd«      S )aÉ  Normalize a distribution name to an importable package name.

    This helper converts hyphens to underscores to derive a best-effort
    importable module/package name from a distribution name.

    Parameters
    ----------
    dist_name : str
        The distribution/project name (e.g., "my-awesome-component").

    Returns
    -------
    str
        The normalized package name suitable for import lookups
        (e.g., "my_awesome_component").
    ú-Ú_)Úreplace)Ú	dist_names    ú_/home/htdocs/ttos/venv/lib/python3.12/site-packages/streamlit/components/v2/manifest_scanner.pyÚ_normalize_package_namer   -   s   € ð" ×Ñ˜S #Ó&Ð&ó    c                  ó0   — e Zd ZU dZded<   ded<   ded<   y)ÚComponentManifestzParsed component manifest data.ÚstrÚnameÚversionzlist[ComponentConfig]Ú
componentsN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__© r   r   r   r   A   s   … á)à
ƒIØƒLØ%Ô%r   r   c                  óV   — e Zd ZU dZded<   dZded<   ed
d„«       Zedd„«       Zdd	„Z	y)ÚComponentConfigzìStructured configuration for a single component entry.

    Parameters
    ----------
    name
        Component name as declared in ``pyproject.toml``.
    asset_dir
        Optional relative directory containing component assets.
    r   r   Nz
str | NoneÚ	asset_dirc                óÔ   — | j                  d«      }t        |t        «      r|st        d«      ‚| j                  d«      }|�t        |t        «      st        d«      ‚t	        ||¬«      S )a  Create a ComponentConfig from a raw dict.

        Parameters
        ----------
        config
            Raw component dictionary parsed from TOML.

        Returns
        -------
        ComponentConfig
            Parsed and validated component configuration.
        r   z-Component entry missing required 'name' fieldr%   z'asset_dir' must be a string)r   r%   )ÚgetÚ
isinstancer   Ú
ValueErrorr$   )ÚconfigÚ
name_valueÚasset_dir_values      r   Ú	from_dictzComponentConfig.from_dictY   sf   € ð —Z‘Z Ó'ˆ
Ü˜*¤cÔ*±*äÐLÓMÐMà Ÿ*™* [Ó1ˆØÐ&¬z¸/Ì3Ô/OäÐ;Ó<Ð<äØØ%ô
ð 	
r   c                ó†   — 	 t         j                  | «      S # t        $ r }t        j	                  d|«       Y d}~yd}~ww xY w)zCBest-effort parse without raising; returns None on malformed input.z&Skipping malformed component entry: %sN)r$   r-   Ú	Exceptionr   Údebug)r*   Úes     r   Úparse_or_nonezComponentConfig.parse_or_nonev   s:   € ð	Ü"×,Ñ,¨VÓ4Ð4øÜò 	Ü�M‰MÐBÀAÔFÜûð	ús   ‚ —	A  ;»A c           	     óv  — | j                   €yt        j                  | j                   «       || j                   z  j                  «       }|j	                  «       r|j                  «       s)t        d| j                   › d| j                  › d|› d�«      ‚t        j                  ||j                  «       d¬«       |S )a@  Resolve and security-check the component's asset root directory.

        Parameters
        ----------
        package_root : Path
            The root directory of the installed component package.

        Returns
        -------
        Path | None
            Absolute, resolved path to the asset directory, or ``None`` if
            ``asset_dir`` is not declared.

        Raises
        ------
        StreamlitComponentRegistryError
            If the declared directory does not exist, is not a directory, or
            resolves outside of ``package_root``.
        NzDeclared asset_dir 'z' for component 'z;' does not exist or is not a directory under package root 'z'.r%   )Úabs_pathÚrootÚkind)	r%   r   Úvalidate_path_securityÚresolveÚexistsÚis_dirr   r   Úensure_within_root)ÚselfÚpackage_rootÚ
asset_roots      r   Úresolve_asset_rootz"ComponentConfig.resolve_asset_root   s¶   € ð( �>‰>Ð!Øô 	×1Ñ1°$·.±.ÔAà" T§^¡^Ñ3×<Ñ<Ó>ˆ
à× Ñ Ô"¨*×*;Ñ*;Ô*=Ü1Ø& t§~¡~Ð&6Ð6GÈÏ	É	À{ð SLØLXÈ>ÐY[ð]óð ô 	×-Ñ-ØØ×%Ñ%Ó'Øõ	
ð Ðr   )r*   údict[str, Any]Úreturnr$   )r*   r@   rA   zComponentConfig | None)r=   r   rA   úPath | None)
r   r   r   r    r!   r%   Ústaticmethodr-   r2   r?   r"   r   r   r$   r$   J   sC   … ñð ƒIØ €IˆzÓ àò
ó ð
ð8 òó ðô)r   r$   c                óœ  — | j                   j                  «       }d| j                  v r| j                  d   j                  «       nd}d|v ryd|v ry	 | j                  j                  d«      xs g }|D ]  }|sŒd|j                  «       v sŒ y 	 |j                  d«      S # t        $ r }t
        j                  d|«       Y d}~Œ5d}~ww xY w)	aÛ  Check if a package is likely to contain streamlit components before
    expensive operations.

    This early filter reduces the number of packages that need file I/O
    operations from potentially hundreds down to just a few candidates.

    Parameters
    ----------
    dist : importlib.metadata.Distribution
        The package distribution to check.

    Returns
    -------
    bool
        True if the package might contain streamlit components, False otherwise.
    ÚSummaryÚ Ú	streamlitTzRequires-DistzFFailed to parse package metadata for streamlit component detection: %sN)z
streamlit-Ú
streamlit_zst-Úst_)r   ÚlowerÚmetadataÚget_allr/   r   r0   Ú
startswith)Údistr   ÚsummaryÚrequires_distÚrequirementr1   s         r   Ú&_is_likely_streamlit_component_packagerR   «   sÑ   € ð( �9‰9�?‰?Ó€DØ2;¸t¿}¹}Ñ2Lˆd�m‰m˜IÑ&×,Ñ,Ô.ÐRT€Gð �dÑØð �gÑØð

àŸ™×-Ñ-¨oÓ>ÒDÀ"ˆØ(ò 	ˆKÚ˜{¨k×.?Ñ.?Ó.AÒAÙñ	ð �?‰?ÐEÓFÐFøô ò 
ä�‰ØTÐVW÷	
ñ 	
ûð
ús*   Á&B" Á:B" ÂB" ÂB" Â"	CÂ+CÃCc                óv   ‡— t        | j                  «      Št        t        ˆfd„fD ]  } || «      }|€Œ|c S  y)aè  Find ``pyproject.toml`` for a package.

    Handles both regular and editable installs. The function uses increasingly
    permissive strategies to locate the file while validating that the file
    belongs to the given distribution.

    Parameters
    ----------
    dist : importlib.metadata.Distribution
        The package distribution to find pyproject.toml for.

    Returns
    -------
    Path | None
        Path to the ``pyproject.toml`` file if found, otherwise ``None``.
    c                ó   •— t        | ‰«      S ©N)Ú_pyproject_via_import_spec)ÚdÚpackage_names    €r   ú<lambda>z._find_package_pyproject_toml.<locals>.<lambda>ô   s   ø€ Ô,¨Q°Ó=€ r   N)r   r   Ú_pyproject_via_read_textÚ_pyproject_via_dist_files)rN   ÚfinderÚresultrX   s      @r   Ú_find_package_pyproject_tomlr^   Ý   sJ   ø€ ô" +¨4¯9©9Ó5€Lô 	!Ü!Û=ðò ˆñ
 ˜“ˆØÑØŠMðð r   c                ó  — t        | j                  «      }	 t        | d«      rÂ| j                  d«      }|r¯| j                  r£| j                  D ]”  }dt        |«      v sdt        |«      v sŒ	 t        t        | j                  |«      «      «      }|j                  }||j                  fD ]5  }|dz  }|j                  «       sŒt        || j                  |«      sŒ1|c c S   y y# t        $ r Y Œ£w xY w# t        $ r Y yw xY w)z›Locate pyproject.toml using the distribution's read_text + nearby files.

    This works for many types of installations including some editable ones.
    Ú	read_textúpyproject.tomlú__init__.pyz.pyN)r   r   Úhasattrr`   Úfilesr   r   Úlocate_fileÚparentr9   Ú_validate_pyproject_for_packager/   )rN   rX   Úpyproject_contentÚfileÚ	file_pathÚcurrent_dirÚ
search_dirÚpyproject_paths           r   rZ   rZ   ý   s  € ô
 +¨4¯9©9Ó5€LðÜ�4˜Ô%Ø $§¡Ð/?Ó @ÐÙ  T§Z¢Zð !ŸJ™Jò %�DØ$¬¨D«	Ñ1°U¼cÀ$»iÒ5Gð%Ü(,¬S°×1AÑ1AÀ$Ó1GÓ-HÓ(I˜Ià*3×*:Ñ*:˜Kà/:¸K×<NÑ<NÐ.Oò 
: 
Ø1;Ð>NÑ1N à$2×$9Ñ$9Õ$;Ü(GØ(6Ø(,¯	©	Ø(4õ)&ð ,:Ô$9ð
:ð "ð
 ð1%ð0 øô	  )ò %Ù$ð%ûäò ÙðúsU   —AC5 Á-AC&ÃC&ÃC&ÃC5 Ã!C&Ã"C5 Ã$C5 Ã&	C2Ã/C5 Ã1C2Ã2C5 Ã5	DÄ Dc                óN  — t        | j                  «      }t        | dd«      }|sy|D ]l  }t        |dd«      dk(  st        |«      j	                  d«      sŒ.	 t        t        | j                  |«      «      «      }t        || j                  |«      r|c S Œn y# t        $ r Y Œ{w xY w)z?Locate pyproject.toml by scanning the distribution's file list.rd   Nr   ra   )	r   r   Úgetattrr   Úendswithr   re   rg   r/   )rN   rX   rd   ri   rm   s        r   r[   r[   $  s³   € ä*¨4¯9©9Ó5€LÜ�D˜' 4Ó(€EÙØØò ˆÜ�4˜ Ó&Ð*:Ò:¼cÀ$»i×>PÑ>PØõ?
ð	Ü!%¤c¨$×*:Ñ*:¸4Ó*@Ó&AÓ!B�Ü2Ø"Ø—I‘IØ ôð
 *Ò)ððð øô ò Ùðús   Á;BÂ	B$Â#B$c                óD  — 	 t         j                  j                  |«      }|ro|j                  rct	        |j                  «      j
                  }||j
                  fD ]3  }|dz  }|j                  «       sŒt        || j                  |«      sŒ1|c S  y# t        $ r Y yw xY w)z—Locate pyproject.toml by resolving the import spec and checking nearby.

    For editable installs, try the package directory and its parent only.
    ra   N)
Ú	importlibÚutilÚ	find_specÚoriginr   rf   r9   rg   r   r/   )rN   rX   ÚspecÚpackage_dirrl   rm   s         r   rV   rV   ;  sŸ   € ðÜ�~‰~×'Ñ'¨Ó5ˆÙ�D—K’KÜ˜tŸ{™{Ó+×2Ñ2ˆKØ*¨K×,>Ñ,>Ð?ò *�
Ø!+Ð.>Ñ!>�Ø!×(Ñ(Õ*Ô/NØ"Ø—I‘IØ õ0ð
 *Ò)ð*ð øô ò Ùðús$   ‚A2B Á5B ÂB ÂB Â	BÂBc                óÌ  — 	 t        | d¬«      5 }t        j                  |«      }ddd«       d}dv rd|d   v r|d   d   }|s d|v rd|d   v rd|d   d   v r|d   d   d   }|rEt        j                  |«      }t        j                  |«      }t        j                  |«      }|||fv S y	# 1 sw Y   ŒˆxY w# t
        $ r"}	t        j                  d
| ||	«       Y d}	~	y	d}	~	ww xY w)a¹  Validate that a ``pyproject.toml`` file belongs to the specified package.

    Parameters
    ----------
    pyproject_path : Path
        Path to the pyproject.toml file to validate.
    dist_name : str
        The distribution name (e.g., "streamlit-bokeh").
    package_name : str
        The package name (e.g., "streamlit_bokeh").

    Returns
    -------
    bool
        True if the file belongs to this package, False otherwise.
    úutf-8©ÚencodingNÚprojectr   ÚtoolÚ
setuptoolszpackage-nameFz0Error validating pyproject.toml at %s for %s: %s)ÚopenÚtomlÚloadÚpackaging_utilsÚcanonicalize_namer/   r   r0   )
rm   r   rX   ÚfÚpyproject_dataÚproject_nameÚcanonical_projectÚcanonical_distÚcanonical_packager1   s
             r   rg   rg   S  s$  € ð&+Ü�.¨7Ô3ð 	*°qÜ!ŸY™Y q›\ˆN÷	*ð ˆð ˜Ñ&¨6°^ÀIÑ5NÑ+NØ)¨)Ñ4°VÑ<ˆLñ Ø˜.Ñ(à ¨vÑ 6Ñ6Ø" n°VÑ&<¸\Ñ&JÑJð *¨&Ñ1°,Ñ?ÀÑOˆLñ ô !0× AÑ AÀ,Ó OÐÜ,×>Ñ>¸yÓIˆNÜ /× AÑ AÀ,Ó OÐð %¨Ð9JÐ(KÐKÐKð ÷C	*ð 	*ûôF ò Ü�‰Ø>ØØØô		
ô ûðús.   ‚B8 �B,¥BB8 Â,B5Â1B8 Â8	C#ÃCÃC#c                óÎ   — 	 t        | d¬«      5 }t        j                  |«      cddd«       S # 1 sw Y   yxY w# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)zJLoad and parse a pyproject.toml, returning parsed data or None on failure.ry   rz   Nz(Failed to parse pyproject.toml at %s: %s)r   r€   r�   r/   r   r0   )rm   r„   r1   s      r   Ú_load_pyprojectr‹   ”  sW   € ðÜ�.¨7Ô3ð 	 °qÜ—9‘9˜Q“<÷	 ÷ 	 ò 	 ûäò Ü�‰Ð@À.ÐRSÔTÜûðús)   ‚: �.¤	: ®7³: ·: º	A$ÁAÁA$c                ó  — | j                  di «      j                  di «      j                  d«      }|sy|j                  d«      }t        |t        «      sy|D �cg c]  }t        |t        «      sŒ|‘Œ }}|sy|S c c}w )zGExtract raw component dicts from pyproject data; return None if absent.r}   rG   Ú	componentNr   )r'   r(   ÚlistÚdict)r…   Ústreamlit_componentÚraw_componentsÚitemr]   s        r   Ú_extract_componentsr“   ž  s�   € ð 	×Ñ˜6 2Ó&×*Ñ*¨;¸Ó;×?Ñ?ÀÓLð ñ ØØ(×,Ñ,¨\Ó:€NÜ�n¤dÔ+Øð (ö$Ø¬:°d¼DÕ+AŠð$€Fð $ñ ØØ€Mùò$s   ÁA<Á1A<c                ó>  — d}	 t         j                  j                  |«      }|r+|j                  rt	        |j                  «      j
                  }t        | dd«      }|sV|rT|D ]O  }|t        |«      v sŒdt        |«      v sŒ	 t	        t        | j                  |«      «      «      }|j
                  } n |s|j
                  }|S # t        $ r!}t        j                  d||«       Y d}~Œšd}~ww xY w# t        $ r!}t        j                  d||«       Y d}~Œ´d}~ww xY w)z2Resolve the package root directory with fallbacks.Nz9Failed to resolve package root via import spec for %s: %srd   rb   z8Failed to resolve package root via dist files for %s: %s)rr   rs   rt   ru   r   rf   r/   r   r0   ro   r   re   )	rN   rX   rm   r=   rv   r1   rd   ri   Ú	init_paths	            r   Ú_resolve_package_rootr–   ±  s  € ð !%€Lð	
Ü�~‰~×'Ñ'¨Ó5ˆÙ�D—K’KÜ §¡Ó,×3Ñ3ˆLô �D˜' 4Ó(€EÙ™EØò 	ˆDØœs 4›yÒ(¨]¼cÀ$»iÒ-Gð	Ü $¤S¨×)9Ñ)9¸$Ó)?Ó%@Ó A�IØ#,×#3Ñ#3�LÙð	ñ Ø%×,Ñ,ˆàÐøô3 ò 
Ü�‰ØGØØ÷	
ñ 	
ûð
ûô !ò Ü—M‘MØRØ$Ø÷ñ ûðús0   „AC Â/C2Ã	C/ÃC*Ã*C/Ã2	DÃ;DÄDc                ó²   — | j                  di «      }|j                  d«      xs |j                  }|j                  d«      xs |j                  xs d}||fS )z4Derive project name and version with safe fallbacks.r|   r   r   z0.0.0)r'   r   r   )r…   rN   Úproject_tableÚderived_nameÚderived_versions        r   Ú_derive_project_metadatar›   Ö  sX   € ð #×&Ñ& y°"Ó5€MØ ×$Ñ$ VÓ,Ò9°·	±	€LØ#×'Ñ'¨	Ó2ÒM°d·l±lÒMÀg€OØ˜Ð(Ð(r   c           	     óª  — 	 t        | «      }|syt        |«      }|€yt        |«      }|syt        | j                  «      }t        | ||«      }t        || «      \  }}|D �cg c]  }t        j                  |«      x}	�|	‘Œ }
}|
syt        |||
¬«      }||fS c c}w # t        $ r,}t        j                  dt        | dd«      |«       Y d}~yd}~ww xY w)a’  Process a single package to extract component manifest.

    This function is designed to be called from a thread pool for parallel processing.

    Parameters
    ----------
    dist : importlib.metadata.Distribution
        The package distribution to process.

    Returns
    -------
    tuple[ComponentManifest, Path] | None
        The manifest and package root if found, otherwise ``None``.
    N)r   r   r   z/Unexpected error processing distribution %s: %sr   z	<unknown>)r^   r‹   r“   r   r   r–   r›   r$   r2   r   r/   r   r0   ro   )rN   rm   r…   r‘   rX   r=   r™   rš   ÚcompÚparsedÚparsed_componentsÚmanifestr1   s                r   Ú_process_single_packager¡   à  s   € ð")Ü5°dÓ;ˆÙØä(¨Ó8ˆØÐ!Øä,¨^Ó<ˆÙØä.¨t¯y©yÓ9ˆÜ,¨T°<ÀÓPˆä(@ÀÐQUÓ(VÑ%ˆ�oð 'ö4
àÜ)×7Ñ7¸Ó=Ð=�ÐJò ð4
Ðð 4
ñ !Øä$ØØ#Ø(ô
ˆð ˜,Ð'Ð'ùò4
øô" ò Ü�‰Ø=Ü�D˜& +Ó.Øô	
ô
 ûðús>   ‚B �B žB ¬5B Á! BÂB ÂB ÂB Â	CÂ&"CÃCc                ó  — g }t        t        j                  j                  «       «      }|s|S |D �cg c]  }t	        |«      r|‘Œ }}t
        j                  dt        |«      t        |«      «       |s|S | €%t        dt        j                  «       xs ddz   «      } t        | t        |«      d«      } t
        j                  dt        |«      | «       t        | ¬«      5 }|D �ci c]#  }|j                  t        |«      |j                  “Œ% }}t        |«      D ]&  }|j!                  «       }|sŒ|j#                  |«       Œ( 	 ddd«       t
        j                  d	t        |«      «       |S c c}w c c}w # 1 sw Y   Œ4xY w)
a%  Scan installed packages for Streamlit component metadata.

    Uses parallel processing to improve performance in environments with many
    installed packages. Applies early filtering to only check packages likely to
    contain streamlit components.

    Parameters
    ----------
    max_workers : int or None
        Maximum number of worker threads. If None, uses min(32, (os.cpu_count()
        or 1) + 4).

    Returns
    -------
    list[tuple[ComponentManifest, Path]]
        List of tuples of manifests and their package root paths.
    zAFiltered %d packages down to %d candidates for component scanningNé    é   é   é   zNScanning %d candidate packages for component manifests using %d worker threads)Úmax_workersz"Found %d component manifests total)rŽ   rr   rK   ÚdistributionsrR   r   r0   ÚlenÚminÚosÚ	cpu_countr   Úsubmitr¡   r   r   r]   Úappend)	r§   Ú	manifestsÚall_distributionsrN   Úcandidate_distributionsÚexecutorÚfuture_to_distÚfuturer]   s	            r   Úscan_component_manifestsrµ     sŒ  € ð( 79€Iô œY×/Ñ/×=Ñ=Ó?Ó@ÐáØÐð
 &öàÜ1°$Ô7ò 	ðÐð ô ‡M�MØKÜÐÓÜÐ#Ó$ôñ #ØÐð ÐÜ˜"œrŸ|™|›~Ò2°°aÑ7Ó8ˆô Ø”SÐ0Ó1°2ó€Kô ‡M�MØXÜÐ#Ó$Øôô 
¨Ô	4ð )¸ð 0ö
àð �O‰OÔ3°TÓ:¸D¿I¹IÑEð
ˆð 
ô # >Ó2ò 	)ˆFØ—]‘]“_ˆFÚØ× Ñ  Õ(ñ	)÷)ô ‡M�MÐ6¼¸I»ÔGØÐùò[ùòB
÷)ð )ús)   ²E+ÃE5Ã#(E0Ä"E5Ä.E5Å0E5Å5E>)r   r   rA   r   )rN   úimportlib.metadata.DistributionrA   Úbool)rN   r¶   rA   rB   )rN   r¶   rX   r   rA   rB   )rm   r   r   r   rX   r   rA   r·   )rm   r   rA   zdict[str, Any] | None)r…   r@   rA   zlist[dict[str, Any]] | None)rN   r¶   rX   r   rm   r   rA   r   )r…   r@   rN   r¶   rA   ztuple[str, str])rN   r¶   rA   z%tuple[ComponentManifest, Path] | NonerU   )r§   z
int | NonerA   z$list[tuple[ComponentManifest, Path]])-r    Ú
__future__r   Úimportlib.metadatarr   Úimportlib.utilr«   Úconcurrent.futuresr   r   Údataclassesr   Úpathlibr   Útypingr   r	   r€   Ú	packagingr
   r‚   Ú,streamlit.components.v2.component_path_utilsr   Ústreamlit.errorsr   Ústreamlit.loggerr   r   r   r!   r   r   r$   rR   r^   rZ   r[   rV   rg   r‹   r“   r–   r›   r¡   rµ   r"   r   r   ú<module>rÃ      sj  ðòõ #ã Û Û 	ß ?Ý !Ý ß ã Ý .å KÝ <Ý 'á˜HÓ%€ˆÓ %ó'ð( ÷&ð &ó ð&ð ÷]ð ]ó ð]ð@/GØ
)ð/Gà	ó/Gódó@$óNð.Ø
)ðØ9<ðàóð0>Øð>Ø%(ð>Ø8;ð>à	ó>óBóð&"Ø
)ð"Ø9<ð"ØNRð"à	ó"ðJ)Ø"ð)Ø*Ið)àó)ð:Ø
)ð:à*ó:ð| #ðJØðJà)ôJr   