kailash 0.9.14__py3-none-any.whl → 0.9.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kailash/__init__.py CHANGED
@@ -6,6 +6,7 @@ that align with container-node architecture while allowing rapid prototyping.
6
6
  New in v0.9.14: Code quality improvements and updated dependencies for DataFlow v0.4.6 compatibility.
7
7
  Applied black formatting fixes and ensured CI stability. Updated dependency references to latest framework versions.
8
8
  Previous v0.9.13: Fixed WorkflowBuilder parameter validation false positives (Bug 010).
9
+ Enhanced validation.py to recognize auto_map_from parameters, eliminating spurious warnings.
9
10
  Previous v0.9.12: SQLite Compatibility & Code Quality improvements.
10
11
  Previous v0.9.2: WebSocket Transport Support with Enterprise Connection Pooling.
11
12
  Fixed "Unsupported transport: websocket" error. Added 73% performance improvement with connection pooling.
@@ -38,7 +38,7 @@ Examples:
38
38
  %(prog)s src/myapp # Validate specific directory
39
39
  %(prog)s src/myapp --fix # Show import fixes (dry run)
40
40
  %(prog)s --file module.py # Validate single file
41
-
41
+
42
42
  For more info, see: sdk-users/7-gold-standards/absolute-imports-gold-standard.md
43
43
  """,
44
44
  )
@@ -59,8 +59,8 @@ class QueryPatternTracker:
59
59
  """Tracks and analyzes query execution patterns."""
60
60
 
61
61
  def __init__(
62
- self, retention_hours: int = 168, min_pattern_frequency: int = 5 # 7 days
63
- ):
62
+ self, retention_hours: int = 168, min_pattern_frequency: int = 5
63
+ ): # 7 days
64
64
  self.retention_hours = retention_hours
65
65
  self.min_pattern_frequency = min_pattern_frequency
66
66
 
@@ -14,10 +14,7 @@ from .cloud_integration import (
14
14
  InstanceState,
15
15
  )
16
16
  from .cost_optimizer import CloudProvider as CostCloudProvider
17
- from .cost_optimizer import (
18
- CostOptimizer,
19
- OptimizationStrategy,
20
- )
17
+ from .cost_optimizer import CostOptimizer, OptimizationStrategy
21
18
  from .docker_integration import (
22
19
  ContainerSpec,
23
20
  ContainerState,
@@ -227,7 +227,7 @@ class SensitiveData:
227
227
  user_id: int
228
228
  personal_info: dict
229
229
  location: str
230
-
230
+
231
231
  __dataflow__ = {
232
232
  'multi_tenant': True,
233
233
  'soft_delete': True,
@@ -247,7 +247,7 @@ class SensitiveData:
247
247
 
248
248
  # When using generated nodes in workflows:
249
249
  workflow = WorkflowBuilder(edge_config=DataFlowEdgeIntegration.create_edge_workflow_config(
250
- 'SensitiveData',
250
+ 'SensitiveData',
251
251
  SensitiveData.__dataflow__['edge_config']
252
252
  ))
253
253
 
@@ -8,13 +8,7 @@ import uuid
8
8
  from datetime import datetime, timezone
9
9
  from typing import Any, Dict, List, Optional
10
10
 
11
- from sqlalchemy import (
12
- JSON,
13
- Boolean,
14
- CheckConstraint,
15
- Column,
16
- DateTime,
17
- )
11
+ from sqlalchemy import JSON, Boolean, CheckConstraint, Column, DateTime
18
12
  from sqlalchemy import Enum as SQLEnum
19
13
  from sqlalchemy import (
20
14
  Float,
@@ -260,12 +260,12 @@ class EmailNotificationChannel(NotificationChannel):
260
260
  <p><strong>Status:</strong> {alert.status.value}</p>
261
261
  <p><strong>Description:</strong> {alert.description}</p>
262
262
  <p><strong>Created:</strong> {alert.created_at.isoformat()}</p>
263
-
263
+
264
264
  <h3>Labels:</h3>
265
265
  <ul>
266
266
  {"".join(f"<li><strong>{k}:</strong> {v}</li>" for k, v in alert.labels.items())}
267
267
  </ul>
268
-
268
+
269
269
  <h3>Context:</h3>
270
270
  <ul>
271
271
  {"".join(f"<li><strong>{k}:</strong> {v}</li>" for k, v in context.items())}
kailash/nodes/__init__.py CHANGED
@@ -1,42 +1,24 @@
1
- """Node system for the Kailash SDK."""
2
-
3
- # Import all node modules to ensure registration - fixed circular import
4
- from kailash.nodes.base import Node, NodeParameter, NodeRegistry, register_node
5
- from kailash.nodes.base_cycle_aware import CycleAwareNode
6
- from kailash.nodes.code import PythonCodeNode
7
-
8
- from . import (
9
- ai,
10
- alerts,
11
- api,
12
- auth,
13
- cache,
14
- code,
15
- compliance,
16
- data,
17
- edge,
18
- enterprise,
19
- logic,
20
- mixins,
21
- monitoring,
22
- security,
23
- testing,
24
- transaction,
25
- transform,
26
- )
27
-
28
- # Compatibility alias - AsyncNode is now just Node
29
- AsyncNode = Node
30
-
31
- __all__ = [
32
- "Node",
33
- "AsyncNode", # Compatibility alias
34
- "CycleAwareNode",
35
- "NodeParameter",
36
- "NodeRegistry",
37
- "register_node",
38
- "PythonCodeNode",
39
- # Node modules
1
+ """
2
+ Kailash SDK Nodes Module - Safe Lazy Loading Implementation
3
+
4
+ This implementation provides lazy loading with circular dependency protection
5
+ and maintains full backward compatibility.
6
+ """
7
+
8
+ import importlib
9
+ import sys
10
+ import warnings
11
+ from typing import Any, Dict, Optional, Set
12
+
13
+ # Core imports that are always needed
14
+ from .base import Node, NodeParameter, NodeRegistry
15
+
16
+ # Track loading state to detect circular dependencies
17
+ _LOADING_STACK: Set[str] = set()
18
+ _LOADED_MODULES: Dict[str, Optional[Any]] = {}
19
+
20
+ # Define available node categories for lazy loading
21
+ _NODE_CATEGORIES = [
40
22
  "ai",
41
23
  "alerts",
42
24
  "api",
@@ -50,8 +32,198 @@ __all__ = [
50
32
  "logic",
51
33
  "mixins",
52
34
  "monitoring",
35
+ "rag",
53
36
  "security",
54
37
  "testing",
55
38
  "transaction",
56
39
  "transform",
57
40
  ]
41
+
42
+ # Initialize lazy module cache
43
+ _LAZY_MODULES: Dict[str, Optional[Any]] = {
44
+ category: None for category in _NODE_CATEGORIES
45
+ }
46
+
47
+
48
+ def _safe_lazy_import(name: str) -> Any:
49
+ """
50
+ Safely import a module with circular dependency detection.
51
+
52
+ Args:
53
+ name: The module name to import
54
+
55
+ Returns:
56
+ The imported module
57
+
58
+ Raises:
59
+ ImportError: If a circular dependency is detected
60
+ """
61
+ full_module_name = f"kailash.nodes.{name}"
62
+
63
+ # Check if already loaded
64
+ if name in _LOADED_MODULES:
65
+ return _LOADED_MODULES[name]
66
+
67
+ # Check for circular dependency
68
+ if full_module_name in _LOADING_STACK:
69
+ cycle_modules = list(_LOADING_STACK) + [full_module_name]
70
+ warnings.warn(
71
+ f"Circular dependency detected: {' -> '.join(cycle_modules)}. "
72
+ f"Using partial import to break the cycle.",
73
+ ImportWarning,
74
+ stacklevel=3,
75
+ )
76
+ # Return a placeholder that will be populated after loading
77
+ module = sys.modules.get(full_module_name)
78
+ if module:
79
+ return module
80
+ # Create empty module as placeholder
81
+ module = type(sys)("placeholder")
82
+ sys.modules[full_module_name] = module
83
+ return module
84
+
85
+ # Add to loading stack
86
+ _LOADING_STACK.add(full_module_name)
87
+
88
+ try:
89
+ # Perform the actual import
90
+ module = importlib.import_module(f".{name}", package="kailash.nodes")
91
+ _LOADED_MODULES[name] = module
92
+ return module
93
+ finally:
94
+ # Remove from loading stack
95
+ _LOADING_STACK.discard(full_module_name)
96
+
97
+
98
+ def __getattr__(name: str) -> Any:
99
+ """
100
+ Lazy loading of node category modules with circular dependency protection.
101
+
102
+ This function is called when accessing an attribute that doesn't exist
103
+ in the module's namespace. It enables lazy loading of node categories
104
+ while detecting and handling circular dependencies.
105
+
106
+ Args:
107
+ name: The attribute name being accessed
108
+
109
+ Returns:
110
+ The requested module or attribute
111
+
112
+ Raises:
113
+ AttributeError: If the attribute doesn't exist
114
+ """
115
+ # Check if it's a known node category
116
+ if name in _LAZY_MODULES:
117
+ if _LAZY_MODULES[name] is None:
118
+ try:
119
+ # Use safe import with circular dependency detection
120
+ _LAZY_MODULES[name] = _safe_lazy_import(name)
121
+ except ImportError as e:
122
+ # Log the error and re-raise
123
+ import logging
124
+
125
+ logging.error(f"Failed to import kailash.nodes.{name}: {e}")
126
+ raise
127
+ return _LAZY_MODULES[name]
128
+
129
+ # Handle special attributes
130
+ if name == "__all__":
131
+ return ["Node", "NodeParameter", "NodeRegistry"] + _NODE_CATEGORIES
132
+
133
+ # Attribute not found
134
+ raise AttributeError(f"module 'kailash.nodes' has no attribute '{name}'")
135
+
136
+
137
+ def __dir__():
138
+ """Return the list of available attributes for tab completion."""
139
+ return ["Node", "NodeParameter", "NodeRegistry"] + _NODE_CATEGORIES
140
+
141
+
142
+ def check_circular_dependencies() -> Dict[str, Any]:
143
+ """
144
+ Check for circular dependencies in the nodes module.
145
+
146
+ Returns:
147
+ A dictionary containing:
148
+ - has_circular_deps: Boolean indicating if circular deps exist
149
+ - circular_chains: List of circular dependency chains found
150
+ - warnings: List of warning messages
151
+ """
152
+ from pathlib import Path
153
+
154
+ from ..utils.circular_dependency_detector import CircularDependencyDetector
155
+
156
+ # Get the SDK root directory
157
+ sdk_root = Path(__file__).parent.parent.parent
158
+
159
+ detector = CircularDependencyDetector(sdk_root)
160
+ detector.build_import_graph("src/kailash/nodes")
161
+ cycles = detector.detect_cycles()
162
+
163
+ result = {
164
+ "has_circular_deps": bool(cycles),
165
+ "circular_chains": cycles,
166
+ "warnings": [],
167
+ }
168
+
169
+ if cycles:
170
+ for cycle in cycles:
171
+ result["warnings"].append(
172
+ f"Circular dependency detected: {' -> '.join(cycle)} -> {cycle[0]}"
173
+ )
174
+
175
+ return result
176
+
177
+
178
+ def preload_all_categories():
179
+ """
180
+ Preload all node categories (useful for testing or warming up).
181
+
182
+ This function loads all node categories immediately rather than lazily.
183
+ It's useful for:
184
+ - Testing that all imports work correctly
185
+ - Warming up the import cache
186
+ - Detecting circular dependencies early
187
+ """
188
+ failed_imports = []
189
+
190
+ for category in _NODE_CATEGORIES:
191
+ try:
192
+ _safe_lazy_import(category)
193
+ except ImportError as e:
194
+ failed_imports.append((category, str(e)))
195
+
196
+ if failed_imports:
197
+ warnings.warn(
198
+ f"Failed to import some categories: {failed_imports}", ImportWarning
199
+ )
200
+
201
+ return {
202
+ "loaded": [cat for cat in _NODE_CATEGORIES if cat in _LOADED_MODULES],
203
+ "failed": failed_imports,
204
+ }
205
+
206
+
207
+ # Performance monitoring
208
+ def get_import_stats() -> Dict[str, Any]:
209
+ """
210
+ Get statistics about module imports.
211
+
212
+ Returns:
213
+ Dictionary containing import statistics
214
+ """
215
+ return {
216
+ "loaded_modules": list(_LOADED_MODULES.keys()),
217
+ "pending_modules": [
218
+ cat for cat in _NODE_CATEGORIES if cat not in _LOADED_MODULES
219
+ ],
220
+ "total_categories": len(_NODE_CATEGORIES),
221
+ "loaded_count": len(_LOADED_MODULES),
222
+ "currently_loading": list(_LOADING_STACK),
223
+ }
224
+
225
+
226
+ # Backward compatibility - ensure all existing imports work
227
+ __all__ = ["Node", "NodeParameter", "NodeRegistry"] + _NODE_CATEGORIES
228
+
229
+ # Export core components directly
@@ -0,0 +1,57 @@
1
+ """Node system for the Kailash SDK."""
2
+
3
+ # Import all node modules to ensure registration - fixed circular import
4
+ from kailash.nodes.base import Node, NodeParameter, NodeRegistry, register_node
5
+ from kailash.nodes.base_cycle_aware import CycleAwareNode
6
+ from kailash.nodes.code import PythonCodeNode
7
+
8
+ from . import (
9
+ ai,
10
+ alerts,
11
+ api,
12
+ auth,
13
+ cache,
14
+ code,
15
+ compliance,
16
+ data,
17
+ edge,
18
+ enterprise,
19
+ logic,
20
+ mixins,
21
+ monitoring,
22
+ security,
23
+ testing,
24
+ transaction,
25
+ transform,
26
+ )
27
+
28
+ # Compatibility alias - AsyncNode is now just Node
29
+ AsyncNode = Node
30
+
31
+ __all__ = [
32
+ "Node",
33
+ "AsyncNode", # Compatibility alias
34
+ "CycleAwareNode",
35
+ "NodeParameter",
36
+ "NodeRegistry",
37
+ "register_node",
38
+ "PythonCodeNode",
39
+ # Node modules
40
+ "ai",
41
+ "alerts",
42
+ "api",
43
+ "auth",
44
+ "cache",
45
+ "code",
46
+ "compliance",
47
+ "data",
48
+ "edge",
49
+ "enterprise",
50
+ "logic",
51
+ "mixins",
52
+ "monitoring",
53
+ "security",
54
+ "testing",
55
+ "transaction",
56
+ "transform",
57
+ ]
@@ -1666,7 +1666,7 @@ class IterativeLLMAgentNode(LLMAgentNode):
1666
1666
  synthesis_messages = [
1667
1667
  {
1668
1668
  "role": "system",
1669
- "content": """You are an AI assistant synthesizing results from an iterative analysis process.
1669
+ "content": """You are an AI assistant synthesizing results from an iterative analysis process.
1670
1670
  Create a comprehensive, helpful response based on the findings from multiple iterations of analysis.""",
1671
1671
  },
1672
1672
  {
@@ -1679,7 +1679,7 @@ Results from {len(iterations)} iterations:
1679
1679
  Insights achieved:
1680
1680
  {chr(10).join(all_insights[:5]) if all_insights else "No specific insights achieved"}
1681
1681
 
1682
- Please provide a comprehensive response to the original query based on these findings. If the findings are limited,
1682
+ Please provide a comprehensive response to the original query based on these findings. If the findings are limited,
1683
1683
  provide your best analysis of the query directly.""",
1684
1684
  },
1685
1685
  ]
@@ -0,0 +1,319 @@
1
+ """
2
+ Circular Dependency Detector for Kailash SDK
3
+
4
+ This module provides tools to detect and report circular dependencies in the codebase,
5
+ ensuring that lazy loading doesn't mask architectural issues.
6
+ """
7
+
8
+ import ast
9
+ import importlib
10
+ import os
11
+ import sys
12
+ from collections import defaultdict, deque
13
+ from pathlib import Path
14
+ from typing import Dict, List, Optional, Set, Tuple
15
+
16
+
17
+ class CircularDependencyDetector:
18
+ """Detects circular dependencies in Python modules."""
19
+
20
+ def __init__(self, root_path: str):
21
+ """Initialize the detector with the root path of the codebase."""
22
+ self.root_path = Path(root_path)
23
+ self.import_graph: Dict[str, Set[str]] = defaultdict(set)
24
+ self.visited_files: Set[str] = set()
25
+ self.circular_deps: List[List[str]] = []
26
+
27
+ def analyze_file(self, file_path: Path) -> Set[str]:
28
+ """Extract all imports from a Python file."""
29
+ imports = set()
30
+
31
+ try:
32
+ with open(file_path, "r", encoding="utf-8") as f:
33
+ tree = ast.parse(f.read(), str(file_path))
34
+
35
+ for node in ast.walk(tree):
36
+ if isinstance(node, ast.Import):
37
+ for alias in node.names:
38
+ imports.add(alias.name)
39
+ elif isinstance(node, ast.ImportFrom):
40
+ if node.module:
41
+ # Handle relative imports
42
+ if node.level > 0:
43
+ # Relative import
44
+ module_parts = (
45
+ str(file_path.relative_to(self.root_path))
46
+ .replace(".py", "")
47
+ .split("/")
48
+ )
49
+ parent_parts = (
50
+ module_parts[: -node.level]
51
+ if node.level < len(module_parts)
52
+ else []
53
+ )
54
+ if node.module:
55
+ full_module = ".".join(
56
+ parent_parts + node.module.split(".")
57
+ )
58
+ else:
59
+ full_module = ".".join(parent_parts)
60
+ imports.add(full_module.replace("/", "."))
61
+ else:
62
+ imports.add(node.module)
63
+
64
+ except (SyntaxError, FileNotFoundError) as e:
65
+ print(f"Error analyzing {file_path}: {e}")
66
+
67
+ return imports
68
+
69
+ def build_import_graph(self, start_dir: str = "src/kailash"):
70
+ """Build the complete import dependency graph."""
71
+ start_path = self.root_path / start_dir
72
+
73
+ for py_file in start_path.rglob("*.py"):
74
+ # Skip test files and __pycache__
75
+ if "__pycache__" in str(py_file) or "test_" in py_file.name:
76
+ continue
77
+
78
+ module_name = self._path_to_module(py_file)
79
+ imports = self.analyze_file(py_file)
80
+
81
+ # Filter to only internal imports
82
+ internal_imports = {
83
+ imp
84
+ for imp in imports
85
+ if imp.startswith("kailash") or imp.startswith(".")
86
+ }
87
+
88
+ self.import_graph[module_name].update(internal_imports)
89
+
90
+ def _path_to_module(self, file_path: Path) -> str:
91
+ """Convert file path to module name."""
92
+ relative = file_path.relative_to(self.root_path / "src")
93
+ module = str(relative).replace(".py", "").replace("/", ".")
94
+ return module
95
+
96
+ def detect_cycles(self) -> List[List[str]]:
97
+ """Detect all circular dependencies using DFS."""
98
+ visited = set()
99
+ rec_stack = set()
100
+ path = []
101
+ cycles = []
102
+
103
+ def dfs(module: str) -> bool:
104
+ visited.add(module)
105
+ rec_stack.add(module)
106
+ path.append(module)
107
+
108
+ for imported in self.import_graph.get(module, set()):
109
+ if imported not in visited:
110
+ if dfs(imported):
111
+ return True
112
+ elif imported in rec_stack:
113
+ # Found a cycle
114
+ cycle_start = path.index(imported)
115
+ cycle = path[cycle_start:] + [imported]
116
+ cycles.append(cycle)
117
+
118
+ path.pop()
119
+ rec_stack.remove(module)
120
+ return False
121
+
122
+ for module in self.import_graph:
123
+ if module not in visited:
124
+ dfs(module)
125
+
126
+ # Remove duplicate cycles
127
+ unique_cycles = []
128
+ seen = set()
129
+ for cycle in cycles:
130
+ # Normalize cycle to start with smallest element
131
+ min_idx = cycle.index(min(cycle))
132
+ normalized = tuple(cycle[min_idx:] + cycle[:min_idx])
133
+ if normalized not in seen:
134
+ seen.add(normalized)
135
+ unique_cycles.append(
136
+ list(normalized)[:-1]
137
+ ) # Remove duplicate last element
138
+
139
+ return unique_cycles
140
+
141
+ def check_lazy_loading_safety(self, module_path: str) -> Dict[str, any]:
142
+ """Check if lazy loading is safe for a given module."""
143
+ result = {
144
+ "module": module_path,
145
+ "has_circular_deps": False,
146
+ "circular_chains": [],
147
+ "safe_for_lazy_loading": True,
148
+ "warnings": [],
149
+ }
150
+
151
+ # Check if module is involved in any circular dependencies
152
+ for cycle in self.circular_deps:
153
+ if module_path in cycle:
154
+ result["has_circular_deps"] = True
155
+ result["circular_chains"].append(cycle)
156
+ result["safe_for_lazy_loading"] = False
157
+ result["warnings"].append(
158
+ f"Module is part of circular dependency: {' -> '.join(cycle)}"
159
+ )
160
+
161
+ return result
162
+
163
+ def generate_report(self) -> str:
164
+ """Generate a comprehensive circular dependency report."""
165
+ self.build_import_graph()
166
+ self.circular_deps = self.detect_cycles()
167
+
168
+ report = []
169
+ report.append("=" * 80)
170
+ report.append("CIRCULAR DEPENDENCY ANALYSIS REPORT")
171
+ report.append("=" * 80)
172
+ report.append("")
173
+
174
+ if not self.circular_deps:
175
+ report.append("✅ No circular dependencies detected!")
176
+ else:
177
+ report.append(
178
+ f"⚠️ Found {len(self.circular_deps)} circular dependency chains:"
179
+ )
180
+ report.append("")
181
+
182
+ for i, cycle in enumerate(self.circular_deps, 1):
183
+ report.append(f"{i}. Circular dependency chain:")
184
+ report.append(f" {' -> '.join(cycle)} -> {cycle[0]}")
185
+ report.append("")
186
+
187
+ # Analyze specific high-risk modules
188
+ high_risk_modules = [
189
+ "kailash.nodes.ai.a2a",
190
+ "kailash.nodes.ai.self_organizing",
191
+ "kailash.nodes.ai.intelligent_agent_orchestrator",
192
+ "kailash.nodes.__init__",
193
+ ]
194
+
195
+ report.append("-" * 80)
196
+ report.append("HIGH-RISK MODULE ANALYSIS")
197
+ report.append("-" * 80)
198
+
199
+ for module in high_risk_modules:
200
+ safety = self.check_lazy_loading_safety(module)
201
+ if safety["has_circular_deps"]:
202
+ report.append(f"\n❌ {module}:")
203
+ for warning in safety["warnings"]:
204
+ report.append(f" - {warning}")
205
+ else:
206
+ report.append(f"\n✅ {module}: No circular dependencies")
207
+
208
+ report.append("")
209
+ report.append("=" * 80)
210
+
211
+ return "\n".join(report)
212
+
213
+
214
+ class CircularImportResolver:
215
+ """Provides solutions for resolving circular dependencies."""
216
+
217
+ @staticmethod
218
+ def create_lazy_import_wrapper(
219
+ module_name: str, attribute_name: Optional[str] = None
220
+ ) -> str:
221
+ """Generate code for a lazy import wrapper."""
222
+ if attribute_name:
223
+ return f"""
224
+ def get_{attribute_name}():
225
+ \"\"\"Lazy import of {module_name}.{attribute_name}\"\"\"
226
+ from {module_name} import {attribute_name}
227
+ return {attribute_name}
228
+ """
229
+ else:
230
+ return f"""
231
+ def get_{module_name.split('.')[-1]}():
232
+ \"\"\"Lazy import of {module_name}\"\"\"
233
+ import {module_name}
234
+ return {module_name}
235
+ """
236
+
237
+ @staticmethod
238
+ def create_type_checking_import(module_name: str, types: List[str]) -> str:
239
+ """Generate code for TYPE_CHECKING imports to avoid runtime circular deps."""
240
+ return f"""
241
+ from typing import TYPE_CHECKING
242
+
243
+ if TYPE_CHECKING:
244
+ from {module_name} import {', '.join(types)}
245
+ """
246
+
247
+ @staticmethod
248
+ def suggest_refactoring(cycles: List[List[str]]) -> List[str]:
249
+ """Suggest refactoring strategies for circular dependencies."""
250
+ suggestions = []
251
+
252
+ for cycle in cycles:
253
+ if len(cycle) == 2:
254
+ suggestions.append(
255
+ f"""
256
+ Circular dependency between {cycle[0]} and {cycle[1]}:
257
+ 1. Extract shared functionality to a common base module
258
+ 2. Use dependency injection instead of direct imports
259
+ 3. Consider if one module should be a submodule of the other
260
+ """
261
+ )
262
+ elif "ai" in str(cycle):
263
+ suggestions.append(
264
+ f"""
265
+ AI module circular dependency in {' -> '.join(cycle)}:
266
+ 1. Create an ai.base module for shared components
267
+ 2. Use factory pattern for agent creation
268
+ 3. Move orchestration logic to a separate coordinator module
269
+ """
270
+ )
271
+ else:
272
+ suggestions.append(
273
+ f"""
274
+ Complex circular dependency in {' -> '.join(cycle)}:
275
+ 1. Apply Dependency Inversion Principle
276
+ 2. Create interfaces/protocols for cross-module communication
277
+ 3. Use event-driven architecture to decouple modules
278
+ """
279
+ )
280
+
281
+ return suggestions
282
+
283
+
284
+ def main():
285
+ """Run circular dependency detection on Kailash SDK."""
286
+ # Get the SDK root directory
287
+ sdk_root = Path(__file__).parent.parent.parent.parent
288
+
289
+ detector = CircularDependencyDetector(sdk_root)
290
+ report = detector.generate_report()
291
+
292
+ print(report)
293
+
294
+ if detector.circular_deps:
295
+ print("\n" + "=" * 80)
296
+ print("REFACTORING SUGGESTIONS")
297
+ print("=" * 80)
298
+
299
+ resolver = CircularImportResolver()
300
+ suggestions = resolver.suggest_refactoring(detector.circular_deps)
301
+
302
+ for i, suggestion in enumerate(suggestions, 1):
303
+ print(f"\n{i}. {suggestion}")
304
+
305
+ print("\n" + "=" * 80)
306
+ print("IMMEDIATE ACTION REQUIRED")
307
+ print("=" * 80)
308
+ print(
309
+ """
310
+ 1. Fix AI module circular dependencies (critical)
311
+ 2. Clean up duplicate __init__.py files
312
+ 3. Implement lazy loading WITH circular dependency checks
313
+ 4. Add this detector to CI/CD pipeline
314
+ """
315
+ )
316
+
317
+
318
+ if __name__ == "__main__":
319
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kailash
3
- Version: 0.9.14
3
+ Version: 0.9.15
4
4
  Summary: Python SDK for the Kailash container-node architecture
5
5
  Home-page: https://github.com/integrum/kailash-python-sdk
6
6
  Author: Integrum
@@ -1,4 +1,4 @@
1
- kailash/__init__.py,sha256=5ah04rxNTa7lqceRYS0LAu2U7VHLfU09Jek3rd7Rm2k,2853
1
+ kailash/__init__.py,sha256=ffp6pb2WvAiU8rhVtGWfCtb7StsOQLbshcvPDd7NY2o,2946
2
2
  kailash/__main__.py,sha256=vr7TVE5o16V6LsTmRFKG6RDKUXHpIWYdZ6Dok2HkHnI,198
3
3
  kailash/access_control.py,sha256=MjKtkoQ2sg1Mgfe7ovGxVwhAbpJKvaepPWr8dxOueMA,26058
4
4
  kailash/access_control_abac.py,sha256=FPfa_8PuDP3AxTjdWfiH3ntwWO8NodA0py9W8SE5dno,30263
@@ -28,7 +28,7 @@ kailash/channels/mcp_channel.py,sha256=V_BqYXHFb26V_8C6XOasgGZiDxLyN-BiRi5hsBgry
28
28
  kailash/channels/session.py,sha256=4ZEutfyQ3fhBlBjXa5e32ZL2ZqEuQKwbAk0DGu00X1A,13068
29
29
  kailash/cli/__init__.py,sha256=TvNjX0Q-2IxdWeh6w8rkqyONuFbSleStlRF8b-Aa8Iw,302
30
30
  kailash/cli/commands.py,sha256=lv1S1uB0JQE4tiQCJIa1HCbjYDbFE9KwcK3M1jRtRU4,18168
31
- kailash/cli/validate_imports.py,sha256=ebmruTzNyy_k9EGoXunO_7rntcoqH88lkbN6XyFtZXE,6093
31
+ kailash/cli/validate_imports.py,sha256=fJswjiuXLtZcDjzc7SRRPBBA7hDXgVRwiG04e_f547E,6091
32
32
  kailash/cli/validation_audit.py,sha256=0WBzOdh1pkaqYm011bpnumyMf30blvPzq9_nsUQoGno,20308
33
33
  kailash/client/__init__.py,sha256=WNR39t4O6TDQLI14uR_MjQpLza2c6rU3YkQCXcGCiSU,293
34
34
  kailash/client/enhanced_client.py,sha256=trcDWQsON0Hphj14WozVMbfU7HKuxauknzDfoy1fTlo,9431
@@ -39,7 +39,7 @@ kailash/core/actors/adaptive_pool_controller.py,sha256=tque9heLsLwjrNlM1wZSAYi1R
39
39
  kailash/core/actors/connection_actor.py,sha256=M8fOX1a3jvH5PUkfQyk0eBJqCk0SD9KGZCw0TXLON_o,18979
40
40
  kailash/core/actors/supervisor.py,sha256=GaTbRRA0REHNnsn0a8NXao-aj9Eh8KkZt6H2YJm7I4w,11975
41
41
  kailash/core/ml/__init__.py,sha256=eaD-bmoxMXtwwtKWePsoX1IkcpysX0bMAGyMR7jaAqI,64
42
- kailash/core/ml/query_patterns.py,sha256=4wV1pBOwUiK80UTKuMXSoRgR0pojtjg2BMNoa5qWpc0,20290
42
+ kailash/core/ml/query_patterns.py,sha256=gDr_WVg_7JK6HSisKZ28Gtrm95M4XVlwtIesXXu4olM,20290
43
43
  kailash/core/monitoring/__init__.py,sha256=Qua4i50JYUQcRkWHy1wGyuXGqzqsDVMmdPtud746xts,371
44
44
  kailash/core/monitoring/connection_metrics.py,sha256=fvFyHOgMU5lgRB2EB7d-D_F5XERjlmcGAfkrIL0I_OQ,16805
45
45
  kailash/core/optimization/__init__.py,sha256=FY5SLLNedH0_aawLYdXHj2rsGdBaaB49QuJ_R9ctHOE,65
@@ -71,7 +71,7 @@ kailash/edge/resource/cloud_integration.py,sha256=0zBBuWKaN5yqoBGLj5c5YcfmLwxCkj
71
71
  kailash/edge/resource/cost_optimizer.py,sha256=pPp985nMp6r4MzlR0k8D5PyNEKtkV7EIKkxwfIcZXiA,32916
72
72
  kailash/edge/resource/docker_integration.py,sha256=2CnhKF5P4cgwgk-r01Nr3IObJPTLvmk_Yu757Uu8vNg,30375
73
73
  kailash/edge/resource/kubernetes_integration.py,sha256=g703nAN3rVQK65lcphnth_6VOZHLo6FGprUYVgc5poQ,33123
74
- kailash/edge/resource/platform_integration.py,sha256=Rdc3bqz1MYFzPNSKKTkKwNGkl5-HzjvG0xtzwblDy1o,33522
74
+ kailash/edge/resource/platform_integration.py,sha256=EOH_Kw_4MVS71pa3oNkgDxsXEUo0q9qdLBv0GnrGjCc,33509
75
75
  kailash/edge/resource/predictive_scaler.py,sha256=FxoYIq1Xd6HOilWydOlxWn0jCIzKcaJqrxePw_YQH2Y,32728
76
76
  kailash/edge/resource/resource_analyzer.py,sha256=tcQM2uS_b985fY_-YOOhN_DiDjjVGo1k5c1GFHHE9P8,30043
77
77
  kailash/edge/resource/resource_pools.py,sha256=YlKa3d1MMCw2lOv7gz-KIkOg-uLfFbW_uy6nwo3mefU,20107
@@ -80,7 +80,7 @@ kailash/gateway/api.py,sha256=xpK8PIamsqQPpKAJwacyV7RA_Snjv2pc_0ljnnU9Oy4,9534
80
80
  kailash/gateway/enhanced_gateway.py,sha256=IlN1XV01FQrF4rGcq_z9LE4uUHAAAQoVsRNToXENen0,13399
81
81
  kailash/gateway/resource_resolver.py,sha256=IC1dceiKfjfUWToYCIBcrUapuR3LlDG6RJ4o7haLY10,7746
82
82
  kailash/gateway/security.py,sha256=kf4Quf6u7dqhs80fQQ982eHbRb4weDKG0DaYNeKntT4,7557
83
- kailash/integrations/dataflow_edge.py,sha256=R3Is8JJZcqLNn4op7gidp1dtbT82oY5vn9tXVAWLOrg,8994
83
+ kailash/integrations/dataflow_edge.py,sha256=UqQMrTHmVYkgJt9T3bfcumBexMnvcTtNUIDUYFonuPo,8989
84
84
  kailash/mcp_server/__init__.py,sha256=AzrCEat5gdl9Nes8xOs7D4Wj3HpGlms3xLbOrx2diPA,8791
85
85
  kailash/mcp_server/advanced_features.py,sha256=76dmttUa0M61ReBbgexf7Igu4CXaXS-CUmFhvTDjKyI,30673
86
86
  kailash/mcp_server/ai_registry_server.py,sha256=vMNMvWLegKBVp7YAHVKgltWa2vTXKNvV-_Ni_z1argM,28973
@@ -120,7 +120,7 @@ kailash/middleware/core/schema.py,sha256=uVF-5ZJlLYHOQdsKrG46FnTO1bq_QtDjhUSkIID
120
120
  kailash/middleware/core/workflows.py,sha256=kjwwP69-T6eCY7kWIMLUBwVy2CapoPR34cqCETquq0s,12480
121
121
  kailash/middleware/database/__init__.py,sha256=UMws94L-vja94AjfzPWIgn0h4_5BGQzI3YaSdqtzeLk,1682
122
122
  kailash/middleware/database/base.py,sha256=cWEei9Gb6J-C-bpa4M4T0takfWE3POXWumzYhqX3V4g,2735
123
- kailash/middleware/database/base_models.py,sha256=XBcHEUmcpl2f6zZHCAgHQ_0jqUB3Gl82XARR83lW5GY,18287
123
+ kailash/middleware/database/base_models.py,sha256=t4HfXKGHZkfLkzoRgXXvlO_wdgsqXhm7S0XP4OIdQXc,18262
124
124
  kailash/middleware/database/enums.py,sha256=Yo_wMS7OpsleWtNMESTc2LTf15d93nPnBADIn2EHjeQ,2516
125
125
  kailash/middleware/database/migrations.py,sha256=v5VZxsqciwmOl3rzIBQLp5p6-OP8OG_EL3mu65_yrCM,240
126
126
  kailash/middleware/database/models.py,sha256=CJwwUEdgxqBteXqpFJr1tWskjypJxViZXjODZlByrFk,17784
@@ -137,9 +137,10 @@ kailash/middleware/mcp/__init__.py,sha256=EdZB8zOMSBEEmudRzs8ksz9QZJYWQMEx7Tm1MO
137
137
  kailash/middleware/mcp/client_integration.py,sha256=dY1RmX-g5E6JzUFuWxk7viuOYIh8bMwoUSvHQMVEsYk,18265
138
138
  kailash/middleware/mcp/enhanced_server.py,sha256=RUVS7jWHn0ma4F3F23UvuFwUdu7OkSsIRNQmGtkG9I8,18547
139
139
  kailash/monitoring/__init__.py,sha256=C5WmkNpk_mmAScqMWiCfkUbjhM5W16dsnRnc3Ial-Uc,475
140
- kailash/monitoring/alerts.py,sha256=eKX4ooPw1EicumPuswlR_nU18UgRETWvFg8FzCW5pVU,21416
140
+ kailash/monitoring/alerts.py,sha256=Hk3Xs0EEkOIBH2ZhlejJBOsLYaPlvRejAAEGqNQISc0,21400
141
141
  kailash/monitoring/metrics.py,sha256=SiAnL3o6K0QaJHgfAuWBa-0pTkW5zymhuPEsj4bgOgM,22022
142
- kailash/nodes/__init__.py,sha256=p2KSo0dyUBCLClU123qpQ0tyv5S_36PTxosNyW58nyY,1031
142
+ kailash/nodes/__init__.py,sha256=zn4M0f-sIPAq8bG5golQIxmEY8lG5d55Kzg8UNL2lAY,6392
143
+ kailash/nodes/__init___original.py,sha256=p2KSo0dyUBCLClU123qpQ0tyv5S_36PTxosNyW58nyY,1031
143
144
  kailash/nodes/base.py,sha256=GR2E1fWf8j1yMvJic7m2NAih7kjY1NtoDi47hHwoZ40,85437
144
145
  kailash/nodes/base_async.py,sha256=whxepCiVplrltfzEQuabmnGCpEV5WgfqwgxbLdCyiDk,8864
145
146
  kailash/nodes/base_cycle_aware.py,sha256=Xpze9xZzLepWeLpi9Y3tMn1dm2LVv-omr5TSQuGTtWo,13377
@@ -166,7 +167,7 @@ kailash/nodes/ai/ai_providers.py,sha256=egfiOZzPmZ10d3wBCJ6ST4tRFrrtq0kt1VyCqxVp
166
167
  kailash/nodes/ai/embedding_generator.py,sha256=akGCzz7zLRSziqEQCiPwL2qWhRWxuM_1RQh-YtVEddw,31879
167
168
  kailash/nodes/ai/hybrid_search.py,sha256=k26uDDP_bwrIpv7Yl7PBCPvWSyQEmTlBjI1IpbgDsO4,35446
168
169
  kailash/nodes/ai/intelligent_agent_orchestrator.py,sha256=LvBqMKc64zSxFWVCjbLKKel2QwEzoTeJAEgna7rZw00,83097
169
- kailash/nodes/ai/iterative_llm_agent.py,sha256=Q_letP5mHtO225LBX0Tq5GlPkXkk-yWf3oFEOJTP6Z0,100289
170
+ kailash/nodes/ai/iterative_llm_agent.py,sha256=h8iP1KFhB_eCDs7UvmY_9y0OUBuprYMj2MLM6dR0W2c,100287
170
171
  kailash/nodes/ai/llm_agent.py,sha256=NeNJZbV_VOUbULug2LASwyzLyoUO5wi58Bc9sXTubuc,90181
171
172
  kailash/nodes/ai/models.py,sha256=wsEeUTuegy87mnLtKgSTg7ggCXvC1n3MsL-iZ4qujHs,16393
172
173
  kailash/nodes/ai/self_organizing.py,sha256=B7NwKaBW8OHQBf5b0F9bSs8Wm-5BDJ9IjIkxS9h00mg,62885
@@ -360,6 +361,7 @@ kailash/tracking/storage/base.py,sha256=wWkK1XdrMV0EGxlbFDyfuVnDoIG0tdSPPwz_8iwz
360
361
  kailash/tracking/storage/database.py,sha256=O3-qYmgwTccq9jYl25C0L6R398pXPsWkIAoWLL1aZvQ,20048
361
362
  kailash/tracking/storage/filesystem.py,sha256=VhWxNvqf_Ta3mIaGqKuOrcCqQiEvJj7S8NK5yRd1V68,19627
362
363
  kailash/utils/__init__.py,sha256=pFKhHJxU_kyFE9aGT5recw5E-3nbfVF5pMHepBJWB2E,253
364
+ kailash/utils/circular_dependency_detector.py,sha256=YqhaD_rAfubGebLyXtICX_K7WN2qB6p_T84jVqR4TaA,10821
363
365
  kailash/utils/data_paths.py,sha256=pZWoqXPc62kB1iJlIXRUZSzXTglEUrJ3hML0YmXuC5k,2148
364
366
  kailash/utils/data_validation.py,sha256=LYQWHtB-BRSAGQDMdZQGUKOZCGeoeia2fIqM0UfJFSU,6851
365
367
  kailash/utils/export.py,sha256=WBazN03LOCI03TsIElNv31wSZ_uTLPl8THnqdohgyTk,37361
@@ -403,10 +405,10 @@ kailash/workflow/templates.py,sha256=XQMAKZXC2dlxgMMQhSEOWAF3hIbe9JJt9j_THchhAm8
403
405
  kailash/workflow/type_inference.py,sha256=i1F7Yd_Z3elTXrthsLpqGbOnQBIVVVEjhRpI0HrIjd0,24492
404
406
  kailash/workflow/validation.py,sha256=LdbIPQSokCqSLfWTBhJR82pa_0va44pcVu9dpEM4rvY,45177
405
407
  kailash/workflow/visualization.py,sha256=nHBW-Ai8QBMZtn2Nf3EE1_aiMGi9S6Ui_BfpA5KbJPU,23187
406
- kailash-0.9.14.dist-info/licenses/LICENSE,sha256=9GYZHXVUmx6FdFRNzOeE_w7a_aEGeYbqTVmFtJlrbGk,13438
407
- kailash-0.9.14.dist-info/licenses/NOTICE,sha256=9ssIK4LcHSTFqriXGdteMpBPTS1rSLlYtjppZ_bsjZ0,723
408
- kailash-0.9.14.dist-info/METADATA,sha256=4j6DBNRv5DSiH0VPQ1H3IhTw8vh06MYdDAJebLSmGg0,23528
409
- kailash-0.9.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
410
- kailash-0.9.14.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
411
- kailash-0.9.14.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
412
- kailash-0.9.14.dist-info/RECORD,,
408
+ kailash-0.9.15.dist-info/licenses/LICENSE,sha256=9GYZHXVUmx6FdFRNzOeE_w7a_aEGeYbqTVmFtJlrbGk,13438
409
+ kailash-0.9.15.dist-info/licenses/NOTICE,sha256=9ssIK4LcHSTFqriXGdteMpBPTS1rSLlYtjppZ_bsjZ0,723
410
+ kailash-0.9.15.dist-info/METADATA,sha256=xXck9LkEnFmoRYJW_c5EPsOOWwkH6uI8d5biAA2Nf3w,23528
411
+ kailash-0.9.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
412
+ kailash-0.9.15.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
413
+ kailash-0.9.15.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
414
+ kailash-0.9.15.dist-info/RECORD,,