Coverage for jsonschema_diff / config_maker.py: 100%

56 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-18 17:05 +0000

1""" 

2Factory for a ready-to-use :class:`jsonschema_diff.core.Config` instance. 

3 

4All optional switches are enabled by default; pass ``False`` to disable. 

5""" 

6 

7from dataclasses import dataclass 

8from enum import Enum 

9 

10from .core import Compare, Config 

11from .core.custom_compare import CompareList, CompareRange 

12from .core.tools.combine import COMBINE_RULES_TYPE 

13from .core.tools.compare import COMPARE_RULES_TYPE 

14from .core.tools.context import CONTEXT_RULES_TYPE, PAIR_CONTEXT_RULES_TYPE 

15from .core.tools.render import PATH_MAKER_IGNORE_RULES_TYPE 

16 

17 

18@dataclass(frozen=True) 

19class MultilineChars: 

20 START_LINE: str 

21 MIDDLE_LINE: str 

22 END_LINE: str 

23 SINGLE_LINE: str 

24 

25 

26class MultilineListRender(Enum): 

27 Soft = MultilineChars("╭", "│", "╰", "•") 

28 Hard = MultilineChars("┌", "│", "└", "▪") 

29 HardBold = MultilineChars("┏", "┃", "┗", "■") 

30 Double = MultilineChars("╔", "║", "╚", "◆") 

31 Without = MultilineChars(" ", " ", " ", " ") 

32 

33 

34class ConfigMaker: 

35 """Helper that builds a fully populated :class:`~jsonschema_diff.core.Config`.""" 

36 

37 # pylint: disable=too-many-arguments 

38 @staticmethod 

39 def make( 

40 *, 

41 tab_size: int = 1, 

42 all_for_rendering: bool = False, 

43 crop_path: bool = True, 

44 path_render_with_properies: bool = False, 

45 path_render_with_items: bool = False, 

46 list_comparator: bool = True, 

47 list_multiline_render: MultilineListRender = MultilineListRender.Soft, 

48 range_digit_comparator: bool = True, 

49 range_length_comparator: bool = True, 

50 range_items_comparator: bool = True, 

51 range_properties_comparator: bool = True, 

52 additional_compare_rules: COMPARE_RULES_TYPE = {}, 

53 additional_combine_rules: COMBINE_RULES_TYPE = [], 

54 additional_pair_context_rules: PAIR_CONTEXT_RULES_TYPE = [], 

55 additional_context_rules: CONTEXT_RULES_TYPE = {}, 

56 additional_path_maker_ignore: PATH_MAKER_IGNORE_RULES_TYPE = [], 

57 ) -> Config: 

58 """ 

59 Assemble and return a :class:`~jsonschema_diff.core.Config`. 

60 

61 Parameters 

62 ---------- 

63 tab_size : int 

64 Number of spaces per indentation level. 

65 path_render_with_properies, path_render_with_items : bool 

66 Include these schema service tokens in rendered paths. 

67 list_comparator : bool 

68 Enable :class:`~jsonschema_diff.core.custom_compare.CompareList`. 

69 list_multiline_render : MultilineListRender 

70 How to render multi-line elements of list. 

71 range_*_comparator : bool 

72 Enable :class:`~jsonschema_diff.core.custom_compare.CompareRange` 

73 for numeric/length/items/properties limits. 

74 additional_* : collections 

75 User-supplied rules that override the built-ins. 

76 """ 

77 tab = " " * tab_size 

78 

79 compare_rules: COMPARE_RULES_TYPE = {} 

80 combine_rules: COMBINE_RULES_TYPE = [] 

81 pair_context_rules: list[list[str | type[Compare]]] = [] 

82 context_rules: dict[str | type[Compare], list[str | type[Compare]]] = {} 

83 path_maker_ignore: list[str] = [] 

84 compare_config: dict[type[Compare], dict] = {} 

85 

86 # Built-in comparators 

87 if list_comparator: 

88 compare_rules[list] = CompareList 

89 compare_config[CompareList] = { 

90 field: getattr(list_multiline_render.value, field) 

91 for field in list_multiline_render.value.__dataclass_fields__ 

92 } 

93 

94 def add_rule(keys: list[str], value: type[Compare]) -> None: 

95 combine_rules.append(keys) 

96 for key in keys: 

97 compare_rules[key] = value 

98 

99 ranger = CompareRange 

100 if range_digit_comparator: 

101 add_rule(["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum"], ranger) 

102 if range_length_comparator: 

103 add_rule(["minLength", "maxLength"], ranger) 

104 if range_items_comparator: 

105 add_rule(["minItems", "maxItems"], ranger) 

106 if range_properties_comparator: 

107 add_rule(["minProperties", "maxProperties"], ranger) 

108 

109 # Path-render filters 

110 if not path_render_with_properies: 

111 path_maker_ignore.append("properties") 

112 if not path_render_with_items: 

113 path_maker_ignore.append("items") 

114 

115 # User additions override defaults 

116 compare_rules.update(additional_compare_rules) 

117 combine_rules.extend(additional_combine_rules) 

118 pair_context_rules.extend([list(r) for r in additional_pair_context_rules]) 

119 context_rules.update({k: list(v) for k, v in additional_context_rules.items()}) 

120 path_maker_ignore.extend(additional_path_maker_ignore) 

121 

122 return Config( 

123 tab=tab, 

124 all_for_rendering=all_for_rendering, 

125 crop_path=crop_path, 

126 compare_rules=compare_rules, 

127 combine_rules=combine_rules, 

128 path_maker_ignore=path_maker_ignore, 

129 pair_context_rules=pair_context_rules, 

130 context_rules=context_rules, 

131 compare_config=compare_config, 

132 )