Coverage for jsonschema_diff/core/parameter_base.py: 91%

46 statements  

« prev     ^ index     » next       coverage.py v7.10.5, created at 2025-08-25 07:00 +0000

1from typing import TYPE_CHECKING, Any, TypeAlias 

2 

3from .abstraction import Statuses, ToCompare 

4from .tools.render import RenderTool 

5 

6if TYPE_CHECKING: 

7 from .config import Config 

8 

9COMPARE_PATH_TYPE: TypeAlias = list[str | int] 

10LEGEND_PROCESSOR_TYPE: TypeAlias = dict[str, Any] 

11LEGEND_RETURN_TYPE: TypeAlias = dict[ 

12 str, str | LEGEND_PROCESSOR_TYPE | list[str | LEGEND_PROCESSOR_TYPE] 

13] 

14 

15 

16class Compare: 

17 def __init__( 

18 self, 

19 config: "Config", 

20 schema_path: COMPARE_PATH_TYPE, 

21 json_path: COMPARE_PATH_TYPE, 

22 to_compare: list[ToCompare], 

23 ): 

24 self.status = Statuses.UNKNOWN 

25 

26 self.config = config 

27 self.schema_path = schema_path 

28 self.json_path = json_path 

29 

30 if len(to_compare) <= 0: 

31 raise ValueError("Cannot compare empty list") 

32 self.to_compare = to_compare 

33 

34 def compare(self) -> Statuses: 

35 if len(self.to_compare) > 1: 

36 raise ValueError("Unsupported multiple compare for base logic") 

37 

38 self.status = self.to_compare[0].status 

39 self.key = self.to_compare[0].key 

40 self.value = self.to_compare[0].value 

41 self.old_value = self.to_compare[0].old_value 

42 self.new_value = self.to_compare[0].new_value 

43 return self.status 

44 

45 def get_name(self) -> str: 

46 return self.to_compare[0].key 

47 

48 def is_for_rendering(self) -> bool: 

49 return self.status in [ 

50 Statuses.ADDED, 

51 Statuses.DELETED, 

52 Statuses.REPLACED, 

53 Statuses.MODIFIED, 

54 ] 

55 

56 def _render_start_line( 

57 self, tab_level: int = 0, with_path: bool = True, with_key: bool = True 

58 ) -> str: 

59 to_return = ( 

60 f"{RenderTool.make_prefix(self.status)} {RenderTool.make_tab(self.config, tab_level)}" 

61 ) 

62 if with_path: 

63 to_return += RenderTool.make_path( 

64 self.schema_path, self.json_path, ignore=self.config.PATH_MAKER_IGNORE 

65 ) 

66 

67 if with_key: 

68 to_return += f".{self.get_name()}" 

69 return to_return + ":" 

70 

71 def render(self, tab_level: int = 0, with_path: bool = True) -> str: 

72 to_return = self._render_start_line(tab_level=tab_level, with_path=with_path) 

73 

74 if self.status in [Statuses.ADDED, Statuses.DELETED, Statuses.NO_DIFF]: 

75 to_return += f" {self.value}" 

76 elif self.status == Statuses.REPLACED: 

77 to_return += f" {self.old_value} -> {self.new_value}" 

78 else: 

79 raise ValueError(f"Unsupported for render status: {self.status}") 

80 

81 return to_return 

82 

83 @staticmethod 

84 def legend() -> LEGEND_RETURN_TYPE: 

85 return { 

86 "element": [ 

87 Statuses.ADDED.value, 

88 Statuses.DELETED.value, 

89 Statuses.REPLACED.value, 

90 Statuses.MODIFIED.value, 

91 Statuses.NO_DIFF.value, 

92 Statuses.UNKNOWN.value, 

93 ], 

94 "description": [ 

95 Statuses.ADDED.name, 

96 Statuses.DELETED.name, 

97 Statuses.REPLACED.name, 

98 Statuses.MODIFIED.name, 

99 Statuses.NO_DIFF.name, 

100 Statuses.UNKNOWN.name, 

101 ], 

102 "example": [ 

103 {"old_value": {}, "new_value": {"added_key": "value"}}, 

104 {"old_value": {"deleted_key": "value"}, "new_value": {}}, 

105 { 

106 "old_value": {"replaced_key": "old-value"}, 

107 "new_value": {"replaced_key": "new-value"}, 

108 }, 

109 { 

110 "old_value": {"modified_key": []}, 

111 "new_value": {"modified_key": ["value"]}, 

112 }, 

113 { 

114 "old_value": {"no_diff_key": "value"}, 

115 "new_value": {"no_diff_key": "value"}, 

116 }, 

117 ], 

118 }