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

78 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-14 05:57 +0000

1""" 

2Function Registry Service - Enhanced function discovery and metadata. 

3 

4This service extends existing func_registry functionality with enhanced metadata 

5extraction and UI-specific formatting while avoiding import collisions. 

6""" 

7 

8from typing import Dict, List, Tuple, Callable, Any, Optional 

9import logging 

10 

11# Import from func_registry to avoid circular imports 

12# The FUNC_REGISTRY is auto-initialized on import (following storage_registry pattern) 

13from openhcs.processing.func_registry import FUNC_REGISTRY, get_function_info, get_functions_by_memory_type 

14 

15logger = logging.getLogger(__name__) 

16 

17 

18class FunctionRegistryService: 

19 """ 

20 Stateless service for function registry integration and metadata extraction. 

21  

22 Extends existing FUNC_REGISTRY functionality with enhanced metadata 

23 and UI-specific formatting. 

24 """ 

25 

26 @staticmethod 

27 def get_functions_by_backend() -> Dict[str, List[Tuple[Callable, str]]]: 

28 """ 

29 Group FUNC_REGISTRY functions by backend with memory type display names. 

30  

31 EXACT backend grouping logic - preserves current behavior. 

32  

33 Returns: 

34 Dict mapping backend names to lists of (function, display_name) tuples 

35 """ 

36 functions_by_backend = {} 

37 

38 # CORRECT: Iterate over memory types, then functions within each type 

39 for memory_type in FUNC_REGISTRY: 

40 for func in FUNC_REGISTRY[memory_type]: 

41 try: 

42 # Get basic function info using existing registry 

43 func_info = get_function_info(func) 

44 

45 backend = func_info.get('backend', 'unknown') 

46 input_type = func_info.get('input_memory_type', 'unknown') 

47 output_type = func_info.get('output_memory_type', 'unknown') 

48 

49 # Clean display format - show only function name, backend is shown separately 

50 display_name = func.__name__ 

51 

52 if backend not in functions_by_backend: 

53 functions_by_backend[backend] = [] 

54 

55 functions_by_backend[backend].append((func, display_name)) 

56 

57 except Exception as e: 

58 logger.warning(f"Failed to get info for function {func}: {e}") 

59 # Add to unknown backend as fallback 

60 if 'unknown' not in functions_by_backend: 

61 functions_by_backend['unknown'] = [] 

62 functions_by_backend['unknown'].append((func, func.__name__)) 

63 

64 return functions_by_backend 

65 

66 @staticmethod 

67 def get_enhanced_function_metadata(func: Callable) -> Dict[str, Any]: 

68 """ 

69 Enhanced version of get_function_info with validation and special inputs/outputs. 

70  

71 RENAMED to avoid import collision with existing get_function_info. 

72  

73 Args: 

74 func: Function to analyze 

75  

76 Returns: 

77 Enhanced metadata dict with same structure as get_function_info plus validation 

78 """ 

79 try: 

80 # Start with existing function info 

81 base_info = get_function_info(func) 

82 

83 # Enhance with additional metadata 

84 enhanced_info = { 

85 'name': base_info.get('name', func.__name__), 

86 'backend': base_info.get('backend', 'unknown'), 

87 'input_memory_type': base_info.get('input_memory_type', 'unknown'), 

88 'output_memory_type': base_info.get('output_memory_type', 'unknown'), 

89 'special_inputs': base_info.get('special_inputs', []), 

90 'special_outputs': base_info.get('special_outputs', []), 

91 } 

92 

93 # Add validation status 

94 enhanced_info['is_valid'] = True 

95 enhanced_info['validation_errors'] = [] 

96 

97 # Basic validation checks 

98 if enhanced_info['backend'] == 'unknown': 

99 enhanced_info['validation_errors'].append("Unknown backend") 

100 

101 if enhanced_info['input_memory_type'] == 'unknown': 

102 enhanced_info['validation_errors'].append("Unknown input memory type") 

103 

104 if enhanced_info['output_memory_type'] == 'unknown': 

105 enhanced_info['validation_errors'].append("Unknown output memory type") 

106 

107 if enhanced_info['validation_errors']: 

108 enhanced_info['is_valid'] = False 

109 

110 return enhanced_info 

111 

112 except Exception as e: 

113 logger.error(f"Failed to get enhanced metadata for {func}: {e}") 

114 # Return minimal fallback info 

115 return { 

116 'name': getattr(func, '__name__', 'unknown'), 

117 'backend': 'unknown', 

118 'input_memory_type': 'unknown', 

119 'output_memory_type': 'unknown', 

120 'special_inputs': [], 

121 'special_outputs': [], 

122 'is_valid': False, 

123 'validation_errors': [f"Metadata extraction failed: {e}"] 

124 } 

125 

126 @staticmethod 

127 def create_dropdown_options(functions_by_backend: Dict[str, List[Tuple[Callable, str]]]) -> List[Tuple[str, List[Tuple[Callable, str]]]]: 

128 """ 

129 Format function groups for GroupedDropdown component. 

130  

131 Args: 

132 functions_by_backend: Output from get_functions_by_backend() 

133  

134 Returns: 

135 List of (group_name, options) tuples for GroupedDropdown 

136 """ 

137 dropdown_options = [] 

138 

139 # Sort backends for consistent ordering 

140 sorted_backends = sorted(functions_by_backend.keys()) 

141 

142 for backend in sorted_backends: 

143 functions = functions_by_backend[backend] 

144 # Sort functions by display name for consistent ordering 

145 sorted_functions = sorted(functions, key=lambda x: x[1]) 

146 dropdown_options.append((backend, sorted_functions)) 

147 

148 return dropdown_options 

149 

150 @staticmethod 

151 def find_default_function() -> Optional[Callable]: 

152 """ 

153 Get first available function for new items. 

154 

155 Returns: 

156 First function from FUNC_REGISTRY, or None if empty 

157 """ 

158 # CORRECT: Iterate through memory types to find first function 

159 for memory_type in FUNC_REGISTRY: 

160 if FUNC_REGISTRY[memory_type]: # Check if list is not empty 

161 return FUNC_REGISTRY[memory_type][0] 

162 return None 

163 

164 @staticmethod 

165 def get_functions_by_memory_type_wrapper(memory_type: str) -> List[Callable]: 

166 """ 

167 Wrapper around existing get_functions_by_memory_type for consistency. 

168  

169 Args: 

170 memory_type: Memory type to filter by 

171  

172 Returns: 

173 List of functions matching the memory type 

174 """ 

175 try: 

176 return get_functions_by_memory_type(memory_type) 

177 except Exception as e: 

178 logger.error(f"Failed to get functions by memory type {memory_type}: {e}") 

179 return [] 

180 

181 @staticmethod 

182 def validate_function_in_registry(func: Callable) -> bool: 

183 """ 

184 Check if function exists in FUNC_REGISTRY. 

185 

186 Args: 

187 func: Function to check 

188 

189 Returns: 

190 True if function is in registry, False otherwise 

191 """ 

192 # CORRECT: Check if function exists in any memory type list 

193 for memory_type in FUNC_REGISTRY: 

194 if func in FUNC_REGISTRY[memory_type]: 

195 return True 

196 return False 

197 

198 @staticmethod 

199 def get_function_display_name(func: Callable) -> str: 

200 """ 

201 Get formatted display name for function. 

202  

203 Args: 

204 func: Function to format 

205  

206 Returns: 

207 Formatted display name with memory types 

208 """ 

209 try: 

210 # Clean display format - just return function name 

211 # Backend information is displayed separately in the UI 

212 return func.__name__ 

213 except Exception: 

214 return func.__name__