mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 07:09:11 +02:00
Compare commits
4 commits
main
...
codex/lazy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0a2831401 |
||
|
|
2906c74b83 |
||
|
|
0342e6cccd |
||
|
|
5c751510cc |
11 changed files with 609 additions and 93 deletions
|
|
@ -1,27 +1,55 @@
|
|||
from fastmcp import _install_hints
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from fastmcp import _install_hints
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .auth import (
|
||||
BearerAuth,
|
||||
ClientCredentialsOAuthProvider,
|
||||
OAuth,
|
||||
PrivateKeyJWTOAuthProvider,
|
||||
BearerAuth as BearerAuth,
|
||||
)
|
||||
from .client import Client
|
||||
from .auth import (
|
||||
ClientCredentialsOAuthProvider as ClientCredentialsOAuthProvider,
|
||||
)
|
||||
from .auth import (
|
||||
OAuth as OAuth,
|
||||
)
|
||||
from .auth import (
|
||||
PrivateKeyJWTOAuthProvider as PrivateKeyJWTOAuthProvider,
|
||||
)
|
||||
from .client import Client as Client
|
||||
from .transports import (
|
||||
ClientTransport,
|
||||
FastMCPTransport,
|
||||
NodeStdioTransport,
|
||||
NpxStdioTransport,
|
||||
PythonStdioTransport,
|
||||
SSETransport,
|
||||
StdioTransport,
|
||||
StreamableHttpTransport,
|
||||
UvStdioTransport,
|
||||
UvxStdioTransport,
|
||||
ClientTransport as ClientTransport,
|
||||
)
|
||||
from .transports import (
|
||||
FastMCPTransport as FastMCPTransport,
|
||||
)
|
||||
from .transports import (
|
||||
NodeStdioTransport as NodeStdioTransport,
|
||||
)
|
||||
from .transports import (
|
||||
NpxStdioTransport as NpxStdioTransport,
|
||||
)
|
||||
from .transports import (
|
||||
PythonStdioTransport as PythonStdioTransport,
|
||||
)
|
||||
from .transports import (
|
||||
SSETransport as SSETransport,
|
||||
)
|
||||
from .transports import (
|
||||
StdioTransport as StdioTransport,
|
||||
)
|
||||
from .transports import (
|
||||
StreamableHttpTransport as StreamableHttpTransport,
|
||||
)
|
||||
from .transports import (
|
||||
UvStdioTransport as UvStdioTransport,
|
||||
)
|
||||
from .transports import (
|
||||
UvxStdioTransport as UvxStdioTransport,
|
||||
)
|
||||
except ImportError as exc:
|
||||
raise ImportError(_install_hints.CLIENT_SUPPORT) from exc
|
||||
|
||||
__all__ = [
|
||||
"BearerAuth",
|
||||
|
|
@ -40,3 +68,35 @@ __all__ = [
|
|||
"UvStdioTransport",
|
||||
"UvxStdioTransport",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"BearerAuth": (".auth", "BearerAuth"),
|
||||
"Client": (".client", "Client"),
|
||||
"ClientCredentialsOAuthProvider": (
|
||||
".auth",
|
||||
"ClientCredentialsOAuthProvider",
|
||||
),
|
||||
"ClientTransport": (".transports", "ClientTransport"),
|
||||
"FastMCPTransport": (".transports", "FastMCPTransport"),
|
||||
"NodeStdioTransport": (".transports", "NodeStdioTransport"),
|
||||
"NpxStdioTransport": (".transports", "NpxStdioTransport"),
|
||||
"OAuth": (".auth", "OAuth"),
|
||||
"PrivateKeyJWTOAuthProvider": (".auth", "PrivateKeyJWTOAuthProvider"),
|
||||
"PythonStdioTransport": (".transports", "PythonStdioTransport"),
|
||||
"SSETransport": (".transports", "SSETransport"),
|
||||
"StdioTransport": (".transports", "StdioTransport"),
|
||||
"StreamableHttpTransport": (".transports", "StreamableHttpTransport"),
|
||||
"UvStdioTransport": (".transports", "UvStdioTransport"),
|
||||
"UvxStdioTransport": (".transports", "UvxStdioTransport"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
try:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
except ImportError as exc:
|
||||
raise ImportError(_install_hints.CLIENT_SUPPORT) from exc
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
from .bearer import BearerAuth
|
||||
from .client_credentials import (
|
||||
ClientCredentialsOAuthProvider,
|
||||
PrivateKeyJWTOAuthProvider,
|
||||
SignedJWTParameters,
|
||||
static_assertion_provider,
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
from .oauth import OAuth
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .bearer import BearerAuth as BearerAuth
|
||||
from .client_credentials import (
|
||||
ClientCredentialsOAuthProvider as ClientCredentialsOAuthProvider,
|
||||
)
|
||||
from .client_credentials import (
|
||||
PrivateKeyJWTOAuthProvider as PrivateKeyJWTOAuthProvider,
|
||||
)
|
||||
from .client_credentials import SignedJWTParameters as SignedJWTParameters
|
||||
from .client_credentials import (
|
||||
static_assertion_provider as static_assertion_provider,
|
||||
)
|
||||
from .oauth import OAuth as OAuth
|
||||
|
||||
__all__ = [
|
||||
"BearerAuth",
|
||||
|
|
@ -15,3 +27,29 @@ __all__ = [
|
|||
"SignedJWTParameters",
|
||||
"static_assertion_provider",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"BearerAuth": (".bearer", "BearerAuth"),
|
||||
"ClientCredentialsOAuthProvider": (
|
||||
".client_credentials",
|
||||
"ClientCredentialsOAuthProvider",
|
||||
),
|
||||
"OAuth": (".oauth", "OAuth"),
|
||||
"PrivateKeyJWTOAuthProvider": (
|
||||
".client_credentials",
|
||||
"PrivateKeyJWTOAuthProvider",
|
||||
),
|
||||
"SignedJWTParameters": (".client_credentials", "SignedJWTParameters"),
|
||||
"static_assertion_provider": (
|
||||
".client_credentials",
|
||||
"static_assertion_provider",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mcp.server.mcpserver import MCPServer as SDKServer
|
||||
|
||||
from fastmcp.client.transports.base import (
|
||||
ClientTransport,
|
||||
ClientTransportT,
|
||||
SessionKwargs,
|
||||
from fastmcp.client.transports.base import ClientTransport as ClientTransport
|
||||
from fastmcp.client.transports.base import ClientTransportT as ClientTransportT
|
||||
from fastmcp.client.transports.base import SessionKwargs as SessionKwargs
|
||||
from fastmcp.client.transports.config import (
|
||||
MCPConfigTransport as MCPConfigTransport,
|
||||
)
|
||||
from fastmcp.client.transports.config import MCPConfigTransport
|
||||
from fastmcp.client.transports.http import StreamableHttpTransport
|
||||
from fastmcp.client.transports.inference import infer_transport
|
||||
from fastmcp.client.transports.sse import SSETransport
|
||||
from fastmcp.client.transports.memory import FastMCPTransport
|
||||
from fastmcp.client.transports.http import (
|
||||
StreamableHttpTransport as StreamableHttpTransport,
|
||||
)
|
||||
from fastmcp.client.transports.inference import infer_transport as infer_transport
|
||||
from fastmcp.client.transports.memory import FastMCPTransport as FastMCPTransport
|
||||
from fastmcp.client.transports.sse import SSETransport as SSETransport
|
||||
from fastmcp.client.transports.stdio import (
|
||||
FastMCPStdioTransport,
|
||||
NodeStdioTransport,
|
||||
NpxStdioTransport,
|
||||
PythonStdioTransport,
|
||||
StdioTransport,
|
||||
UvStdioTransport,
|
||||
UvxStdioTransport,
|
||||
FastMCPStdioTransport as FastMCPStdioTransport,
|
||||
)
|
||||
from fastmcp.client.transports.stdio import NodeStdioTransport as NodeStdioTransport
|
||||
from fastmcp.client.transports.stdio import NpxStdioTransport as NpxStdioTransport
|
||||
from fastmcp.client.transports.stdio import (
|
||||
PythonStdioTransport as PythonStdioTransport,
|
||||
)
|
||||
from fastmcp.client.transports.stdio import StdioTransport as StdioTransport
|
||||
from fastmcp.client.transports.stdio import UvStdioTransport as UvStdioTransport
|
||||
from fastmcp.client.transports.stdio import UvxStdioTransport as UvxStdioTransport
|
||||
|
||||
__all__ = [
|
||||
"ClientTransport",
|
||||
|
|
@ -34,3 +46,48 @@ __all__ = [
|
|||
"UvxStdioTransport",
|
||||
"infer_transport",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"ClientTransport": ("fastmcp.client.transports.base", "ClientTransport"),
|
||||
"ClientTransportT": ("fastmcp.client.transports.base", "ClientTransportT"),
|
||||
"FastMCPStdioTransport": (
|
||||
"fastmcp.client.transports.stdio",
|
||||
"FastMCPStdioTransport",
|
||||
),
|
||||
"FastMCPTransport": ("fastmcp.client.transports.memory", "FastMCPTransport"),
|
||||
"MCPConfigTransport": (
|
||||
"fastmcp.client.transports.config",
|
||||
"MCPConfigTransport",
|
||||
),
|
||||
"NodeStdioTransport": (
|
||||
"fastmcp.client.transports.stdio",
|
||||
"NodeStdioTransport",
|
||||
),
|
||||
"NpxStdioTransport": (
|
||||
"fastmcp.client.transports.stdio",
|
||||
"NpxStdioTransport",
|
||||
),
|
||||
"PythonStdioTransport": (
|
||||
"fastmcp.client.transports.stdio",
|
||||
"PythonStdioTransport",
|
||||
),
|
||||
"SDKServer": ("mcp.server.mcpserver", "MCPServer"),
|
||||
"SSETransport": ("fastmcp.client.transports.sse", "SSETransport"),
|
||||
"SessionKwargs": ("fastmcp.client.transports.base", "SessionKwargs"),
|
||||
"StdioTransport": ("fastmcp.client.transports.stdio", "StdioTransport"),
|
||||
"StreamableHttpTransport": (
|
||||
"fastmcp.client.transports.http",
|
||||
"StreamableHttpTransport",
|
||||
),
|
||||
"UvStdioTransport": ("fastmcp.client.transports.stdio", "UvStdioTransport"),
|
||||
"UvxStdioTransport": ("fastmcp.client.transports.stdio", "UvxStdioTransport"),
|
||||
"infer_transport": ("fastmcp.client.transports.inference", "infer_transport"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,18 @@
|
|||
from .function_prompt import FunctionPrompt, prompt
|
||||
from .base import Message, Prompt, PromptArgument, PromptMessage, PromptResult
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .base import Message as Message
|
||||
from .base import Prompt as Prompt
|
||||
from .base import PromptArgument as PromptArgument
|
||||
from .base import PromptMessage as PromptMessage
|
||||
from .base import PromptResult as PromptResult
|
||||
from .function_prompt import FunctionPrompt as FunctionPrompt
|
||||
from .function_prompt import prompt as prompt
|
||||
|
||||
__all__ = [
|
||||
"FunctionPrompt",
|
||||
|
|
@ -10,3 +23,21 @@ __all__ = [
|
|||
"PromptResult",
|
||||
"prompt",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"FunctionPrompt": (".function_prompt", "FunctionPrompt"),
|
||||
"Message": (".base", "Message"),
|
||||
"Prompt": (".base", "Prompt"),
|
||||
"PromptArgument": (".base", "PromptArgument"),
|
||||
"PromptMessage": (".base", "PromptMessage"),
|
||||
"PromptResult": (".base", "PromptResult"),
|
||||
"prompt": (".function_prompt", "prompt"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,24 @@
|
|||
from .function_resource import FunctionResource, resource
|
||||
from .base import Resource, ResourceContent, ResourceResult
|
||||
from .security import ResourceSecurity
|
||||
from .template import ResourceTemplate
|
||||
from .types import (
|
||||
BinaryResource,
|
||||
DirectoryResource,
|
||||
FileResource,
|
||||
HttpResource,
|
||||
TextResource,
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .base import Resource as Resource
|
||||
from .base import ResourceContent as ResourceContent
|
||||
from .base import ResourceResult as ResourceResult
|
||||
from .function_resource import FunctionResource as FunctionResource
|
||||
from .function_resource import resource as resource
|
||||
from .security import ResourceSecurity as ResourceSecurity
|
||||
from .template import ResourceTemplate as ResourceTemplate
|
||||
from .types import BinaryResource as BinaryResource
|
||||
from .types import DirectoryResource as DirectoryResource
|
||||
from .types import FileResource as FileResource
|
||||
from .types import HttpResource as HttpResource
|
||||
from .types import TextResource as TextResource
|
||||
|
||||
__all__ = [
|
||||
"BinaryResource",
|
||||
"DirectoryResource",
|
||||
|
|
@ -24,3 +33,26 @@ __all__ = [
|
|||
"TextResource",
|
||||
"resource",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"BinaryResource": (".types", "BinaryResource"),
|
||||
"DirectoryResource": (".types", "DirectoryResource"),
|
||||
"FileResource": (".types", "FileResource"),
|
||||
"FunctionResource": (".function_resource", "FunctionResource"),
|
||||
"HttpResource": (".types", "HttpResource"),
|
||||
"Resource": (".base", "Resource"),
|
||||
"ResourceContent": (".base", "ResourceContent"),
|
||||
"ResourceResult": (".base", "ResourceResult"),
|
||||
"ResourceSecurity": (".security", "ResourceSecurity"),
|
||||
"ResourceTemplate": (".template", "ResourceTemplate"),
|
||||
"TextResource": (".types", "TextResource"),
|
||||
"resource": (".function_resource", "resource"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
from .authorization import AuthMiddleware
|
||||
from .middleware import (
|
||||
CallNext,
|
||||
Middleware,
|
||||
MiddlewareContext,
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
from .ping import PingMiddleware
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .authorization import AuthMiddleware as AuthMiddleware
|
||||
from .middleware import CallNext as CallNext
|
||||
from .middleware import Middleware as Middleware
|
||||
from .middleware import MiddlewareContext as MiddlewareContext
|
||||
from .ping import PingMiddleware as PingMiddleware
|
||||
|
||||
__all__ = [
|
||||
"AuthMiddleware",
|
||||
|
|
@ -13,3 +19,19 @@ __all__ = [
|
|||
"MiddlewareContext",
|
||||
"PingMiddleware",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"AuthMiddleware": (".authorization", "AuthMiddleware"),
|
||||
"CallNext": (".middleware", "CallNext"),
|
||||
"Middleware": (".middleware", "Middleware"),
|
||||
"MiddlewareContext": (".middleware", "MiddlewareContext"),
|
||||
"PingMiddleware": (".ping", "PingMiddleware"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -27,20 +27,32 @@ Example:
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.server.providers.aggregate import AggregateProvider
|
||||
from fastmcp.server.providers.base import Provider
|
||||
from fastmcp.server.providers.fastmcp_provider import FastMCPProvider
|
||||
from fastmcp.server.providers.filesystem import FileSystemProvider
|
||||
from fastmcp.server.providers.local_provider import LocalProvider
|
||||
from fastmcp.server.providers.skills import (
|
||||
ClaudeSkillsProvider,
|
||||
SkillProvider,
|
||||
SkillsDirectoryProvider,
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastmcp.server.providers.aggregate import (
|
||||
AggregateProvider as AggregateProvider,
|
||||
)
|
||||
from fastmcp.server.providers.base import Provider as Provider
|
||||
from fastmcp.server.providers.fastmcp_provider import (
|
||||
FastMCPProvider as FastMCPProvider,
|
||||
)
|
||||
from fastmcp.server.providers.filesystem import (
|
||||
FileSystemProvider as FileSystemProvider,
|
||||
)
|
||||
from fastmcp.server.providers.local_provider import LocalProvider as LocalProvider
|
||||
from fastmcp.server.providers.openapi import OpenAPIProvider as OpenAPIProvider
|
||||
from fastmcp.server.providers.proxy import ProxyProvider as ProxyProvider
|
||||
from fastmcp.server.providers.skills import (
|
||||
ClaudeSkillsProvider as ClaudeSkillsProvider,
|
||||
)
|
||||
from fastmcp.server.providers.skills import SkillProvider as SkillProvider
|
||||
from fastmcp.server.providers.skills import (
|
||||
SkillsDirectoryProvider as SkillsDirectoryProvider,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AggregateProvider",
|
||||
|
|
@ -55,15 +67,35 @@ __all__ = [
|
|||
"SkillsDirectoryProvider",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"AggregateProvider": ("fastmcp.server.providers.aggregate", "AggregateProvider"),
|
||||
"ClaudeSkillsProvider": (
|
||||
"fastmcp.server.providers.skills",
|
||||
"ClaudeSkillsProvider",
|
||||
),
|
||||
"FastMCPProvider": (
|
||||
"fastmcp.server.providers.fastmcp_provider",
|
||||
"FastMCPProvider",
|
||||
),
|
||||
"FileSystemProvider": (
|
||||
"fastmcp.server.providers.filesystem",
|
||||
"FileSystemProvider",
|
||||
),
|
||||
"LocalProvider": ("fastmcp.server.providers.local_provider", "LocalProvider"),
|
||||
"OpenAPIProvider": ("fastmcp.server.providers.openapi", "OpenAPIProvider"),
|
||||
"Provider": ("fastmcp.server.providers.base", "Provider"),
|
||||
"ProxyProvider": ("fastmcp.server.providers.proxy", "ProxyProvider"),
|
||||
"SkillProvider": ("fastmcp.server.providers.skills", "SkillProvider"),
|
||||
"SkillsDirectoryProvider": (
|
||||
"fastmcp.server.providers.skills",
|
||||
"SkillsDirectoryProvider",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
"""Lazy import for providers to avoid circular imports."""
|
||||
if name == "ProxyProvider":
|
||||
from fastmcp.server.providers.proxy import ProxyProvider
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
return ProxyProvider
|
||||
if name == "OpenAPIProvider":
|
||||
from fastmcp.server.providers.openapi import OpenAPIProvider
|
||||
|
||||
return OpenAPIProvider
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -23,12 +23,31 @@ from __future__ import annotations
|
|||
from collections.abc import Awaitable, Sequence
|
||||
from typing import TYPE_CHECKING, Protocol
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
from fastmcp.utilities.versions import VersionSpec
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastmcp.prompts.base import Prompt
|
||||
from fastmcp.resources.base import Resource
|
||||
from fastmcp.resources.template import ResourceTemplate
|
||||
from fastmcp.server.transforms.namespace import Namespace as Namespace
|
||||
from fastmcp.server.transforms.prompts_as_tools import (
|
||||
PromptsAsTools as PromptsAsTools,
|
||||
)
|
||||
from fastmcp.server.transforms.resources_as_tools import (
|
||||
ResourcesAsTools as ResourcesAsTools,
|
||||
)
|
||||
from fastmcp.server.transforms.tool_transform import (
|
||||
ToolTransform as ToolTransform,
|
||||
)
|
||||
from fastmcp.server.transforms.version_filter import (
|
||||
VersionFilter as VersionFilter,
|
||||
)
|
||||
from fastmcp.server.transforms.visibility import Visibility as Visibility
|
||||
from fastmcp.server.transforms.visibility import is_enabled as is_enabled
|
||||
from fastmcp.tools.base import Tool
|
||||
|
||||
|
||||
|
|
@ -219,14 +238,6 @@ class Transform:
|
|||
return await call_next(name, version=version)
|
||||
|
||||
|
||||
# Re-export built-in transforms (must be after Transform class to avoid circular imports)
|
||||
from fastmcp.server.transforms.visibility import Visibility, is_enabled # noqa: E402
|
||||
from fastmcp.server.transforms.namespace import Namespace # noqa: E402
|
||||
from fastmcp.server.transforms.prompts_as_tools import PromptsAsTools # noqa: E402
|
||||
from fastmcp.server.transforms.resources_as_tools import ResourcesAsTools # noqa: E402
|
||||
from fastmcp.server.transforms.tool_transform import ToolTransform # noqa: E402
|
||||
from fastmcp.server.transforms.version_filter import VersionFilter # noqa: E402
|
||||
|
||||
__all__ = [
|
||||
"Namespace",
|
||||
"PromptsAsTools",
|
||||
|
|
@ -238,3 +249,33 @@ __all__ = [
|
|||
"Visibility",
|
||||
"is_enabled",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"Namespace": ("fastmcp.server.transforms.namespace", "Namespace"),
|
||||
"PromptsAsTools": (
|
||||
"fastmcp.server.transforms.prompts_as_tools",
|
||||
"PromptsAsTools",
|
||||
),
|
||||
"ResourcesAsTools": (
|
||||
"fastmcp.server.transforms.resources_as_tools",
|
||||
"ResourcesAsTools",
|
||||
),
|
||||
"ToolTransform": (
|
||||
"fastmcp.server.transforms.tool_transform",
|
||||
"ToolTransform",
|
||||
),
|
||||
"VersionFilter": (
|
||||
"fastmcp.server.transforms.version_filter",
|
||||
"VersionFilter",
|
||||
),
|
||||
"Visibility": ("fastmcp.server.transforms.visibility", "Visibility"),
|
||||
"is_enabled": ("fastmcp.server.transforms.visibility", "is_enabled"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
from .function_tool import FunctionTool, tool
|
||||
from .base import InputRequiredToolResult, Tool, ToolResult
|
||||
from .tool_transform import forward, forward_raw
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastmcp.utilities.lazy_imports import (
|
||||
list_module_attributes,
|
||||
resolve_lazy_import,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .base import InputRequiredToolResult as InputRequiredToolResult
|
||||
from .base import Tool as Tool
|
||||
from .base import ToolResult as ToolResult
|
||||
from .function_tool import FunctionTool as FunctionTool
|
||||
from .function_tool import tool as tool
|
||||
from .tool_transform import forward as forward
|
||||
from .tool_transform import forward_raw as forward_raw
|
||||
|
||||
__all__ = [
|
||||
"FunctionTool",
|
||||
|
|
@ -11,3 +23,21 @@ __all__ = [
|
|||
"forward_raw",
|
||||
"tool",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"FunctionTool": (".function_tool", "FunctionTool"),
|
||||
"InputRequiredToolResult": (".base", "InputRequiredToolResult"),
|
||||
"Tool": (".base", "Tool"),
|
||||
"ToolResult": (".base", "ToolResult"),
|
||||
"forward": (".tool_transform", "forward"),
|
||||
"forward_raw": (".tool_transform", "forward_raw"),
|
||||
"tool": (".function_tool", "tool"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> object:
|
||||
return resolve_lazy_import(name, __name__, globals(), _LAZY_IMPORTS)
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return list_module_attributes(globals(), _LAZY_IMPORTS)
|
||||
|
|
|
|||
31
fastmcp_slim/fastmcp/utilities/lazy_imports.py
Normal file
31
fastmcp_slim/fastmcp/utilities/lazy_imports.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""Helpers for exposing public names without eagerly importing their modules."""
|
||||
|
||||
from collections.abc import Mapping
|
||||
from importlib import import_module
|
||||
from typing import Any
|
||||
|
||||
LazyImports = Mapping[str, tuple[str, str]]
|
||||
|
||||
|
||||
def resolve_lazy_import(
|
||||
name: str,
|
||||
package: str,
|
||||
namespace: dict[str, Any],
|
||||
lazy_imports: LazyImports,
|
||||
) -> object:
|
||||
"""Resolve and cache a lazily exported module attribute."""
|
||||
try:
|
||||
module_name, attr_name = lazy_imports[name]
|
||||
except KeyError:
|
||||
raise AttributeError(f"module {package!r} has no attribute {name!r}") from None
|
||||
|
||||
value = getattr(import_module(module_name, package), attr_name)
|
||||
namespace[name] = value
|
||||
return value
|
||||
|
||||
|
||||
def list_module_attributes(
|
||||
namespace: dict[str, Any], lazy_imports: LazyImports
|
||||
) -> list[str]:
|
||||
"""Include unresolved lazy exports in module introspection."""
|
||||
return sorted(namespace.keys() | lazy_imports.keys())
|
||||
142
tests/test_lazy_package_imports.py
Normal file
142
tests/test_lazy_package_imports.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
"""Fresh-interpreter guards for lazy public package exports."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("statement", "excluded_modules"),
|
||||
[
|
||||
(
|
||||
"from fastmcp.client import BearerAuth",
|
||||
(
|
||||
"fastmcp.client.auth.client_credentials",
|
||||
"fastmcp.client.auth.oauth",
|
||||
"fastmcp.client.client",
|
||||
"fastmcp.client.transports",
|
||||
),
|
||||
),
|
||||
(
|
||||
"from fastmcp.client.transports import ClientTransport",
|
||||
(
|
||||
"fastmcp.client.transports.config",
|
||||
"fastmcp.client.transports.http",
|
||||
"fastmcp.client.transports.inference",
|
||||
"fastmcp.client.transports.memory",
|
||||
"fastmcp.client.transports.sse",
|
||||
"fastmcp.client.transports.stdio",
|
||||
),
|
||||
),
|
||||
(
|
||||
"from fastmcp.tools import Tool",
|
||||
("fastmcp.tools.function_tool", "fastmcp.tools.tool_transform"),
|
||||
),
|
||||
(
|
||||
"from fastmcp.resources import Resource",
|
||||
(
|
||||
"fastmcp.resources.function_resource",
|
||||
"fastmcp.resources.security",
|
||||
"fastmcp.resources.template",
|
||||
"fastmcp.resources.types",
|
||||
),
|
||||
),
|
||||
(
|
||||
"from fastmcp.prompts import Prompt",
|
||||
("fastmcp.prompts.function_prompt",),
|
||||
),
|
||||
(
|
||||
"from fastmcp.server.providers import Provider",
|
||||
(
|
||||
"fastmcp.server.providers.aggregate",
|
||||
"fastmcp.server.providers.fastmcp_provider",
|
||||
"fastmcp.server.providers.filesystem",
|
||||
"fastmcp.server.providers.local_provider",
|
||||
"fastmcp.server.providers.skills",
|
||||
),
|
||||
),
|
||||
(
|
||||
"from fastmcp.server.middleware import Middleware",
|
||||
(
|
||||
"fastmcp.server.middleware.authorization",
|
||||
"fastmcp.server.middleware.ping",
|
||||
),
|
||||
),
|
||||
(
|
||||
"from fastmcp.server.transforms import Transform",
|
||||
(
|
||||
"fastmcp.server.transforms.namespace",
|
||||
"fastmcp.server.transforms.prompts_as_tools",
|
||||
"fastmcp.server.transforms.resources_as_tools",
|
||||
"fastmcp.server.transforms.tool_transform",
|
||||
"fastmcp.server.transforms.version_filter",
|
||||
"fastmcp.server.transforms.visibility",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.subprocess_heavy
|
||||
def test_narrow_import_does_not_load_sibling_implementations(
|
||||
statement: str, excluded_modules: tuple[str, ...]
|
||||
) -> None:
|
||||
script = textwrap.dedent(
|
||||
f"""
|
||||
import sys
|
||||
|
||||
{statement}
|
||||
|
||||
excluded = {excluded_modules!r}
|
||||
loaded = [
|
||||
name
|
||||
for name in sys.modules
|
||||
if any(name == root or name.startswith(f"{{root}}.") for root in excluded)
|
||||
]
|
||||
assert not loaded, loaded
|
||||
"""
|
||||
)
|
||||
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", script],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
|
||||
@pytest.mark.subprocess_heavy
|
||||
def test_all_public_package_exports_resolve() -> None:
|
||||
script = textwrap.dedent(
|
||||
"""
|
||||
import importlib
|
||||
|
||||
packages = (
|
||||
"fastmcp.client",
|
||||
"fastmcp.client.auth",
|
||||
"fastmcp.client.transports",
|
||||
"fastmcp.prompts",
|
||||
"fastmcp.resources",
|
||||
"fastmcp.server.middleware",
|
||||
"fastmcp.server.providers",
|
||||
"fastmcp.server.transforms",
|
||||
"fastmcp.tools",
|
||||
)
|
||||
for package_name in packages:
|
||||
package = importlib.import_module(package_name)
|
||||
assert set(package.__all__) <= set(dir(package))
|
||||
for export in package.__all__:
|
||||
assert getattr(package, export) is not None, (package_name, export)
|
||||
"""
|
||||
)
|
||||
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", script],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
Loading…
Add table
Add a link
Reference in a new issue