replace inefficient use of to_jsonable_python (#545)

This commit is contained in:
Samuel Colvin 2025-04-26 11:41:19 -07:00 • committed by GitHub
commit 697b6e8e05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 11 additions and 17 deletions

View file

@ -1,7 +1,6 @@
"""Base classes for FastMCP prompts.""" """Base classes for FastMCP prompts."""
import inspect import inspect
import json
from collections.abc import Awaitable, Callable, Sequence from collections.abc import Awaitable, Callable, Sequence
from typing import Any, Literal from typing import Any, Literal
@ -155,7 +154,9 @@ class Prompt(BaseModel):
content = TextContent(type="text", text=msg) content = TextContent(type="text", text=msg)
messages.append(UserMessage(content=content)) messages.append(UserMessage(content=content))
else: else:
content = json.dumps(pydantic_core.to_jsonable_python(msg)) content = pydantic_core.to_json(
msg, fallback=str, indent=2
).decode()
messages.append(Message(role="user", content=content)) messages.append(Message(role="user", content=content))
except Exception: except Exception:
raise ValueError( raise ValueError(

View file

@ -9,7 +9,7 @@ from typing import Any
import anyio import anyio
import anyio.to_thread import anyio.to_thread
import httpx import httpx
import pydantic.json import pydantic
import pydantic_core import pydantic_core
from pydantic import Field, ValidationInfo from pydantic import Field, ValidationInfo
@ -59,15 +59,12 @@ class FunctionResource(Resource):
) )
if isinstance(result, Resource): if isinstance(result, Resource):
return await result.read() return await result.read()
if isinstance(result, bytes): elif isinstance(result, bytes):
return result return result
if isinstance(result, str): elif isinstance(result, str):
return result return result
try: else:
return json.dumps(pydantic_core.to_jsonable_python(result)) return pydantic_core.to_json(result, fallback=str, indent=2).decode()
except (TypeError, pydantic_core.PydanticSerializationError):
# If JSON serialization fails, try str()
return str(result)
except Exception as e: except Exception as e:
raise ValueError(f"Error reading resource {self.uri}: {e}") raise ValueError(f"Error reading resource {self.uri}: {e}")

View file

@ -3,7 +3,6 @@
from __future__ import annotations as _annotations from __future__ import annotations as _annotations
import inspect import inspect
import json
import re import re
from collections.abc import AsyncIterator, Callable, Iterable, Sequence from collections.abc import AsyncIterator, Callable, Iterable, Sequence
from contextlib import ( from contextlib import (
@ -551,10 +550,7 @@ def _convert_to_content(
return list(chain.from_iterable(_convert_to_content(item) for item in result)) # type: ignore[reportUnknownVariableType] return list(chain.from_iterable(_convert_to_content(item) for item in result)) # type: ignore[reportUnknownVariableType]
if not isinstance(result, str): if not isinstance(result, str):
try: result = pydantic_core.to_json(result, fallback=str, indent=2).decode()
result = json.dumps(pydantic_core.to_jsonable_python(result))
except Exception:
result = str(result)
return [TextContent(type="text", text=result)] return [TextContent(type="text", text=result)]

View file

@ -100,7 +100,7 @@ class TestFunctionResource:
fn=lambda: MyModel(name="test"), fn=lambda: MyModel(name="test"),
) )
content = await resource.read() content = await resource.read()
assert content == '{"name": "test"}' assert content == '{\n "name": "test"\n}'
@pytest.mark.anyio @pytest.mark.anyio
async def test_custom_type_conversion(self): async def test_custom_type_conversion(self):

View file

@ -185,4 +185,4 @@ class TestResourceTemplate:
assert isinstance(resource, FunctionResource) assert isinstance(resource, FunctionResource)
content = await resource.read() content = await resource.read()
assert content == "hello" assert content == '"hello"'