-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- per stack encoders via context vars - use the new encoders API features of lilya 0.11.0 - fix incompatibilities with lilya 0.11.0
- Loading branch information
Showing
15 changed files
with
250 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,70 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Any, TypeVar, get_args | ||
from typing import Any, get_args | ||
|
||
import msgspec | ||
from lilya._internal._encoders import json_encoder as json_encoder # noqa | ||
from lilya._utils import is_class_and_subclass | ||
from lilya._internal._encoders import ModelDumpEncoder | ||
from lilya.encoders import ( | ||
ENCODER_TYPES as LILYA_ENCODER_TYPES, # noqa | ||
Encoder as LilyaEncoder, # noqa | ||
register_encoder as register_encoder, # noqa | ||
ENCODER_TYPES as ENCODER_TYPES_CTX, # noqa | ||
Encoder, | ||
EncoderProtocol, # noqa | ||
MoldingProtocol, # noqa | ||
json_encode, | ||
register_encoder, # noqa | ||
) | ||
from msgspec import Struct | ||
from pydantic import BaseModel | ||
from pydantic_core import PydanticSerializationError | ||
|
||
from esmerald.exceptions import ImproperlyConfigured | ||
from esmerald.utils.helpers import is_union | ||
|
||
T = TypeVar("T") | ||
ENCODER_TYPES = ENCODER_TYPES_CTX.get() | ||
|
||
ENCODER_TYPES = LILYA_ENCODER_TYPES.get() | ||
|
||
|
||
class Encoder(LilyaEncoder[T]): | ||
def is_type(self, value: Any) -> bool: | ||
""" | ||
Function that checks if the function is | ||
an instance of a given type | ||
""" | ||
raise NotImplementedError("All Esmerald encoders must implement is_type() method.") | ||
|
||
def serialize(self, obj: Any) -> Any: | ||
""" | ||
Function that transforms a data structure into a serializable | ||
object. | ||
""" | ||
raise NotImplementedError("All Esmerald encoders must implement serialize() method.") | ||
|
||
def encode(self, annotation: Any, value: Any) -> Any: | ||
""" | ||
Function that transforms the kwargs into a structure | ||
""" | ||
raise NotImplementedError("All Esmerald encoders must implement encode() method.") | ||
|
||
|
||
class MsgSpecEncoder(Encoder): | ||
def is_type(self, value: Any) -> bool: | ||
return isinstance(value, Struct) or is_class_and_subclass(value, Struct) | ||
|
||
def serialize(self, obj: Any) -> Any: | ||
""" | ||
When a `msgspec.Struct` is serialised, | ||
it will call this function. | ||
""" | ||
return msgspec.json.decode(msgspec.json.encode(obj)) | ||
|
||
def encode(self, annotation: Any, value: Any) -> Any: | ||
return msgspec.json.decode(msgspec.json.encode(value), type=annotation) | ||
def register_esmerald_encoder( | ||
encoder: EncoderProtocol | MoldingProtocol | type[EncoderProtocol] | type[MoldingProtocol], | ||
) -> None: | ||
""" | ||
Registers an esmerald encoder into available Lilya encoders | ||
""" | ||
try: | ||
register_encoder(encoder) | ||
except RuntimeError: | ||
raise ImproperlyConfigured(f"{type(encoder)} must be a subclass of Encoder") from None | ||
|
||
|
||
class PydanticEncoder(Encoder): | ||
def is_type(self, value: Any) -> bool: | ||
return isinstance(value, BaseModel) or is_class_and_subclass(value, BaseModel) | ||
PydanticEncoder = ModelDumpEncoder | ||
try: | ||
import msgspec | ||
|
||
def serialize(self, obj: BaseModel) -> dict[str, Any]: | ||
try: | ||
return obj.model_dump(mode="json") | ||
except PydanticSerializationError: | ||
return obj.model_dump() | ||
class MsgSpecEncoder(Encoder): | ||
__type__ = msgspec.Struct | ||
|
||
def encode(self, annotation: Any, value: Any) -> Any: | ||
if isinstance(value, BaseModel) or is_class_and_subclass(value, BaseModel): | ||
return value | ||
return annotation(**value) | ||
def serialize(self, obj: Any) -> Any: | ||
""" | ||
When a `msgspec.Struct` is serialised, | ||
it will call this function. | ||
""" | ||
return msgspec.json.decode(msgspec.json.encode(obj)) | ||
|
||
def encode(self, annotation: Any, value: Any) -> Any: | ||
return msgspec.json.decode(msgspec.json.encode(value), type=annotation) | ||
|
||
def register_esmerald_encoder(encoder: Encoder[Any]) -> None: | ||
""" | ||
Registers an esmerald encoder into available Lilya encoders | ||
""" | ||
if not isinstance(encoder, Encoder) and not is_class_and_subclass(encoder, Encoder): # type: ignore | ||
raise ImproperlyConfigured(f"{type(encoder)} must be a subclass of Encoder") | ||
register_esmerald_encoder(MsgSpecEncoder) | ||
except ImportError: | ||
pass | ||
|
||
encoder_types = {encoder.__class__.__name__ for encoder in ENCODER_TYPES} | ||
if encoder.__name__ not in encoder_types: | ||
register_encoder(encoder) | ||
json_encoder = json_encode | ||
|
||
|
||
def is_body_encoder(value: Any) -> bool: | ||
""" | ||
Function that checks if the value is a body encoder. | ||
""" | ||
encoder_types = ENCODER_TYPES_CTX.get() | ||
if not is_union(value): | ||
return any(encoder.is_type(value) for encoder in ENCODER_TYPES) | ||
return any(encoder.is_type(value) for encoder in encoder_types) | ||
|
||
union_arguments = get_args(value) | ||
if not union_arguments: | ||
return False | ||
return any( | ||
any(encoder.is_type(argument) for encoder in ENCODER_TYPES) for argument in union_arguments | ||
any(encoder.is_type(argument) for encoder in encoder_types) for argument in union_arguments | ||
) |
Oops, something went wrong.