fastmcp/tests/test_lazy_package_imports.py
2026-08-02 09:59:37 -04:00

142 lines
4.2 KiB
Python

"""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