Coverage for src/jsoncrack_for_sphinx/config/config_parsing.py: 80%

96 statements  

« prev     ^ index     » next       coverage.py v7.10.0, created at 2025-07-24 22:26 +0000

1""" 

2Configuration parsing functions. 

3""" 

4 

5from typing import Any, Dict 

6 

7from ..search.search_policy import SearchPolicy 

8from ..utils.types import Directions, PathSeparator, RenderMode, Theme 

9from .config_classes import ContainerConfig, RenderConfig 

10from .config_main import JsonCrackConfig 

11 

12 

13def parse_config(config_dict: Dict[str, Any]) -> JsonCrackConfig: 

14 """Parse configuration dictionary into JsonCrackConfig object.""" 

15 

16 # Handle Mock objects in tests 

17 if not isinstance(config_dict, dict): 

18 return JsonCrackConfig() 

19 

20 # Parse render config 

21 render_config = None 

22 if "render" in config_dict: 

23 render_obj = config_dict["render"] 

24 if isinstance(render_obj, RenderConfig): 

25 render_config = render_obj 

26 elif isinstance(render_obj, dict) and "mode" in render_obj: 

27 # Legacy format support 

28 mode_obj = render_obj["mode"] 

29 if isinstance(mode_obj, str): 

30 # Convert string to RenderMode object 

31 if mode_obj == "onclick": 

32 mode_obj = RenderMode.OnClick() 

33 elif mode_obj == "onload": 

34 mode_obj = RenderMode.OnLoad() 

35 elif mode_obj == "onscreen": 

36 threshold = render_obj.get("threshold", 0.1) 

37 margin = render_obj.get("margin", "50px") 

38 mode_obj = RenderMode.OnScreen(threshold=threshold, margin=margin) 

39 else: 

40 # Default to onclick for unknown modes 

41 mode_obj = RenderMode.OnClick() 

42 elif isinstance(mode_obj, dict) and "type" in mode_obj: 

43 # Handle nested mode object 

44 mode_type = mode_obj["type"] 

45 if mode_type == "onclick": 

46 mode_obj = RenderMode.OnClick() 

47 elif mode_type == "onload": 

48 mode_obj = RenderMode.OnLoad() 

49 elif mode_type == "onscreen": 

50 threshold = mode_obj.get("threshold", 0.1) 

51 margin = mode_obj.get("margin", "50px") 

52 mode_obj = RenderMode.OnScreen(threshold=threshold, margin=margin) 

53 else: 

54 # Default to onclick for unknown modes 

55 mode_obj = RenderMode.OnClick() 

56 else: 

57 # Fallback for any other type 

58 mode_obj = RenderMode.OnClick() 

59 render_config = RenderConfig(mode_obj) 

60 

61 # Parse container config 

62 container_config = None 

63 if "container" in config_dict: 

64 container_obj = config_dict["container"] 

65 if isinstance(container_obj, ContainerConfig): 

66 container_config = container_obj 

67 elif isinstance(container_obj, dict): 

68 # Legacy format support 

69 direction_str = container_obj.get("direction", "RIGHT") 

70 if isinstance(direction_str, str): 

71 if direction_str == "LEFT": 

72 direction = Directions.LEFT 

73 elif direction_str == "RIGHT": 

74 direction = Directions.RIGHT 

75 elif direction_str == "TOP": 

76 direction = Directions.TOP 

77 elif direction_str == "DOWN": 

78 direction = Directions.DOWN 

79 else: 

80 # Default to RIGHT for unknown directions 

81 direction = Directions.RIGHT 

82 else: 

83 direction = direction_str 

84 

85 container_config = ContainerConfig( 

86 direction=direction, 

87 height=container_obj.get("height", "500"), 

88 width=container_obj.get("width", "100%"), 

89 ) 

90 

91 # Parse search policy 

92 search_policy = None 

93 if "search_policy" in config_dict: 

94 policy_obj = config_dict["search_policy"] 

95 if isinstance(policy_obj, SearchPolicy): 

96 search_policy = policy_obj 

97 elif isinstance(policy_obj, dict): 

98 # Parse from dictionary 

99 include_package = policy_obj.get("include_package_name", False) 

100 include_path = policy_obj.get("include_path_to_file", True) 

101 

102 # Parse path separators 

103 path_to_file = policy_obj.get("path_to_file_separator", ".") 

104 if isinstance(path_to_file, str): 

105 if path_to_file == ".": 

106 path_to_file = PathSeparator.DOT 

107 elif path_to_file == "/": 

108 path_to_file = PathSeparator.SLASH 

109 elif path_to_file.lower() == "none": 

110 path_to_file = PathSeparator.NONE 

111 else: 

112 path_to_file = PathSeparator.DOT 

113 

114 path_to_class = policy_obj.get("path_to_class_separator", ".") 

115 if isinstance(path_to_class, str): 

116 if path_to_class == ".": 

117 path_to_class = PathSeparator.DOT 

118 elif path_to_class == "/": 

119 path_to_class = PathSeparator.SLASH 

120 elif path_to_class.lower() == "none": 

121 path_to_class = PathSeparator.NONE 

122 else: 

123 path_to_class = PathSeparator.DOT 

124 

125 custom_patterns = policy_obj.get("custom_patterns", []) 

126 

127 search_policy = SearchPolicy( 

128 include_package_name=include_package, 

129 include_path_to_file=include_path, 

130 path_to_file_separator=path_to_file, 

131 path_to_class_separator=path_to_class, 

132 custom_patterns=custom_patterns, 

133 ) 

134 

135 # Parse theme 

136 theme_obj = config_dict.get("theme", Theme.AUTO) 

137 if isinstance(theme_obj, str): 

138 if theme_obj == "light": 

139 theme = Theme.LIGHT 

140 elif theme_obj == "dark": 

141 theme = Theme.DARK 

142 elif theme_obj == "auto": 

143 theme = Theme.AUTO 

144 else: 

145 theme = Theme.AUTO 

146 else: 

147 theme = theme_obj 

148 

149 return JsonCrackConfig( 

150 render=render_config or RenderConfig(RenderMode.OnClick()), 

151 container=container_config or ContainerConfig(), 

152 theme=theme, 

153 search_policy=search_policy or SearchPolicy(), 

154 disable_autodoc=config_dict.get("disable_autodoc", False), 

155 autodoc_ignore=config_dict.get("autodoc_ignore", []), 

156 )