Skip to content

Commit d3a2fba

Browse files
committed
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).
1 parent c75f17d commit d3a2fba

File tree

1 file changed

+4
-20
lines changed

1 file changed

+4
-20
lines changed

fastapi/encoders.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import dataclasses
22
import datetime
3-
from collections import defaultdict, deque
3+
from collections import deque
44
from decimal import Decimal
55
from enum import Enum
66
from ipaddress import (
@@ -96,20 +96,6 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
9696
}
9797

9898

99-
def generate_encoders_by_class_tuples(
100-
type_encoder_map: dict[Any, Callable[[Any], Any]],
101-
) -> dict[Callable[[Any], Any], tuple[Any, ...]]:
102-
encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict(
103-
tuple
104-
)
105-
for type_, encoder in type_encoder_map.items():
106-
encoders_by_class_tuples[encoder] += (type_,)
107-
return encoders_by_class_tuples
108-
109-
110-
encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
111-
112-
11399
def jsonable_encoder(
114100
obj: Annotated[
115101
Any,
@@ -326,11 +312,9 @@ def jsonable_encoder(
326312
)
327313
return encoded_list
328314

329-
if type(obj) in ENCODERS_BY_TYPE:
330-
return ENCODERS_BY_TYPE[type(obj)](obj)
331-
for encoder, classes_tuple in encoders_by_class_tuples.items():
332-
if isinstance(obj, classes_tuple):
333-
return encoder(obj)
315+
for base in obj.__class__.__mro__[:-1]:
316+
if base in ENCODERS_BY_TYPE:
317+
return ENCODERS_BY_TYPE[base](obj)
334318

335319
try:
336320
data = dict(obj)

0 commit comments

Comments
 (0)