Spaces:
Runtime error
Runtime error
"""This module contains related classes and functions for serialization.""" | |
from __future__ import annotations | |
import dataclasses | |
from functools import partialmethod | |
from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, overload | |
from pydantic_core import PydanticUndefined, core_schema | |
from pydantic_core import core_schema as _core_schema | |
from typing_extensions import Annotated, Literal, TypeAlias | |
from . import PydanticUndefinedAnnotation | |
from ._internal import _annotated_handlers, _decorators, _internal_dataclass | |
class PlainSerializer: | |
"""Plain serializers use a function to modify the output of serialization. | |
Attributes: | |
func: The serializer function. | |
return_type: The return type for the function. If omitted it will be inferred from the type annotation. | |
when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, | |
`'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. | |
""" | |
func: core_schema.SerializerFunction | |
return_type: Any = PydanticUndefined | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always' | |
def __get_pydantic_core_schema__( | |
self, source_type: Any, handler: _annotated_handlers.GetCoreSchemaHandler | |
) -> core_schema.CoreSchema: | |
"""Gets the Pydantic core schema. | |
Args: | |
source_type: The source type. | |
handler: The `GetCoreSchemaHandler` instance. | |
Returns: | |
The Pydantic core schema. | |
""" | |
schema = handler(source_type) | |
try: | |
return_type = _decorators.get_function_return_type( | |
self.func, self.return_type, handler._get_types_namespace() | |
) | |
except NameError as e: | |
raise PydanticUndefinedAnnotation.from_name_error(e) from e | |
return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) | |
schema['serialization'] = core_schema.plain_serializer_function_ser_schema( | |
function=self.func, | |
info_arg=_decorators.inspect_annotated_serializer(self.func, 'plain'), | |
return_schema=return_schema, | |
when_used=self.when_used, | |
) | |
return schema | |
class WrapSerializer: | |
"""Wrap serializers receive the raw inputs along with a handler function that applies the standard serialization | |
logic, and can modify the resulting value before returning it as the final output of serialization. | |
Attributes: | |
func: The serializer function to be wrapped. | |
return_type: The return type for the function. If omitted it will be inferred from the type annotation. | |
when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, | |
`'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. | |
""" | |
func: core_schema.WrapSerializerFunction | |
return_type: Any = PydanticUndefined | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always' | |
def __get_pydantic_core_schema__( | |
self, source_type: Any, handler: _annotated_handlers.GetCoreSchemaHandler | |
) -> core_schema.CoreSchema: | |
"""This method is used to get the Pydantic core schema of the class. | |
Args: | |
source_type: Source type. | |
handler: Core schema handler. | |
Returns: | |
The generated core schema of the class. | |
""" | |
schema = handler(source_type) | |
try: | |
return_type = _decorators.get_function_return_type( | |
self.func, self.return_type, handler._get_types_namespace() | |
) | |
except NameError as e: | |
raise PydanticUndefinedAnnotation.from_name_error(e) from e | |
return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) | |
schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( | |
function=self.func, | |
info_arg=_decorators.inspect_annotated_serializer(self.func, 'wrap'), | |
return_schema=return_schema, | |
when_used=self.when_used, | |
) | |
return schema | |
if TYPE_CHECKING: | |
_PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] | |
_PlainSerializationFunction = Union[_core_schema.SerializerFunction, _PartialClsOrStaticMethod] | |
_WrapSerializationFunction = Union[_core_schema.WrapSerializerFunction, _PartialClsOrStaticMethod] | |
_PlainSerializeMethodType = TypeVar('_PlainSerializeMethodType', bound=_PlainSerializationFunction) | |
_WrapSerializeMethodType = TypeVar('_WrapSerializeMethodType', bound=_WrapSerializationFunction) | |
def field_serializer( | |
__field: str, | |
*fields: str, | |
return_type: Any = ..., | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ..., | |
check_fields: bool | None = ..., | |
) -> Callable[[_PlainSerializeMethodType], _PlainSerializeMethodType]: | |
... | |
def field_serializer( | |
__field: str, | |
*fields: str, | |
mode: Literal['plain'], | |
return_type: Any = ..., | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ..., | |
check_fields: bool | None = ..., | |
) -> Callable[[_PlainSerializeMethodType], _PlainSerializeMethodType]: | |
... | |
def field_serializer( | |
__field: str, | |
*fields: str, | |
mode: Literal['wrap'], | |
return_type: Any = ..., | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ..., | |
check_fields: bool | None = ..., | |
) -> Callable[[_WrapSerializeMethodType], _WrapSerializeMethodType]: | |
... | |
def field_serializer( | |
*fields: str, | |
mode: Literal['plain', 'wrap'] = 'plain', | |
return_type: Any = PydanticUndefined, | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always', | |
check_fields: bool | None = None, | |
) -> Callable[[Any], Any]: | |
"""Decorator that enables custom field serialization. | |
See [Custom serializers](../usage/serialization.md#custom-serializers) for more information. | |
Four signatures are supported: | |
- `(self, value: Any, info: FieldSerializationInfo)` | |
- `(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo)` | |
- `(value: Any, info: SerializationInfo)` | |
- `(value: Any, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)` | |
Args: | |
fields: Which field(s) the method should be called on. | |
mode: The serialization mode. | |
- `plain` means the function will be called instead of the default serialization logic, | |
- `wrap` means the function will be called with an argument to optionally call the | |
default serialization logic. | |
return_type: Optional return type for the function, if omitted it will be inferred from the type annotation. | |
when_used: Determines the serializer will be used for serialization. | |
check_fields: Whether to check that the fields actually exist on the model. | |
Returns: | |
The decorator function. | |
""" | |
def dec( | |
f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any] | |
) -> _decorators.PydanticDescriptorProxy[Any]: | |
dec_info = _decorators.FieldSerializerDecoratorInfo( | |
fields=fields, | |
mode=mode, | |
return_type=return_type, | |
when_used=when_used, | |
check_fields=check_fields, | |
) | |
return _decorators.PydanticDescriptorProxy(f, dec_info) | |
return dec | |
FuncType = TypeVar('FuncType', bound=Callable[..., Any]) | |
def model_serializer(__f: FuncType) -> FuncType: | |
... | |
def model_serializer( | |
*, | |
mode: Literal['plain', 'wrap'] = ..., | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always', | |
return_type: Any = ..., | |
) -> Callable[[FuncType], FuncType]: | |
... | |
def model_serializer( | |
__f: Callable[..., Any] | None = None, | |
*, | |
mode: Literal['plain', 'wrap'] = 'plain', | |
when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always', | |
return_type: Any = PydanticUndefined, | |
) -> Callable[[Any], Any]: | |
"""Decorator that enables custom model serialization. | |
See [Custom serializers](../usage/serialization.md#custom-serializers) for more information. | |
Args: | |
__f: The function to be decorated. | |
mode: The serialization mode. | |
- `'plain'` means the function will be called instead of the default serialization logic | |
- `'wrap'` means the function will be called with an argument to optionally call the default | |
serialization logic. | |
when_used: Determines when this serializer should be used. | |
return_type: The return type for the function. If omitted it will be inferred from the type annotation. | |
Returns: | |
The decorator function. | |
""" | |
def dec(f: Callable[..., Any]) -> _decorators.PydanticDescriptorProxy[Any]: | |
dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, return_type=return_type, when_used=when_used) | |
return _decorators.PydanticDescriptorProxy(f, dec_info) | |
if __f is None: | |
return dec | |
else: | |
return dec(__f) # type: ignore | |
AnyType = TypeVar('AnyType') | |
if TYPE_CHECKING: | |
SerializeAsAny = Annotated[AnyType, ...] # SerializeAsAny[list[str]] will be treated by type checkers as list[str] | |
"""Force serialization to ignore whatever is defined in the schema and instead ask the object | |
itself how it should be serialized. | |
In particular, this means that when model subclasses are serialized, fields present in the subclass | |
but not in the original schema will be included. | |
""" | |
else: | |
class SerializeAsAny: # noqa: D101 | |
def __class_getitem__(cls, item: Any) -> Any: | |
return Annotated[item, SerializeAsAny()] | |
def __get_pydantic_core_schema__( | |
self, source_type: Any, handler: _annotated_handlers.GetCoreSchemaHandler | |
) -> core_schema.CoreSchema: | |
schema = handler(source_type) | |
schema_to_update = schema | |
while schema_to_update['type'] == 'definitions': | |
schema_to_update = schema_to_update.copy() | |
schema_to_update = schema_to_update['schema'] | |
schema_to_update['serialization'] = core_schema.wrap_serializer_function_ser_schema( | |
lambda x, h: h(x), schema=core_schema.any_schema() | |
) | |
return schema | |
__hash__ = object.__hash__ | |