🐛 Fix: 兼容 pydantic v2.12 FieldInfo 改动 (#3722)

This commit is contained in:
Ju4tCode
2025-10-13 20:18:37 +09:00
committed by GitHub
parent ca9bb2ceef
commit 07f0cc16a1
4 changed files with 1707 additions and 1243 deletions

View File

@@ -55,7 +55,6 @@ __all__ = (
"Required",
"TypeAdapter",
"custom_validation",
"extract_field_info",
"field_validator",
"model_config",
"model_dump",
@@ -95,7 +94,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2
DEFAULT_CONFIG = ConfigDict(extra="allow", arbitrary_types_allowed=True)
"""Default config for validations"""
class FieldInfo(BaseFieldInfo):
class FieldInfo(BaseFieldInfo): # pyright: ignore[reportGeneralTypeIssues]
"""FieldInfo class with extra property for compatibility with pydantic v1"""
# make default can be positional argument
@@ -115,6 +114,20 @@ if PYDANTIC_V2: # pragma: pydantic-v2
slots = super().__slots__
return {k: v for k, v in self._attributes_set.items() if k not in slots}
@classmethod
def _inherit_construct(
cls, field_info: Optional[BaseFieldInfo] = None, **kwargs: Any
) -> Self:
init_kwargs = {}
if field_info:
init_kwargs.update(field_info._attributes_set)
init_kwargs.update(kwargs)
instance = cls(**init_kwargs)
if field_info:
instance.metadata = field_info.metadata
return instance
@dataclass
class ModelField:
"""ModelField class for compatibility with pydantic v1"""
@@ -187,13 +200,6 @@ if PYDANTIC_V2: # pragma: pydantic-v2
"""Validate the value pass to the field."""
return self.type_adapter.validate_python(value)
def extract_field_info(field_info: BaseFieldInfo) -> dict[str, Any]:
"""Get FieldInfo init kwargs from a FieldInfo instance."""
kwargs = field_info._attributes_set.copy()
kwargs["annotation"] = field_info.rebuild_annotation()
return kwargs
def model_fields(model: type[BaseModel]) -> list[ModelField]:
"""Get field list of a model."""
@@ -201,7 +207,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2
ModelField._construct(
name=name,
annotation=field_info.rebuild_annotation(),
field_info=FieldInfo(**extract_field_info(field_info)),
field_info=FieldInfo._inherit_construct(field_info),
)
for name, field_info in model.model_fields.items()
]
@@ -294,6 +300,22 @@ else: # pragma: pydantic-v1
default = PydanticUndefined
super().__init__(default, **kwargs)
@classmethod
def _inherit_construct(
cls, field_info: Optional[BaseFieldInfo] = None, **kwargs: Any
):
if field_info:
init_kwargs = {
s: getattr(field_info, s)
for s in field_info.__slots__
if s != "extra"
}
init_kwargs.update(field_info.extra)
else:
init_kwargs = {}
init_kwargs.update(kwargs)
return cls(**init_kwargs)
class ModelField(BaseModelField):
@classmethod
def _construct(cls, name: str, annotation: Any, field_info: FieldInfo) -> Self:
@@ -364,15 +386,6 @@ else: # pragma: pydantic-v1
def validate_json(self, value: Union[str, bytes]) -> T:
return type_validate_json(self.type, value)
def extract_field_info(field_info: BaseFieldInfo) -> dict[str, Any]:
"""Get FieldInfo init kwargs from a FieldInfo instance."""
kwargs = {
s: getattr(field_info, s) for s in field_info.__slots__ if s != "extra"
}
kwargs.update(field_info.extra)
return kwargs
@overload
def field_validator(
field: str,
@@ -419,9 +432,7 @@ else: # pragma: pydantic-v1
ModelField._construct(
name=model_field.name,
annotation=model_field.annotation,
field_info=FieldInfo(
**extract_field_info(model_field.field_info),
),
field_info=FieldInfo._inherit_construct(model_field.field_info),
)
for model_field in model.__fields__.values()
]

View File

@@ -17,7 +17,7 @@ import anyio
from exceptiongroup import BaseExceptionGroup, catch
from pydantic.fields import FieldInfo as PydanticFieldInfo
from nonebot.compat import FieldInfo, ModelField, PydanticUndefined, extract_field_info
from nonebot.compat import FieldInfo, ModelField, PydanticUndefined
from nonebot.consts import ARG_KEY, REJECT_PROMPT_RESULT_KEY
from nonebot.dependencies import Dependent, Param
from nonebot.dependencies.utils import check_field_type
@@ -194,15 +194,12 @@ class DependParam(Param):
use_cache: bool,
validate: Union[bool, PydanticFieldInfo],
) -> Self:
kwargs = {}
if isinstance(validate, PydanticFieldInfo):
kwargs.update(extract_field_info(validate))
kwargs["validate"] = bool(validate)
kwargs["dependent"] = sub_dependent
kwargs["use_cache"] = use_cache
return cls(**kwargs)
return cls._inherit_construct(
validate if isinstance(validate, PydanticFieldInfo) else None,
dependent=sub_dependent,
use_cache=use_cache,
validate=bool(validate),
)
@classmethod
@override