
    kKj$A                       d Z 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 ddlmZ ddlmZ dd	lmZ  ee      Ze	 G d
 d             ZddZddZdddZddZddZddZ	 d	 	 	 	 	 ddZddZddZ y)a6  File discovery and module import utilities for filesystem-based routing.

This module provides functions to:
1. Discover Python files in a directory tree
2. Import modules (as packages if __init__.py exists, else directly)
3. Extract decorated components (Tool, Resource, Prompt objects) from imported modules
    )annotationsN)	dataclassfield)
ModuleSpec)Path)
ModuleType)FastMCPComponent)
get_loggerc                  J    e Zd ZU dZ ee      Zded<    ee      Z	ded<   y)DiscoveryResultzResult of filesystem discovery.)default_factoryz#list[tuple[Path, FastMCPComponent]]
componentszdict[Path, str]failed_filesN)
__name__
__module____qualname____doc__r   listr   __annotations__dictr        ~/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/providers/filesystem_discovery.pyr   r      s&    ) 7<D6QJ3Q$)$$?L/?r   r   c                2   | j                         sg S | j                         s#| j                  dk(  r| j                  dk7  r| gS g S g }| j	                  d      D ]2  }|j                  dk(  rd|j
                  v r"|j                  |       4 t        |      S )a  Recursively discover all Python files under a directory.

    Excludes __init__.py files (they're for package structure, not components).

    Args:
        root: Root directory to scan.

    Returns:
        List of .py file paths, sorted for deterministic order.
    .py__init__.pyz*.py__pycache__)existsis_dirsuffixnamerglobpartsappendsorted)rootfilespaths      r   discover_filesr)   #   s     ;;=	;;=;;%DII$>6M	E

6"99%DJJ&T # %=r   c                (    | dz  j                         S )z;Check if a directory is a Python package (has __init__.py).r   )r   )	directorys    r   _is_package_dirr,   E   s    %--//r   c                    | j                   }d}||j                   k7  rA|||j                   k(  r	 |S t        |      r|}|j                   }n	 |S ||j                   k7  rA|S )a  Find the root of the package containing this file.

    Walks up the directory tree until we find a directory without __init__.py,
    but never above stop_at (the provider root). This prevents escaping into
    ancestor packages when the provider is nested inside a larger Python project.

    Args:
        file_path: Path to the Python file.
        stop_at: Do not walk above this directory. Typically the provider root.

    Returns:
        The package root directory, or None if not in a package.
    N)parentr,   )	file_pathstop_atcurrentpackage_roots       r   _find_package_rootr3   J   ss     GL
W^^
#7gnn#<  7#"LnnG W^^
# r   c                    | j                  |j                        }t        |j                        }|d   j	                  d      |d<   dj                  |      S )zCompute the dotted module name for a file within a package.

    Args:
        file_path: Path to the Python file.
        package_root: Root directory of the package.

    Returns:
        Dotted module name (e.g., "mcp.tools.greet").
    r   .)relative_tor.   r   r#   removesuffixjoin)r/   r2   relativer#   s       r   _compute_module_namer;   g   sN     $$\%8%89H Eb	&&u-E"I88E?r   c                l    t        | dd      }|syj                         t        fd|D              S )a  Check whether a package module's __path__ points at package_root.

    Used to tell whether a top-level package name already present in
    sys.modules belongs to this provider (same directory) or to a different
    provider that happens to share the package name.
    __path__NFc              3  V   K   | ]   }t        |      j                         k(   " y wN)r   resolve).0pr2   s     r   	<genexpr>z(_package_path_matches.<locals>.<genexpr>   s"     G,QtAw L0,s   &))getattrr@   any)moduler2   module_pathss    ` r   _package_path_matchesrH   x   s8     6:t4L'')LG,GGGr   c                    t        j                  t        | j                               j	                               j                         dd }d| S )zHCompute a collision-safe synthetic package name anchored at a directory.N   _fastmcp_pkg_)hashlibsha1strr@   encode	hexdigest)r+   digests     r   _private_package_prefixrR      sD    \\#i//1299;<FFH"MF6(##r   c           	        | j                         } ||j                         }t        | |      }|Ct        | |      }|j                  d      d   }t        j
                  j                  |      }|t        ||      st        |j                        }|t        j
                  vr[t        |dd      }t        j                  j                  |      }t        |j                        g|_        |t        j
                  |<   | d| }		 |	t        j
                  v r&t        j                   t        j
                  |	         S t        j"                  |	      S t        |j                        }|t        j&                  v}|r t        j&                  j)                  d|       	 |t        j
                  v rjt        j                   t        j
                  |         |rBt+        j,                  t.              5  t        j&                  j1                  |       ddd       S S t        j"                  |      |rBt+        j,                  t.              5  t        j&                  j1                  |       ddd       S S | j2                  }t        | j                        }t        j
                  j                  |      }|]t5        |d
d      t        |       k7  rDd| dt7        j8                  t        |       j;                               j=                         dd  }n|}|t        j&                  v}|r t        j&                  j)                  d|       	 t        j                  j?                  ||       }||j@                  t%        d|        t        j
                  j                  |      }|||_!        |j@                  |_"        t        |       |_#        	 |j@                  jI                  |       ||rBt+        j,                  t.              5  t        j&                  j1                  |       ddd       S S t        j                  j                  |      }|t        j
                  |<   	 |j@                  jI                  |       ||rBt+        j,                  t.              5  t        j&                  j1                  |       ddd       S S # t$        $ r}
t%        d| d|  d	|
       |
d}
~
ww xY w# 1 sw Y   S xY w# 1 sw Y   S xY w# t$        $ r}
t%        d| d|  d	|
       |
d}
~
ww xY w# |rNt+        j,                  t.              5  t        j&                  j1                  |       ddd       w # 1 sw Y   w xY ww xY w# tJ        $ r}
t%        d|  d	|
       |
d}
~
ww xY w# 1 sw Y   S xY w# tJ        $ r7}
t        j
                  jM                  |d       t%        d|  d	|
       |
d}
~
ww xY w# 1 sw Y   S xY w# |rNt+        j,                  t.              5  t        j&                  j1                  |       ddd       w # 1 sw Y   w xY ww xY w)a  Import a Python file as a module.

    If the file is part of a package (directory has __init__.py), imports
    it as a proper package member (relative imports work). Otherwise,
    imports directly using spec_from_file_location.

    sys.path is modified only for the duration of the import and restored
    immediately after, so no permanent pollution occurs.

    Args:
        file_path: Path to the Python file.
        provider_root: The provider's root directory. Prevents package root
            discovery from walking above this boundary into ancestor packages.

    Returns:
        The imported module.

    Raises:
        ImportError: If the module cannot be imported.
    N)r0   r6   r   T)loader
is_packagezFailed to import z from z: __file__	_fastmcp__rJ   zCannot load spec for zFailed to reload module zFailed to execute module )'r@   r3   r;   splitsysmodulesgetrH   rR   r.   r   	importlibutilmodule_from_specrN   r=   reloadimport_moduleImportErrorr(   insert
contextlibsuppress
ValueErrorremovestemrD   rL   rM   rO   rP   spec_from_file_locationrT   __spec__
__loader__rV   exec_module	Exceptionpop)r/   provider_rootr2   module_nametop_nameexisting_topanchorspecanchor_moduleprivate_nameepackage_parent
path_addedrh   
parent_direxistingrF   s                    r   import_module_from_filer|      sV   . !!#I %--/ &iGL*9lC $$S)!,{{x0#,A,-
 -\-@-@AFS[[(!&$G ) ? ? E*-l.A.A*B)C&&3F#$XQ{m4L3;;.$++CKK,EFF ..|<< \001#3883
HHOOA~.	4ckk) ''K(@A ((4HHOON3 54  **;7 ((4HHOON3 54 
 ~~))*
 ;;??4(GHj$$G3L
 %
 &dV1W\\#i.:O:O:Q-R-\-\-^_b`b-c,deKK
  sxx/
HHOOAz*#	0>>99+yQD|t{{2!$9)"EFF{{{3H# %)!&*kk#$'	N!KK++H5
   ((4HHOOJ/ 54  ^^44T:F'-CKK$W''/ ((4HHOOJ/ 54 e  !'}F9+RsK, 5444  	#K=ykA3G	
 ((4HHOON3 544 V ! %29+RsC& 54  WT2!$=i[1#"NOUVVW 54 ((4HHOOJ/ 544 s  
7S S !7T 3 S-T  S9BW> V  -W> 	 V#32W> &V/ W>  W2	S*S%%S*-S6	9T		T(T##T((T+ +U= U0'	U=0U95U= 	V 	VV  W> #V,	/	W/82W**W//W> 2W;	>Y Y:	YYYc                   ddl }ddlm} ddlm} ddlm} ddlm} ddl	m
} ddlm} dd	lm} dd
lm}	 ddlm}
 |	|||f}g }t'        |       D ]v  }|j)                  d      r	 t+        | |      }t/        ||      r|j1                  |       A ||      }|Lt/        ||
      r|j2                  |j2                  nd}|	j5                  ||j6                  |j8                  |j:                  |j<                  |j>                  |j@                  |jB                  |jD                  |jF                  ||jH                  |jJ                  |jL                  |jN                  |jP                        }|j1                  |       2t/        ||      r|j2                  |j2                  nd}d|jR                  v xr d|jR                  v } ||      }tU        |jW                  |      jX                        }|s|r|j5                  ||jR                  |j6                  |j8                  |j:                  |j<                  |j>                  |jZ                  |j@                  |jD                  |jF                  ||jN                        }n|j5                  ||jR                  |j6                  |j8                  |j:                  |j<                  |j>                  |jZ                  |j@                  |jD                  |jF                  ||jN                        }|j1                  |       t/        ||      s|j2                  |j2                  nd}|j5                  ||j6                  |j8                  |j:                  |j<                  |j>                  |j@                  |jF                  ||jN                  
      }|j1                  |       y |S # t,        $ r Y w xY w)a  Extract all MCP components from a module.

    Scans all module attributes for instances of Tool, Resource,
    ResourceTemplate, or Prompt objects created by standalone decorators,
    or functions decorated with @tool/@resource/@prompt that have __fastmcp__ metadata.

    Args:
        module: The imported module to scan.

    Returns:
        List of component objects (Tool, Resource, ResourceTemplate, Prompt).
    r   N)get_fastmcp_meta)Prompt)
PromptMeta)Resource)ResourceMeta)ResourceTemplate)without_injected_parameters)Tool)ToolMetarX   F)r!   versiontitledescriptioniconstagsoutput_schemar   metataskexclude_args
serializertimeoutauthrun_in_thread{})fnuri_templater!   r   r   r   r   	mime_typer   r   r   r   r   )r   urir!   r   r   r   r   r   r   r   r   r   r   )	r!   r   r   r   r   r   r   r   r   ).inspectfastmcp.decoratorsr~   fastmcp.prompts.baser   fastmcp.prompts.function_promptr   fastmcp.resources.baser   #fastmcp.resources.function_resourcer   fastmcp.resources.templater   fastmcp.server.dependenciesr   fastmcp.tools.baser   fastmcp.tools.function_toolr   dir
startswithrD   AttributeError
isinstancer$   r   from_functionr!   r   r   r   r   r   r   r   r   r   r   r   r   r   r   bool	signature
parametersr   )rF   r   r~   r   r   r   r   r   r   r   r   component_typesr   r!   objr   resolved_tasktoolhas_uri_params
wrapper_fnhas_func_paramsresourceprompts                          r   extract_componentsr     s6    3+:/@;G'4X'7@O)+JF??3	&$'C
 c?+c"  $$)-1YY-B		)) LL** $ 0 0**"&"4"4 $ 0 0&!%!2!2# LL"&"4"4! * $ !!$'D,/-1YY-B		!$!DSDHH_8=
"&w'8'8'D'O'O"P!_/==%)XX!YY $"jj$($4$4"jj"&..!YY$($4$4!YY*!YY  >  H   (55 HH!YY $"jj$($4$4"jj"&..!YY$($4$4!YY*!YY  6  H !!(+D*--1YY-B		-- LL** $ 0 0**& .  !!&)y | o  		s   %O

	OOc                   t               }t        |       D ]?  }	 t        ||       }t        |      }|D ]  }|j                  j                  ||f       ! A |S # t        $ r"}t	        |      |j
                  |<   Y d}~jd}~ww xY w)a  Discover files, import modules, and extract components.

    This is the main entry point for filesystem-based discovery.

    Args:
        root: Root directory to scan.

    Returns:
        DiscoveryResult with components and any failed files.

    Note:
        Files that fail to import are tracked in failed_files, not logged.
        The caller is responsible for logging/handling failures.
        Files with no components are silently skipped.
    )ro   N)	r   r)   r|   rm   rN   r   r   r   r$   )r&   resultr/   rF   rw   r   	components          r   discover_and_importr     s      F#D)		,YdKF
 (/
#I$$i%;< $ * M  	-0VF	*	s   A	B#B  B)r&   r   returnz
list[Path])r+   r   r   r   r?   )r/   r   r0   Path | Noner   r   )r/   r   r2   r   r   rN   )rF   r   r2   r   r   r   )r+   r   r   rN   )r/   r   ro   r   r   r   )rF   r   r   zlist[FastMCPComponent])r&   r   r   r   )!r   
__future__r   rd   rL   importlib.utilr]   rZ   dataclassesr   r   importlib.machineryr   pathlibr   typesr   fastmcp.utilities.componentsr	   fastmcp.utilities.loggingr
   r   loggerr   r)   r,   r3   r;   rH   rR   r|   r   r   r   r   r   <module>r      s    #    
 ( *   9 0	H	 @ @ @D0
:"H$ 37N0N0$/N0N0b{|r   