
    $j47                        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  ee          Ze	 G d	 d
                      Zd!dZd"dZd#d$dZd%dZ	 d#d&dZd'dZd(d ZdS ))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)Path)
ModuleType)FastMCPComponent)
get_loggerc                  X    e Zd ZU dZ ee          Zded<    ee          Z	ded<   dS )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        u/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/fastmcp/server/providers/filesystem_discovery.pyr   r      sV         )) 7<eD6Q6Q6QJQQQQ$)E$$?$?$?L??????r   r   rootr   return
list[Path]c                4   |                                  sg S |                                 s| j        dk    r| j        dk    r| gS g S g }|                     d          D ]-}|j        dk    rd|j        v r|                    |           .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)r   filespaths      r   discover_filesr*   "   s     ;;== 	;;== ;%DI$>$>6M	E

6""  9%%DJ&&T %==r   	directoryboolc                0    | dz                                   S )z;Check if a directory is a Python package (has __init__.py).r   )r    )r+   s    r   _is_package_dirr.   D   s    %--///r   	file_pathstop_atPath | Nonec                    | j         }d}||j         k    r3|||j         k    rn%t          |          r
|}|j         }nn||j         k    3|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.   )r/   r0   currentpackage_roots       r   _find_package_rootr6   I   sk     GL
W^
#
#7gn#<#<7## 	"LnGG W^
#
# r   r5   strc                    |                      |j                  }t          |j                  }|d                             d          |d<   d                    |          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_tor3   r   r%   removesuffixjoin)r/   r5   relativer%   s       r   _compute_module_namer?   f   sT     $$\%899H  Eb	&&u--E"I88E??r   provider_rootr   c           	     
   |                                  } ||                                 }t          | |          }|t          | |          }t          |j                  }|t
          j        v}|r t
          j                            d|           	 |t
          j        v rwt          j
        t
          j        |                   |rQt          j        t                    5  t
          j                            |           ddd           S # 1 swxY w Y   S S t          j        |          |rQt          j        t                    5  t
          j                            |           ddd           S # 1 swxY w Y   S S # t           $ r}t!          d| d|  d|           |d}~ww xY w# |rQt          j        t                    5  t
          j                            |           ddd           w # 1 swxY w Y   w w xY w| j        }t          | j                  }t
          j                            |          }	|	vt'          |	dd          t          |           k    rTd| d	t)          j        t          |                                                                                     dd
          }n|}|t
          j        v}|r t
          j                            d|           	 t          j                            ||           }
|
|
j        t!          d|            t
          j                            |          }	|	|
|	_        |
j        |	_        t          |           |	_        	 |
j                            |	           n(# t>          $ r}t!          d|  d|           |d}~ww xY w|	|rQt          j        t                    5  t
          j                            |           ddd           S # 1 swxY w Y   S S t          j                             |
          }|t
          j        |<   	 |
j                            |           nH# t>          $ r;}t
          j        !                    |d           t!          d|  d|           |d}~ww xY w||rQt          j        t                    5  t
          j                            |           ddd           S # 1 swxY w Y   S S # |rQt          j        t                    5  t
          j                            |           ddd           w # 1 swxY w 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   r   zFailed to import z from z: __file__	_fastmcp__   zCannot load spec for zFailed to reload module zFailed to execute module )"resolver6   r?   r7   r3   sysr)   insertmodules	importlibreload
contextlibsuppress
ValueErrorremoveimport_moduleImportErrorstemgetgetattrhashlibsha1encode	hexdigestutilspec_from_file_locationloader__spec__
__loader__rB   exec_module	Exceptionmodule_from_specpop)r/   r@   r5   module_namepackage_parent
path_addederR   
parent_direxistingspecmodules               r   import_module_from_filerj   w   s   . !!##I %--// &iGGGL*9lCC \011#383
 	/HOOA~...	4ck)) 'K(@AA  4(44 4 4HOON3334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 44 *;77  4(44 4 4HOON3334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 44  	 	 	GKGGyGGAGG 	
  4(44 4 4HOON3334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 44
 ~)**
 ;??4((GHj$$G$G3L
 L
 %
 %
 fdeeW\#i..:O:O:Q:Q-R-R-\-\-^-^_b`b_b-ceeKKK
  sx/
 	+HOOAz***#	0>99+yQQD|t{2!"E)"E"EFFF{{33H# %)!&*k#$'	NN!K++H5555    %C9CCCC     0(44 0 0HOOJ///0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 ^44T::F'-CK$W''//// W W WT222!"Ni"N"N1"N"NOOUVVW
  0(44 0 0HOOJ///0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00z 0(44 0 0HOOJ///0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00s  1F    DD	D	F   E33E7	:E7	 
F(
F##F((F+ +H  G3'H 3G77H :G7;H (BS+ ,N S+ 
N,N''N,,S+  O77O;	>O;	.S+ 3Q S+ 
R6RRS+ 2 SS"	%S"	+U  T3'U 3T77U :T7;U ri   list[FastMCPComponent]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 ]}|                    d          r	 t+          | |          }n# t,          $ r Y 7w xY wt/          ||          r|                    |           a ||          }|Et/          ||
          r|j        |j        nd}|	                    ||j        |j        |j        |j        |j        |j         |j!        |j"        |j#        ||j$        |j%        |j&                  }|                    |           t/          ||          r"|j        |j        nd}d|j'        v od|j'        v } ||          }tQ          |)                    |          j*                  }|s|rZ|                    ||j'        |j        |j        |j        |j        |j        |j+        |j         |j"        |j#        ||j&                  }nY|                    ||j'        |j        |j        |j        |j        |j        |j+        |j         |j"        |j#        ||j&                  }|                    |           8t/          ||          rl|j        |j        nd}|                    ||j        |j        |j        |j        |j        |j         |j#        ||j&        
  
        }|                    |           |S )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)ToolMetarD   F)r#   versiontitledescriptioniconstagsoutput_schemar   metataskexclude_args
serializerauth{})fnuri_templater#   rv   rw   rx   ry   	mime_typerz   r   r|   r}   r   )r   urir#   rv   rw   rx   ry   r   rz   r   r|   r}   r   )	r#   rv   rw   rx   ry   rz   r|   r}   r   ),inspectfastmcp.decoratorsrm   fastmcp.prompts.basern   fastmcp.prompts.function_promptro   fastmcp.resources.baserp   #fastmcp.resources.function_resourcerq   fastmcp.resources.templaterr   fastmcp.server.dependenciesrs   fastmcp.tools.basert   fastmcp.tools.function_toolru   dir
startswithrT   AttributeError
isinstancer&   r}   from_functionr#   rv   rw   rx   ry   rz   r{   r   r|   r~   r   r   r   r,   	signature
parametersr   )ri   r   rm   rn   ro   rp   rq   rr   rs   rt   ru   component_typesr   r#   objr|   resolved_tasktoolhas_uri_params
wrapper_fnhas_func_paramsresourceprompts                          r   extract_componentsr      s    NNN333333++++++:::::://////@@@@@@;;;;;;GGGGGG''''''444444X'7@O)+JF Z* Z*??3 		&$''CC 	 	 	H	 c?++ 	c"""  $$$)) H*-1Y-B		)) L* $ 0*"&"4 $ 0&!%!2# *    !!$''''D,// 5*-1Y-B		!$!DSDH_88==
"&w'8'8'D'D'O"P"P! _ /==%)X!Y $"j$($4"j"&.!Y$($4!Y*!Y  >    HH   (55 H!Y $"j$($4"j"&.!Y$($4!Y*!Y  6    H !!(++++D*-- *-1Y-B		-- L* $ 0*& .   !!&)))s   ,A==
B
	B
c                (   t                      }t          |           D ]s}	 t          ||           }n.# t          $ r!}t	          |          |j        |<   Y d}~;d}~ww xY wt          |          }|D ]}|j                            ||f           t|S )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.
    )r@   N)	r   r*   rj   r_   r7   r   r   r   r&   )r   resultr/   ri   re   r   	components          r   discover_and_importr   g  s      F#D)) 	= 	=		,YdKKKFF 	 	 	-0VVF	*HHHH	 (//
# 	= 	=I$$i%;<<<<	= Ms   3
AAA)r   r   r   r   )r+   r   r   r,   )N)r/   r   r0   r1   r   r1   )r/   r   r5   r   r   r7   )r/   r   r@   r1   r   r   )ri   r   r   rk   )r   r   r   r   )r   
__future__r   rL   rU   importlib.utilrJ   rG   dataclassesr   r   pathlibr   typesr   fastmcp.utilities.componentsr   fastmcp.utilities.loggingr	   r   loggerr   r*   r.   r6   r?   rj   r   r   r   r   r   <module>r      s    # " " " " "          



 ( ( ( ( ( ( ( (             9 9 9 9 9 9 0 0 0 0 0 0	H		 @ @ @ @ @ @ @ @   D0 0 0 0
    :   $ 37q0 q0 q0 q0 q0hy y y yx     r   