Coverage for src/configuraptor/dump.py: 100%

35 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-09-18 12:33 +0200

1""" 

2Method to dump classes to other formats. 

3""" 

4 

5import json 

6import typing 

7 

8import tomli_w 

9import yaml 

10 

11from .helpers import camel_to_snake, instance_of_custom_class, is_custom_class 

12from .loaders.register import register_dumper 

13 

14 

15@register_dumper("dict") 

16def asdict(inst: typing.Any, _level: int = 0, /, with_top_level_key: bool = True) -> dict[str, typing.Any]: 

17 """ 

18 Dump a config instance to a dictionary (recursively). 

19 """ 

20 data: dict[str, typing.Any] = {} 

21 

22 for key, value in inst.__dict__.items(): 

23 cls = value.__class__ 

24 if is_custom_class(cls): 

25 value = asdict(value, _level + 1) 

26 elif isinstance(value, list): 

27 value = [asdict(_, _level + 1) if instance_of_custom_class(_) else _ for _ in value] 

28 elif isinstance(value, dict): 

29 value = {k: asdict(v, _level + 1) if instance_of_custom_class(v) else v for k, v in value.items()} 

30 

31 data[key] = value 

32 

33 if _level == 0 and with_top_level_key: 

34 # top-level: add an extra key indicating the class' name 

35 cls_name = camel_to_snake(inst.__class__.__name__) 

36 return {cls_name: data} 

37 

38 return data 

39 

40 

41@register_dumper("toml") 

42def astoml(inst: typing.Any, multiline_strings: bool = False, **kw: typing.Any) -> str: 

43 """ 

44 Dump a config instance to toml (recursively). 

45 """ 

46 data = asdict(inst, with_top_level_key=kw.pop("with_top_level_key", True)) 

47 return tomli_w.dumps(data, multiline_strings=multiline_strings) 

48 

49 

50@register_dumper("json") 

51def asjson(inst: typing.Any, **kw: typing.Any) -> str: 

52 """ 

53 Dump a config instance to json (recursively). 

54 """ 

55 data = asdict(inst, with_top_level_key=kw.pop("with_top_level_key", True)) 

56 return json.dumps(data, **kw) 

57 

58 

59@register_dumper("yaml") 

60def asyaml(inst: typing.Any, **kw: typing.Any) -> str: 

61 """ 

62 Dump a config instance to yaml (recursively). 

63 """ 

64 data = asdict(inst, with_top_level_key=kw.pop("with_top_level_key", True)) 

65 output = yaml.dump(data, encoding=None, **kw) 

66 # output is already a str but mypy doesn't know that 

67 return typing.cast(str, output)