使用Pydantic的ImportString获取类实例遇Schema生成错误求解决
问题:Pydantic ImportString 泛型使用自定义类时触发Schema生成错误
问题复现
尝试使用Pydantic的ImportString类型导入指定对象实例,代码如下:
from __future__ import annotations from pydantic.types import ImportString from pydantic import Field, BaseModel from typing import Annotated, Callable class Foo: """A test class.""" def __init__(self, name: str) -> None: self.name = name def __call__(self, name: str) -> str: """Call the foo class.""" return f"hello {name}" x = Foo("world") def say_hello(name: str) -> str: """Say hello to a name.""" return f"hello {name}" def test_pydantic_ai_tool() -> None: """Test that the PydanticAiTool type can be used to validate a tool.""" class Bar(BaseModel): foo: Annotated[ ImportString[Callable[..., str]], Field(description="A tool that can be used in a pydantic-ai agent."), ] bar = Bar.model_validate( { "foo": "_tests.utils.types.test__pydantic_ai_tool.say_hello", }, ) assert bar.foo("world") == "hello world" assert bar.model_dump_json() == '{"foo":"_tests.utils.types.test__pydantic_ai_tool.say_hello"}' def test_pydantic_ai_tool_two() -> None: """Test that the PydanticAiTool type can be used to validate a tool.""" class Bar(BaseModel): foo: Annotated[ ImportString[Foo], Field(description="A tool that can be used in a pydantic-ai agent."), ] bar = Bar.model_validate( { "foo": "_tests.utils.types.test__pydantic_ai_tool.x", }, ) assert bar.foo("world") == "hello world" assert bar.model_dump_json() == '{"foo": "_tests.utils.types.test__pydantic_ai_tool.x"}'
其中test_pydantic_ai_tool可正常运行,但test_pydantic_ai_tool_two执行时抛出错误:
E pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for <class 'test__pydantic_ai_tool.Foo'>. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it. E E If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on <some type> otherwise to avoid infinite recursion. E E For further information visit https://errors.pydantic.dev/2.10/u/schema-for-unknown-type .venv/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:513: PydanticSchemaGenerationError
期望效果:ImportString可导入路径对应的对象并验证其是否为指定类型的实例,序列化时仅返回导入字符串(如第一个测试中model_dump_json返回的是导入字符串而非目标类型的Schema)。
解决办法
方案1:在模型配置中启用arbitrary_types_allowed
自定义类Foo未实现Pydantic的Schema生成逻辑,因此需要在包含ImportString[Foo]的模型中开启任意类型允许,跳过对Foo的Schema检查。修改第二个测试中的Bar类:
class Bar(BaseModel): foo: Annotated[ ImportString[Foo], Field(description="A tool that can be used in a pydantic-ai agent."), ] model_config = {"arbitrary_types_allowed": True}
方案2:为自定义类实现__get_pydantic_core_schema__
若不想全局启用任意类型允许,可在Foo类中添加Schema生成方法,让Pydantic能够识别该类型:
from pydantic_core import core_schema from pydantic import GetCoreSchemaHandler class Foo: """A test class.""" def __init__(self, name: str) -> None: self.name = name def __call__(self, name: str) -> str: """Call the foo class.""" return f"hello {name}" @classmethod def __get_pydantic_core_schema__(cls, source_type: type, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: # 返回任意类型的Schema,也可根据需求自定义验证逻辑 return core_schema.any_schema()
原因说明
第一个测试中Callable[..., str]是Pydantic原生支持的类型,内置了对应的Schema生成逻辑;而自定义类Foo不属于Pydantic默认支持的类型集合,因此在生成模型Schema时,Pydantic无法为其生成对应的核心Schema,从而抛出错误。ImportString在验证阶段会完成对象导入,但模型初始化时需要确认泛型参数的类型可被Schema化,因此需要让Pydantic能够处理Foo类型。
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

