Coverage for src/typedal/serializers/as_json.py: 100%

1"""

2 Replacement for pydal's json serializer.

3"""

4

5 import json

6 import typing

7 from typing import Any

8

9 from configurablejson import ConfigurableJsonEncoder, JSONRule

10

11

12 class SerializedJson(ConfigurableJsonEncoder):

13 """

14 Custom encoder class with slightly improved defaults.

15 """

16

17 def _default(self, o: Any) -> Any: # pragma: no cover

18 if hasattr(o, "as_dict"):

19 return o.as_dict()

20 elif hasattr(o, "asdict"):

21 return o.asdict()

22 elif hasattr(o, "_asdict"):

23 return o._asdict()

24 elif hasattr(o, "_as_dict"):

25 return o._as_dict()

26 elif hasattr(o, "to_dict"):

27 return o.to_dict()

28 elif hasattr(o, "todict"):

29 return o.todict()

30 elif hasattr(o, "_todict"):

31 return o._todict()

32 elif hasattr(o, "_to_dict"):

33 return o._to_dict()

34 elif hasattr(o, "__json__"):

35 if callable(o.__json__):

36 return o.__json__()

37 else:

38 return o.__json__

39 elif hasattr(o, "__dict__"):

40 return o.__dict__

41

42 return str(o)

43

44 @typing.overload

45 def rules(self, o: Any, with_default: typing.Literal[False]) -> JSONRule | None:

46 """

47 If you pass with_default=False, you could get a None result.

48 """

49

50 @typing.overload

51 def rules(self, o: Any, with_default: typing.Literal[True] = True) -> JSONRule:

52 """

53 If you don't pass with_default=False, you will always get a JSONRule result.

54 """

55

56 def rules(self, o: Any, with_default: bool = True) -> JSONRule | None:

57 """

58 Custom rules, such as set to list and as_dict/__json__ etc. lookups.

59 """

60 _type = type(o)

61

62 _rules: dict[type[Any], JSONRule] = {

63 # convert set to list

64 set: JSONRule(preprocess=lambda o: list(o)),

65 }

66

67 # other rules:

68 return _rules.get(_type, JSONRule(transform=self._default) if with_default else None)

69

70

71 def encode(something: Any, indent: int = None, **kw: Any) -> str:

72 """

73 Encode anything to JSON with some improved defaults.

74 """

75 return json.dumps(something, indent=indent, cls=SerializedJson, **kw)