Coverage for openhcs/textual_tui/services/pattern_data_manager.py: 0.0%

80 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-04 02:09 +0000

1""" 

2Pattern Data Manager - Pure data operations for function patterns. 

3 

4This service handles pattern data structure operations and transformations 

5with order determinism and immutable operations. 

6""" 

7 

8import copy 

9from typing import Union, List, Dict, Tuple, Optional, Callable, Any 

10 

11 

12class PatternDataManager: 

13 """ 

14 Pure data operations for function patterns. 

15  

16 Handles List↔Dict conversions, cloning, and data transformations 

17 with order determinism and immutable operations. 

18 """ 

19 

20 @staticmethod 

21 def clone_pattern(pattern: Union[List, Dict]) -> Union[List, Dict]: 

22 """ 

23 Deep clone preserving callable references exactly. 

24  

25 Args: 

26 pattern: Pattern to clone (List or Dict) 

27  

28 Returns: 

29 Deep cloned pattern with preserved callable references 

30 """ 

31 if pattern is None: 

32 return [] 

33 return copy.deepcopy(pattern) 

34 

35 @staticmethod 

36 def convert_list_to_dict(pattern: List) -> Dict: 

37 """ 

38 Convert List pattern to empty Dict - user must add component keys manually. 

39 

40 Args: 

41 pattern: List pattern to convert (will be discarded) 

42 

43 Returns: 

44 Empty dict for user to populate with experimental component identifiers 

45 """ 

46 if not isinstance(pattern, list): 

47 raise ValueError(f"Expected list, got {type(pattern)}") 

48 

49 # Return empty dict - user will add experimental component keys manually 

50 return {} 

51 

52 @staticmethod 

53 def convert_dict_to_list(pattern: Dict) -> Union[List, Dict]: 

54 """ 

55 Convert Dict pattern to List when empty. 

56 

57 Args: 

58 pattern: Dict pattern to potentially convert 

59 

60 Returns: 

61 Empty list if dict is empty, otherwise returns original dict 

62 """ 

63 if not isinstance(pattern, dict): 

64 raise ValueError(f"Expected dict, got {type(pattern)}") 

65 

66 # Convert to empty list if dict is empty 

67 if not pattern: 

68 return [] 

69 

70 # Keep as dict if it has keys 

71 return pattern 

72 

73 @staticmethod 

74 def extract_func_and_kwargs(func_item) -> Tuple[Optional[Callable], Dict]: 

75 """ 

76 Parse (func, kwargs) tuples and bare callables. 

77 

78 Handles both tuple format and bare callable format exactly as current logic. 

79 

80 Args: 

81 func_item: Either (callable, kwargs) tuple or bare callable 

82 

83 Returns: 

84 Tuple of (callable, kwargs_dict) 

85 """ 

86 # EXACT current logic preservation 

87 if isinstance(func_item, tuple) and len(func_item) == 2 and callable(func_item[0]): 

88 result = func_item[0], func_item[1] 

89 print(f"🔍 PATTERN DATA MANAGER extract_func_and_kwargs: tuple case - returning {result}") 

90 return result 

91 elif callable(func_item): 

92 result = func_item, {} 

93 print(f"🔍 PATTERN DATA MANAGER extract_func_and_kwargs: callable case - returning {result}") 

94 return result 

95 else: 

96 print("🔍 PATTERN DATA MANAGER extract_func_and_kwargs: neither tuple nor callable - returning None, {}") 

97 return None, {} 

98 

99 @staticmethod 

100 def validate_pattern_structure(pattern: Union[List, Dict]) -> bool: 

101 """ 

102 Basic structural validation of pattern. 

103  

104 Args: 

105 pattern: Pattern to validate 

106  

107 Returns: 

108 True if structure is valid, False otherwise 

109 """ 

110 if pattern is None: 

111 return True 

112 

113 if isinstance(pattern, list): 

114 # Validate list items are callables or (callable, dict) tuples 

115 for item in pattern: 

116 func, kwargs = PatternDataManager.extract_func_and_kwargs(item) 

117 if func is None: 

118 return False 

119 if not isinstance(kwargs, dict): 

120 return False 

121 return True 

122 

123 elif isinstance(pattern, dict): 

124 # Validate dict values are lists of callables 

125 for key, value in pattern.items(): 

126 if not isinstance(value, list): 

127 return False 

128 # Recursively validate the list 

129 if not PatternDataManager.validate_pattern_structure(value): 

130 return False 

131 return True 

132 

133 else: 

134 return False 

135 

136 @staticmethod 

137 def get_current_functions(pattern: Union[List, Dict], key: Any, is_dict: bool) -> List: 

138 """ 

139 Extract function list for current context. 

140  

141 Args: 

142 pattern: Full pattern (List or Dict) 

143 key: Current key (for Dict patterns) 

144 is_dict: Whether pattern is currently in dict mode 

145  

146 Returns: 

147 List of functions for current context 

148 """ 

149 if is_dict and isinstance(pattern, dict): 

150 return pattern.get(key, []) 

151 elif not is_dict and isinstance(pattern, list): 

152 return pattern 

153 else: 

154 return [] 

155 

156 @staticmethod 

157 def update_pattern_functions(pattern: Union[List, Dict], key: Any, is_dict: bool, 

158 new_functions: List) -> Union[List, Dict]: 

159 """ 

160 Update functions in pattern for current context. 

161  

162 Returns new pattern object (immutable operation). 

163  

164 Args: 

165 pattern: Original pattern 

166 key: Current key (for Dict patterns) 

167 is_dict: Whether pattern is in dict mode 

168 new_functions: New function list 

169  

170 Returns: 

171 New pattern with updated functions 

172 """ 

173 if is_dict and isinstance(pattern, dict): 

174 new_pattern = copy.deepcopy(pattern) 

175 new_pattern[key] = new_functions 

176 return new_pattern 

177 elif not is_dict and isinstance(pattern, list): 

178 return copy.deepcopy(new_functions) 

179 else: 

180 # Fallback - return original pattern 

181 return copy.deepcopy(pattern) 

182 

183 @staticmethod 

184 def add_new_key(pattern: Dict, new_key: str) -> Dict: 

185 """ 

186 Add new key to dict pattern. 

187  

188 Args: 

189 pattern: Dict pattern 

190 new_key: Key to add 

191  

192 Returns: 

193 New dict with added key 

194 """ 

195 new_pattern = copy.deepcopy(pattern) 

196 if new_key not in new_pattern: 

197 new_pattern[new_key] = [] 

198 return new_pattern 

199 

200 @staticmethod 

201 def remove_key(pattern: Dict, key_to_remove: Any) -> Union[List, Dict]: 

202 """ 

203 Remove key from dict pattern. 

204 

205 If dict becomes empty after removal, converts back to list. 

206 

207 Args: 

208 pattern: Dict pattern 

209 key_to_remove: Key to remove 

210 

211 Returns: 

212 New pattern (List if dict becomes empty, Dict otherwise) 

213 """ 

214 new_pattern = copy.deepcopy(pattern) 

215 if key_to_remove in new_pattern: 

216 del new_pattern[key_to_remove] 

217 

218 # Check if should convert back to list (when empty) 

219 return PatternDataManager.convert_dict_to_list(new_pattern)