Compare objects MRO with encoders at runtime

The previous implementation doesn't handle subclass instances when
pydantic.json.ENCODERS_BY_TYPE is modified after fastapi.encoders import.

This diff makes it easier for developers to add custom encoders that also work
with subclass instances (and it simplifies the code, as well).
This commit is contained in:
ramnes 2022-11-30 18:24:42 +01:00 committed by Guillaume Gelin
parent d06ab3f5c7
commit c2766f1ecc
No known key found for this signature in database
GPG Key ID: 8C1702070803487A
1 changed files with 4 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import dataclasses
import datetime
from collections import defaultdict, deque
from collections import deque
from collections.abc import Callable
from decimal import Decimal
from enum import Enum
@ -95,20 +95,6 @@ ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = {
}
def generate_encoders_by_class_tuples(
type_encoder_map: dict[Any, Callable[[Any], Any]],
) -> dict[Callable[[Any], Any], tuple[Any, ...]]:
encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict(
tuple
)
for type_, encoder in type_encoder_map.items():
encoders_by_class_tuples[encoder] += (type_,)
return encoders_by_class_tuples
encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
def jsonable_encoder(
obj: Annotated[
Any,
@ -314,11 +300,9 @@ def jsonable_encoder(
)
return encoded_list
if type(obj) in ENCODERS_BY_TYPE:
return ENCODERS_BY_TYPE[type(obj)](obj)
for encoder, classes_tuple in encoders_by_class_tuples.items():
if isinstance(obj, classes_tuple):
return encoder(obj)
for base in obj.__class__.__mro__[:-1]:
if base in ENCODERS_BY_TYPE:
return ENCODERS_BY_TYPE[base](obj)
if is_pydantic_v1_model_instance(obj):
raise PydanticV1NotSupportedError(
"pydantic.v1 models are no longer supported by FastAPI."