
    i+                        d Z ddlm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ZddZ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)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/bowang/.openclaw/workspace/ChatDev/.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+   B   s    %--//r   c                    | j                   }d}||j                   k7  r-t        |      r|}|j                   }n	 |S ||j                   k7  r-|S )zFind the root of the package containing this file.

    Walks up the directory tree until we find a directory without __init__.py.

    Returns:
        The package root directory, or None if not in a package.
    N)parentr+   )	file_pathcurrentpackage_roots      r   _find_package_rootr1   G   sU     GL
W^^
#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.   r0   relativer"   s       r   _compute_module_namer9   \   sN     $$\%8%89H Eb	&&u-E"I88E?r   c           	        | j                         } t        |       }|t        | |      }t        |j                        }|t
        j                  vr t
        j                  j                  d|       	 |t
        j                  v r&t        j                  t
        j                  |         S t        j                  |      S | j                  }t        | j                        }|t
        j                  vr t
        j                  j                  d|       t        j                  j                  ||       }||j                   t        d|        t        j                  j#                  |      }|t
        j                  |<   	 |j                   j%                  |       |S # t        $ r}t        d| d|  d|       |d}~ww xY w# t&        $ r7}t
        j                  j)                  |d       t        d|  d|       |d}~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.

    Args:
        file_path: Path to the Python file.

    Returns:
        The imported module.

    Raises:
        ImportError: If the module cannot be imported.
    Nr   zFailed to import z from z: zCannot load spec for zFailed to execute module )resolver1   r9   strr-   sysr'   insertmodules	importlibreloadimport_moduleImportErrorstemutilspec_from_file_locationloadermodule_from_specexec_module	Exceptionpop)r.   r0   module_namepackage_parente
parent_dirspecmodules           r   import_module_from_filerR   m   s     !!#I &i0L*9lC \001)HHOOA~.	ckk) ''K(@AA**;77  nn ))*
SXX%HHOOAz*~~55k9M<4;;. 5i[ABB006#)K 	SKK##F+ 7  	#K=ykA3G	,  	SKKOOK. 9)BqcJKQRR	Ss6   27F *F G 	G'F<<G	H2G??Hc                0   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 ]4  }|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                        }|j1                  |       t/        ||      r~|j2                  |j2                  nd}d|jL                  v xr d|jL                  v } ||      }tO        |jQ                  |      jR                        }|s|r|j5                  ||jL                  |j6                  |j8                  |j:                  |j<                  |jT                  |j>                  |jB                  |jD                  ||jJ                        }n|j5                  ||jL                  |j6                  |j8                  |j:                  |j<                  |jT                  |j>                  |jB                  |jD                  ||jJ                        }|j1                  |       t/        ||      s|j2                  |j2                  nd}|j5                  ||j6                  |j8                  |j:                  |j<                  |j>                  |jD                  ||jJ                  	      }|j1                  |       7 |S # t,        $ r Y Fw 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)
PromptMeta)Prompt)ResourceMeta)Resource)ResourceTemplate)without_injected_parameters)ToolMeta)Tool_F)r    titledescriptioniconstagsoutput_schemar   metataskexclude_args
serializerauth{})fnuri_templater    r^   r_   r`   	mime_typera   r   rc   rd   rg   )rj   urir    r^   r_   r`   rl   ra   r   rc   rd   rg   )r    r^   r_   r`   ra   rc   rd   rg   )+inspectfastmcp.decoratorsrT   fastmcp.prompts.function_promptrU   fastmcp.prompts.promptrV   #fastmcp.resources.function_resourcerW   fastmcp.resources.resourcerX   fastmcp.resources.templaterY   fastmcp.server.dependenciesrZ   fastmcp.tools.function_toolr[   fastmcp.tools.toolr\   dir
startswithgetattrAttributeError
isinstancer#   rd   from_functionr    r^   r_   r`   ra   rb   r   rc   re   rf   rg   rm   bool	signature
parametersrl   )rQ   rn   rT   rU   rV   rW   rX   rY   rZ   r[   r\   component_typesr   r    objrc   resolved_tasktoolhas_uri_params
wrapper_fnhas_func_paramsresourceprompts                          r   extract_componentsr      s
    3:-@3;G4'X'7@O)+JF??3	&$'C
 c?+c"  $$)-1YY-B		))** $ 0 0**"&"4"4 $ 0 0&!%!2!2# *  !!$'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		--** $ 0 0**& . 
 !!&)m p c  		s   %N	NNc                ^   t               }t        |       D ]=  }	 t        |      }t        |      }|D ]  }|j                  j                  ||f       ! ? |S # t        $ r"}t	        |      |j
                  |<   Y d}~hd}~wt        $ r"}t	        |      |j
                  |<   Y d}~d}~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.
    N)
r   r(   rR   rC   r<   r   rJ   r   r   r#   )r%   resultr.   rQ   rN   r   	components          r   discover_and_importr   '  s      F#D)		,Y7F (/
#I$$i%;< $ * M  	-0VF	* 	-0VF	*	s#   A	B,!A>>B,
B''B,)r%   r   returnz
list[Path])r*   r   r   r~   )r.   r   r   zPath | None)r.   r   r0   r   r   r<   )r.   r   r   r   )rQ   r   r   zlist[FastMCPComponent])r%   r   r   r   )r   
__future__r   importlib.utilr@   r=   dataclassesr   r   pathlibr   typesr   fastmcp.utilities.componentsr   fastmcp.utilities.loggingr	   r   loggerr   r(   r+   r1   r9   rR   r   r   r   r   r   <module>r      sq    #  
 (   9 0	H	 @ @ @D0
*"?Dup r   