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

15 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-08-05 19:10 +0200

1""" 

2Replacement for pydal's json serializer. 

3""" 

4 

5import json 

6import typing 

7from typing import Any 

8 

9from configurablejson import ConfigurableJsonEncoder, JSONRule 

10 

11 

12class 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 

71def 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)