Merge pull request #3198 from jlowin/fix/ty-errors

Fix ty 0.0.17 diagnostics
This commit is contained in:
Jeremiah Lowin 2026-02-16 16:24:42 -05:00 committed by GitHub
commit 5dc2432950
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 465 additions and 387 deletions

View file

@ -378,7 +378,7 @@ async def run_with_reload(
# Watch for either: file changes OR process death
watch_task = asyncio.create_task(
anext(aiter(awatch(*watch_paths, watch_filter=_watch_filter)))
anext(aiter(awatch(*watch_paths, watch_filter=_watch_filter))) # ty: ignore[invalid-argument-type]
)
wait_task = asyncio.create_task(process.wait())
shutdown_task = asyncio.create_task(shutdown_event.wait())
@ -409,7 +409,7 @@ async def run_with_reload(
# Wait for file change or shutdown (avoid hot loop on crash)
watch_task = asyncio.create_task(
anext(aiter(awatch(*watch_paths, watch_filter=_watch_filter)))
anext(aiter(awatch(*watch_paths, watch_filter=_watch_filter))) # ty: ignore[invalid-argument-type]
)
shutdown_task = asyncio.create_task(shutdown_event.wait())
done, pending = await asyncio.wait(

View file

@ -99,9 +99,9 @@ class FileSystemSource(Source):
logger.error("Could not load module", extra={"file": str(file_path)})
sys.exit(1)
module = importlib.util.module_from_spec(spec) # type: ignore[arg-type]
module = importlib.util.module_from_spec(spec)
sys.modules["server_module"] = module # Register in sys.modules
spec.loader.exec_module(module) # type: ignore[union-attr]
spec.loader.exec_module(module)
return module

View file

@ -60,6 +60,7 @@ class TestClientToolTracing:
None,
)
assert client_span is not None
assert client_span.attributes is not None
# Standard MCP semantic conventions
assert client_span.attributes["mcp.method.name"] == "tools/call"
# Standard RPC semantic conventions
@ -119,6 +120,7 @@ class TestClientResourceTracing:
None,
)
assert client_span is not None
assert client_span.attributes is not None
# Standard MCP semantic conventions
assert client_span.attributes["mcp.method.name"] == "resources/read"
assert "data://" in str(client_span.attributes["mcp.resource.uri"])
@ -178,6 +180,7 @@ class TestClientPromptTracing:
None,
)
assert client_span is not None
assert client_span.attributes is not None
# Standard MCP semantic conventions
assert client_span.attributes["mcp.method.name"] == "prompts/get"
# Standard RPC semantic conventions
@ -230,7 +233,9 @@ class TestClientServerSpanHierarchy:
# Both spans should exist
assert client_span is not None, "Client should create a span"
assert client_span.attributes is not None
assert server_span is not None, "Server should create a span"
assert server_span.attributes is not None
# Verify span kinds are correct
assert client_span.kind == SpanKind.CLIENT, "Client span should be CLIENT kind"
@ -539,6 +544,7 @@ class TestSessionIdOnSpans:
)
assert client_span is not None, "Client should create a span"
assert client_span.attributes is not None
assert "mcp.session.id" in client_span.attributes
assert client_span.attributes["mcp.session.id"] is not None
@ -570,6 +576,7 @@ class TestSessionIdOnSpans:
)
assert server_span is not None, "Server should create a span"
assert server_span.attributes is not None
assert "mcp.session.id" in server_span.attributes
assert server_span.attributes["mcp.session.id"] is not None
@ -611,7 +618,9 @@ class TestSessionIdOnSpans:
)
assert client_span is not None
assert client_span.attributes is not None
assert server_span is not None
assert server_span.attributes is not None
# Both should have session IDs and they should match
client_session = client_span.attributes.get("mcp.session.id")

View file

@ -31,7 +31,7 @@ def create_test_server() -> FastMCP:
result = await ctx.elicit("What is your name?", response_type=str)
if result.action == "accept":
return f"You said your name was: {result.data}!" # ty: ignore[possibly-missing-attribute]
return f"You said your name was: {result.data}!" # ty: ignore[unresolved-attribute]
else:
return "No name provided"

View file

@ -63,6 +63,7 @@ class TestStreamableHTTPAppResourceMetadataURL:
assert isinstance(route.endpoint, RequireAuthMiddleware)
# Verify methods include GET, POST, DELETE for streamable-http
expected_methods = {"GET", "POST", "DELETE"}
assert route.methods is not None
assert expected_methods.issubset(set(route.methods))
def test_no_auth_provider_mounts_without_middleware(self, rsa_key_pair):

View file

@ -9,7 +9,7 @@ import pytest
from mcp.types import TextContent
from fastmcp import Client, Context, FastMCP
from fastmcp.prompts.prompt import Prompt
from fastmcp.prompts.prompt import Prompt, PromptResult
class TestPromptContext:
@ -58,6 +58,7 @@ class TestPromptDecorator:
prompt = next(p for p in prompts if p.name == "fn")
assert prompt.name == "fn"
content = await prompt.render()
assert isinstance(content, PromptResult)
assert isinstance(content.messages[0].content, TextContent)
assert content.messages[0].content.text == "Hello, world!"
@ -88,6 +89,7 @@ class TestPromptDecorator:
prompt = next(p for p in prompts_list if p.name == "custom_name")
assert prompt.name == "custom_name"
content = await prompt.render()
assert isinstance(content, PromptResult)
assert isinstance(content.messages[0].content, TextContent)
assert content.messages[0].content.text == "Hello, world!"
@ -103,6 +105,7 @@ class TestPromptDecorator:
prompt = next(p for p in prompts_list if p.name == "fn")
assert prompt.description == "A custom description"
content = await prompt.render()
assert isinstance(content, PromptResult)
assert isinstance(content.messages[0].content, TextContent)
assert content.messages[0].content.text == "Hello, world!"

View file

@ -41,6 +41,7 @@ class TestFastMCPProviderTracing:
# Verify delegate span has correct attributes
delegate_span = next(s for s in spans if s.name == "delegate child_tool")
assert delegate_span.attributes is not None
assert delegate_span.attributes["fastmcp.provider.type"] == "FastMCPProvider"
assert delegate_span.attributes["fastmcp.component.key"] == "child_tool"
@ -96,6 +97,7 @@ class TestFastMCPProviderTracing:
# Verify delegate span has correct attributes
delegate_span = next(s for s in spans if s.name == "delegate child_prompt")
assert delegate_span.attributes is not None
assert delegate_span.attributes["fastmcp.provider.type"] == "FastMCPProvider"
@ -125,5 +127,7 @@ class TestProviderSpanHierarchy:
child_span = next(s for s in spans if s.name == "tools/call greet")
# Verify parent-child relationships
assert delegate_span.parent is not None
assert child_span.parent is not None
assert delegate_span.parent.span_id == parent_span.context.span_id
assert child_span.parent.span_id == delegate_span.context.span_id

View file

@ -246,6 +246,7 @@ class TestMountedServerVersioning:
# Calling the v1.0 wrapper should execute v1.0's logic
result = await v1_tool.run({"x": 5})
assert isinstance(result.content[0], TextContent)
assert result.content[0].text == "50" # 5 * 10, not 5 * 100
async def test_mounted_resource_wrapper_reads_correct_version(self):

View file

@ -554,9 +554,9 @@ class TestNameHandling:
Type = json_schema_to_type(schema)
assert Type.__name__ == "Parent"
child_field_type = get_dataclass_field(Type, "child").type
assert child_field_type.__origin__ is Union # ty: ignore[possibly-missing-attribute]
assert child_field_type.__args__[0].__name__ == "Child" # ty: ignore[possibly-missing-attribute]
assert child_field_type.__args__[1] is type(None) # ty: ignore[possibly-missing-attribute]
assert child_field_type.__origin__ is Union # ty: ignore[unresolved-attribute]
assert child_field_type.__args__[0].__name__ == "Child" # ty: ignore[unresolved-attribute]
assert child_field_type.__args__[1] is type(None) # ty: ignore[unresolved-attribute]
def test_recursive_schema_naming(self):
schema = {
@ -569,9 +569,9 @@ class TestNameHandling:
next_field_type = get_dataclass_field(Type, "next").type
assert next_field_type.__origin__ is Union # ty: ignore[possibly-missing-attribute]
assert next_field_type.__args__[0].__forward_arg__ == "Node" # ty: ignore[possibly-missing-attribute]
assert next_field_type.__args__[1] is type(None) # ty: ignore[possibly-missing-attribute]
assert next_field_type.__origin__ is Union # ty: ignore[unresolved-attribute]
assert next_field_type.__args__[0].__forward_arg__ == "Node" # ty: ignore[unresolved-attribute]
assert next_field_type.__args__[1] is type(None) # ty: ignore[unresolved-attribute]
def test_name_caching_with_different_titles(self):
"""Ensure schemas with different titles create different cached classes"""

796
uv.lock generated

File diff suppressed because it is too large Load diff