kailash 0.3.0__py3-none-any.whl → 0.3.2__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.
Files changed (113) hide show
  1. kailash/access_control.py +40 -39
  2. kailash/api/auth.py +26 -32
  3. kailash/api/custom_nodes.py +29 -29
  4. kailash/api/custom_nodes_secure.py +35 -35
  5. kailash/api/database.py +17 -17
  6. kailash/api/gateway.py +19 -19
  7. kailash/api/mcp_integration.py +24 -23
  8. kailash/api/studio.py +45 -45
  9. kailash/api/workflow_api.py +8 -8
  10. kailash/cli/commands.py +5 -8
  11. kailash/manifest.py +42 -42
  12. kailash/mcp/__init__.py +1 -1
  13. kailash/mcp/ai_registry_server.py +20 -20
  14. kailash/mcp/client.py +9 -11
  15. kailash/mcp/client_new.py +10 -10
  16. kailash/mcp/server.py +1 -2
  17. kailash/mcp/server_enhanced.py +449 -0
  18. kailash/mcp/servers/ai_registry.py +6 -6
  19. kailash/mcp/utils/__init__.py +31 -0
  20. kailash/mcp/utils/cache.py +267 -0
  21. kailash/mcp/utils/config.py +263 -0
  22. kailash/mcp/utils/formatters.py +293 -0
  23. kailash/mcp/utils/metrics.py +418 -0
  24. kailash/nodes/ai/agents.py +9 -9
  25. kailash/nodes/ai/ai_providers.py +33 -34
  26. kailash/nodes/ai/embedding_generator.py +31 -32
  27. kailash/nodes/ai/intelligent_agent_orchestrator.py +62 -66
  28. kailash/nodes/ai/iterative_llm_agent.py +48 -48
  29. kailash/nodes/ai/llm_agent.py +32 -33
  30. kailash/nodes/ai/models.py +13 -13
  31. kailash/nodes/ai/self_organizing.py +44 -44
  32. kailash/nodes/api/auth.py +11 -11
  33. kailash/nodes/api/graphql.py +13 -13
  34. kailash/nodes/api/http.py +19 -19
  35. kailash/nodes/api/monitoring.py +20 -20
  36. kailash/nodes/api/rate_limiting.py +9 -13
  37. kailash/nodes/api/rest.py +29 -29
  38. kailash/nodes/api/security.py +44 -47
  39. kailash/nodes/base.py +21 -23
  40. kailash/nodes/base_async.py +7 -7
  41. kailash/nodes/base_cycle_aware.py +12 -12
  42. kailash/nodes/base_with_acl.py +5 -5
  43. kailash/nodes/code/python.py +66 -57
  44. kailash/nodes/data/directory.py +6 -6
  45. kailash/nodes/data/event_generation.py +10 -10
  46. kailash/nodes/data/file_discovery.py +28 -31
  47. kailash/nodes/data/readers.py +8 -8
  48. kailash/nodes/data/retrieval.py +10 -10
  49. kailash/nodes/data/sharepoint_graph.py +17 -17
  50. kailash/nodes/data/sources.py +5 -5
  51. kailash/nodes/data/sql.py +13 -13
  52. kailash/nodes/data/streaming.py +25 -25
  53. kailash/nodes/data/vector_db.py +22 -22
  54. kailash/nodes/data/writers.py +7 -7
  55. kailash/nodes/logic/async_operations.py +17 -17
  56. kailash/nodes/logic/convergence.py +11 -11
  57. kailash/nodes/logic/loop.py +4 -4
  58. kailash/nodes/logic/operations.py +11 -11
  59. kailash/nodes/logic/workflow.py +8 -9
  60. kailash/nodes/mixins/mcp.py +17 -17
  61. kailash/nodes/mixins.py +8 -10
  62. kailash/nodes/transform/chunkers.py +3 -3
  63. kailash/nodes/transform/formatters.py +7 -7
  64. kailash/nodes/transform/processors.py +10 -10
  65. kailash/runtime/access_controlled.py +18 -18
  66. kailash/runtime/async_local.py +17 -19
  67. kailash/runtime/docker.py +20 -22
  68. kailash/runtime/local.py +16 -16
  69. kailash/runtime/parallel.py +23 -23
  70. kailash/runtime/parallel_cyclic.py +27 -27
  71. kailash/runtime/runner.py +6 -6
  72. kailash/runtime/testing.py +20 -20
  73. kailash/sdk_exceptions.py +0 -58
  74. kailash/security.py +14 -26
  75. kailash/tracking/manager.py +38 -38
  76. kailash/tracking/metrics_collector.py +15 -14
  77. kailash/tracking/models.py +53 -53
  78. kailash/tracking/storage/base.py +7 -17
  79. kailash/tracking/storage/database.py +22 -23
  80. kailash/tracking/storage/filesystem.py +38 -40
  81. kailash/utils/export.py +21 -21
  82. kailash/utils/templates.py +2 -3
  83. kailash/visualization/api.py +30 -34
  84. kailash/visualization/dashboard.py +17 -17
  85. kailash/visualization/performance.py +16 -16
  86. kailash/visualization/reports.py +25 -27
  87. kailash/workflow/builder.py +8 -8
  88. kailash/workflow/convergence.py +13 -12
  89. kailash/workflow/cycle_analyzer.py +30 -32
  90. kailash/workflow/cycle_builder.py +12 -12
  91. kailash/workflow/cycle_config.py +16 -15
  92. kailash/workflow/cycle_debugger.py +40 -40
  93. kailash/workflow/cycle_exceptions.py +29 -29
  94. kailash/workflow/cycle_profiler.py +21 -21
  95. kailash/workflow/cycle_state.py +20 -22
  96. kailash/workflow/cyclic_runner.py +44 -44
  97. kailash/workflow/graph.py +40 -40
  98. kailash/workflow/mermaid_visualizer.py +9 -11
  99. kailash/workflow/migration.py +22 -22
  100. kailash/workflow/mock_registry.py +6 -6
  101. kailash/workflow/runner.py +9 -9
  102. kailash/workflow/safety.py +12 -13
  103. kailash/workflow/state.py +8 -11
  104. kailash/workflow/templates.py +19 -19
  105. kailash/workflow/validation.py +14 -14
  106. kailash/workflow/visualization.py +22 -22
  107. {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/METADATA +53 -5
  108. kailash-0.3.2.dist-info/RECORD +136 -0
  109. kailash-0.3.0.dist-info/RECORD +0 -130
  110. {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/WHEEL +0 -0
  111. {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/entry_points.txt +0 -0
  112. {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/licenses/LICENSE +0 -0
  113. {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,7 @@ import json
27
27
  import logging
28
28
  from datetime import datetime
29
29
  from pathlib import Path
30
- from typing import Any, Dict, List, Optional, Union
30
+ from typing import Any, Optional
31
31
 
32
32
  try:
33
33
  from fastapi import (
@@ -59,8 +59,8 @@ if FASTAPI_AVAILABLE:
59
59
  class RunRequest(BaseModel):
60
60
  """Request model for starting monitoring."""
61
61
 
62
- run_id: Optional[str] = None
63
- config: Optional[Dict[str, Any]] = None
62
+ run_id: str | None = None
63
+ config: dict[str, Any] | None = None
64
64
 
65
65
  class MetricsResponse(BaseModel):
66
66
  """Response model for metrics data."""
@@ -80,12 +80,12 @@ if FASTAPI_AVAILABLE:
80
80
  node_id: str
81
81
  node_type: str
82
82
  status: str
83
- started_at: Optional[datetime]
84
- ended_at: Optional[datetime]
85
- duration: Optional[float]
86
- cpu_usage: Optional[float]
87
- memory_usage_mb: Optional[float]
88
- error_message: Optional[str]
83
+ started_at: datetime | None
84
+ ended_at: datetime | None
85
+ duration: float | None
86
+ cpu_usage: float | None
87
+ memory_usage_mb: float | None
88
+ error_message: str | None
89
89
 
90
90
  class RunResponse(BaseModel):
91
91
  """Response model for run information."""
@@ -93,8 +93,8 @@ if FASTAPI_AVAILABLE:
93
93
  run_id: str
94
94
  workflow_name: str
95
95
  status: str
96
- started_at: Optional[datetime]
97
- ended_at: Optional[datetime]
96
+ started_at: datetime | None
97
+ ended_at: datetime | None
98
98
  total_tasks: int
99
99
  completed_tasks: int
100
100
  failed_tasks: int
@@ -105,7 +105,7 @@ if FASTAPI_AVAILABLE:
105
105
  run_id: str
106
106
  format: str = "html"
107
107
  include_charts: bool = True
108
- compare_runs: Optional[List[str]] = None
108
+ compare_runs: list[str] | None = None
109
109
  detail_level: str = "detailed"
110
110
 
111
111
 
@@ -123,7 +123,7 @@ class DashboardAPIServer:
123
123
  def __init__(
124
124
  self,
125
125
  task_manager: TaskManager,
126
- dashboard_config: Optional[DashboardConfig] = None,
126
+ dashboard_config: DashboardConfig | None = None,
127
127
  ):
128
128
  """Initialize API server.
129
129
 
@@ -145,8 +145,8 @@ class DashboardAPIServer:
145
145
  self.reporter = WorkflowPerformanceReporter(task_manager)
146
146
 
147
147
  # WebSocket connections for real-time updates
148
- self._websocket_connections: List[WebSocket] = []
149
- self._broadcast_task: Optional[asyncio.Task] = None
148
+ self._websocket_connections: list[WebSocket] = []
149
+ self._broadcast_task: asyncio.Task | None = None
150
150
 
151
151
  # Create FastAPI app
152
152
  self.app = FastAPI(
@@ -177,7 +177,7 @@ class DashboardAPIServer:
177
177
  """Health check endpoint."""
178
178
  return {"status": "healthy", "timestamp": datetime.now()}
179
179
 
180
- @self.app.get("/api/v1/runs", response_model=List[RunResponse])
180
+ @self.app.get("/api/v1/runs", response_model=list[RunResponse])
181
181
  async def list_runs(limit: int = 10, offset: int = 0):
182
182
  """Get list of workflow runs."""
183
183
  try:
@@ -243,7 +243,7 @@ class DashboardAPIServer:
243
243
  self.logger.error(f"Failed to get run {run_id}: {e}")
244
244
  raise HTTPException(status_code=500, detail=str(e))
245
245
 
246
- @self.app.get("/api/v1/runs/{run_id}/tasks", response_model=List[TaskResponse])
246
+ @self.app.get("/api/v1/runs/{run_id}/tasks", response_model=list[TaskResponse])
247
247
  async def get_run_tasks(run_id: str):
248
248
  """Get tasks for a specific run."""
249
249
  try:
@@ -352,7 +352,7 @@ class DashboardAPIServer:
352
352
  self.logger.error(f"Failed to get current metrics: {e}")
353
353
  raise HTTPException(status_code=500, detail=str(e))
354
354
 
355
- @self.app.get("/api/v1/metrics/history", response_model=List[MetricsResponse])
355
+ @self.app.get("/api/v1/metrics/history", response_model=list[MetricsResponse])
356
356
  async def get_metrics_history(minutes: int = 30):
357
357
  """Get metrics history for specified time period."""
358
358
  try:
@@ -475,7 +475,7 @@ class DashboardAPIServer:
475
475
  run_id: str,
476
476
  output_path: Path,
477
477
  report_format: ReportFormat,
478
- compare_runs: Optional[List[str]] = None,
478
+ compare_runs: list[str] | None = None,
479
479
  ):
480
480
  """Generate report in background task."""
481
481
  try:
@@ -564,7 +564,7 @@ class SimpleDashboardAPI:
564
564
  def __init__(
565
565
  self,
566
566
  task_manager: TaskManager,
567
- dashboard_config: Optional[DashboardConfig] = None,
567
+ dashboard_config: DashboardConfig | None = None,
568
568
  ):
569
569
  """Initialize simple API interface.
570
570
 
@@ -578,7 +578,7 @@ class SimpleDashboardAPI:
578
578
  self.reporter = WorkflowPerformanceReporter(task_manager)
579
579
  self.logger = logger
580
580
 
581
- def get_runs(self, limit: int = 10, offset: int = 0) -> List[Dict[str, Any]]:
581
+ def get_runs(self, limit: int = 10, offset: int = 0) -> list[dict[str, Any]]:
582
582
  """Get list of workflow runs."""
583
583
  all_runs = self.task_manager.list_runs()
584
584
  runs = all_runs[offset : offset + limit]
@@ -604,7 +604,7 @@ class SimpleDashboardAPI:
604
604
 
605
605
  return result
606
606
 
607
- def get_run_details(self, run_id: str) -> Optional[Dict[str, Any]]:
607
+ def get_run_details(self, run_id: str) -> dict[str, Any] | None:
608
608
  """Get details for a specific run."""
609
609
  run = self.task_manager.get_run(run_id)
610
610
  if not run:
@@ -641,17 +641,17 @@ class SimpleDashboardAPI:
641
641
  ],
642
642
  }
643
643
 
644
- def start_monitoring(self, run_id: Optional[str] = None) -> Dict[str, Any]:
644
+ def start_monitoring(self, run_id: str | None = None) -> dict[str, Any]:
645
645
  """Start real-time monitoring."""
646
646
  self.dashboard.start_monitoring(run_id)
647
647
  return {"status": "started", "run_id": run_id}
648
648
 
649
- def stop_monitoring(self) -> Dict[str, Any]:
649
+ def stop_monitoring(self) -> dict[str, Any]:
650
650
  """Stop real-time monitoring."""
651
651
  self.dashboard.stop_monitoring()
652
652
  return {"status": "stopped"}
653
653
 
654
- def get_current_metrics(self) -> Optional[Dict[str, Any]]:
654
+ def get_current_metrics(self) -> dict[str, Any] | None:
655
655
  """Get current live metrics."""
656
656
  metrics = self.dashboard.get_current_metrics()
657
657
  if not metrics:
@@ -668,7 +668,7 @@ class SimpleDashboardAPI:
668
668
  "avg_task_duration": metrics.avg_task_duration,
669
669
  }
670
670
 
671
- def get_metrics_history(self, minutes: int = 30) -> List[Dict[str, Any]]:
671
+ def get_metrics_history(self, minutes: int = 30) -> list[dict[str, Any]]:
672
672
  """Get metrics history."""
673
673
  history = self.dashboard.get_metrics_history(minutes=minutes)
674
674
 
@@ -690,8 +690,8 @@ class SimpleDashboardAPI:
690
690
  self,
691
691
  run_id: str,
692
692
  format: str = "html",
693
- output_path: Optional[Union[str, Path]] = None,
694
- compare_runs: Optional[List[str]] = None,
693
+ output_path: str | Path | None = None,
694
+ compare_runs: list[str] | None = None,
695
695
  ) -> Path:
696
696
  """Generate performance report."""
697
697
  try:
@@ -708,9 +708,7 @@ class SimpleDashboardAPI:
708
708
  compare_runs=compare_runs,
709
709
  )
710
710
 
711
- def generate_dashboard(
712
- self, output_path: Optional[Union[str, Path]] = None
713
- ) -> Path:
711
+ def generate_dashboard(self, output_path: str | Path | None = None) -> Path:
714
712
  """Generate live dashboard HTML."""
715
713
  if output_path is None:
716
714
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -718,9 +716,7 @@ class SimpleDashboardAPI:
718
716
 
719
717
  return self.dashboard.generate_live_report(output_path, include_charts=True)
720
718
 
721
- def export_metrics_json(
722
- self, output_path: Optional[Union[str, Path]] = None
723
- ) -> Path:
719
+ def export_metrics_json(self, output_path: str | Path | None = None) -> Path:
724
720
  """Export current metrics as JSON."""
725
721
  if output_path is None:
726
722
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -27,7 +27,7 @@ import time
27
27
  from dataclasses import dataclass, field
28
28
  from datetime import datetime, timedelta
29
29
  from pathlib import Path
30
- from typing import Any, Dict, List, Optional, Union
30
+ from typing import Any
31
31
 
32
32
  import numpy as np
33
33
 
@@ -100,7 +100,7 @@ class RealTimeDashboard:
100
100
  """
101
101
 
102
102
  def __init__(
103
- self, task_manager: TaskManager, config: Optional[DashboardConfig] = None
103
+ self, task_manager: TaskManager, config: DashboardConfig | None = None
104
104
  ):
105
105
  """Initialize real-time dashboard.
106
106
 
@@ -114,17 +114,17 @@ class RealTimeDashboard:
114
114
 
115
115
  # Live monitoring state
116
116
  self._monitoring = False
117
- self._monitor_thread: Optional[threading.Thread] = None
118
- self._metrics_history: List[LiveMetrics] = []
119
- self._current_run_id: Optional[str] = None
117
+ self._monitor_thread: threading.Thread | None = None
118
+ self._metrics_history: list[LiveMetrics] = []
119
+ self._current_run_id: str | None = None
120
120
 
121
121
  # Event callbacks
122
- self._status_callbacks: List[callable] = []
123
- self._metrics_callbacks: List[callable] = []
122
+ self._status_callbacks: list[callable] = []
123
+ self._metrics_callbacks: list[callable] = []
124
124
 
125
125
  self.logger = logger
126
126
 
127
- def start_monitoring(self, run_id: Optional[str] = None):
127
+ def start_monitoring(self, run_id: str | None = None):
128
128
  """Start real-time monitoring for a workflow run.
129
129
 
130
130
  Args:
@@ -297,11 +297,11 @@ class RealTimeDashboard:
297
297
  """
298
298
  self._status_callbacks.append(callback)
299
299
 
300
- def get_current_metrics(self) -> Optional[LiveMetrics]:
300
+ def get_current_metrics(self) -> LiveMetrics | None:
301
301
  """Get the most recent metrics."""
302
302
  return self._metrics_history[-1] if self._metrics_history else None
303
303
 
304
- def get_metrics_history(self, minutes: Optional[int] = None) -> List[LiveMetrics]:
304
+ def get_metrics_history(self, minutes: int | None = None) -> list[LiveMetrics]:
305
305
  """Get metrics history for specified time period.
306
306
 
307
307
  Args:
@@ -317,7 +317,7 @@ class RealTimeDashboard:
317
317
  return [m for m in self._metrics_history if m.timestamp >= cutoff]
318
318
 
319
319
  def generate_live_report(
320
- self, output_path: Union[str, Path], include_charts: bool = True
320
+ self, output_path: str | Path, include_charts: bool = True
321
321
  ) -> Path:
322
322
  """Generate comprehensive live dashboard report.
323
323
 
@@ -396,7 +396,7 @@ class RealTimeDashboard:
396
396
 
397
397
  return html_template
398
398
 
399
- def _generate_status_section(self, metrics: Optional[LiveMetrics]) -> str:
399
+ def _generate_status_section(self, metrics: LiveMetrics | None) -> str:
400
400
  """Generate status overview section."""
401
401
  if not metrics:
402
402
  return """
@@ -442,7 +442,7 @@ class RealTimeDashboard:
442
442
  </section>
443
443
  """
444
444
 
445
- def _generate_live_metrics_section(self, history: List[LiveMetrics]) -> str:
445
+ def _generate_live_metrics_section(self, history: list[LiveMetrics]) -> str:
446
446
  """Generate live metrics charts section."""
447
447
  if not history:
448
448
  return """
@@ -860,7 +860,7 @@ class DashboardExporter:
860
860
  self.dashboard = dashboard
861
861
  self.logger = logger
862
862
 
863
- def export_metrics_json(self, output_path: Union[str, Path]) -> Path:
863
+ def export_metrics_json(self, output_path: str | Path) -> Path:
864
864
  """Export current metrics as JSON.
865
865
 
866
866
  Args:
@@ -895,7 +895,7 @@ class DashboardExporter:
895
895
  self.logger.info(f"Exported metrics to: {output_path}")
896
896
  return output_path
897
897
 
898
- def _metrics_to_dict(self, metrics: LiveMetrics) -> Dict[str, Any]:
898
+ def _metrics_to_dict(self, metrics: LiveMetrics) -> dict[str, Any]:
899
899
  """Convert LiveMetrics to dictionary."""
900
900
  return {
901
901
  "timestamp": metrics.timestamp.isoformat(),
@@ -909,8 +909,8 @@ class DashboardExporter:
909
909
  }
910
910
 
911
911
  def create_dashboard_snapshot(
912
- self, output_dir: Union[str, Path], include_static_charts: bool = True
913
- ) -> Dict[str, Path]:
912
+ self, output_dir: str | Path, include_static_charts: bool = True
913
+ ) -> dict[str, Path]:
914
914
  """Create complete dashboard snapshot with all assets.
915
915
 
916
916
  Args:
@@ -23,7 +23,7 @@ Downstream Consumers:
23
23
 
24
24
  import logging
25
25
  from pathlib import Path
26
- from typing import Any, Dict, List, Optional
26
+ from typing import Any
27
27
 
28
28
  import matplotlib.pyplot as plt
29
29
  import numpy as np
@@ -51,8 +51,8 @@ class PerformanceVisualizer:
51
51
  self.logger = logger
52
52
 
53
53
  def create_run_performance_summary(
54
- self, run_id: str, output_dir: Optional[Path] = None
55
- ) -> Dict[str, Path]:
54
+ self, run_id: str, output_dir: Path | None = None
55
+ ) -> dict[str, Path]:
56
56
  """Create comprehensive performance summary for a workflow run.
57
57
 
58
58
  Args:
@@ -112,7 +112,7 @@ class PerformanceVisualizer:
112
112
  return outputs
113
113
 
114
114
  def _create_execution_timeline(
115
- self, tasks: List[TaskRun], output_path: Path
115
+ self, tasks: list[TaskRun], output_path: Path
116
116
  ) -> Path:
117
117
  """Create Gantt-style execution timeline."""
118
118
  fig, ax = plt.subplots(figsize=(12, max(6, len(tasks) * 0.5)))
@@ -210,7 +210,7 @@ class PerformanceVisualizer:
210
210
  return output_path
211
211
 
212
212
  def _create_resource_usage_chart(
213
- self, tasks: List[TaskRun], output_path: Path
213
+ self, tasks: list[TaskRun], output_path: Path
214
214
  ) -> Path:
215
215
  """Create resource usage comparison chart."""
216
216
  fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 12))
@@ -258,7 +258,7 @@ class PerformanceVisualizer:
258
258
  ax1.grid(True, axis="y", alpha=0.3)
259
259
 
260
260
  # Add value labels
261
- for bar, value in zip(bars1, cpu_usage):
261
+ for bar, value in zip(bars1, cpu_usage, strict=False):
262
262
  if value > 0:
263
263
  ax1.text(
264
264
  bar.get_x() + bar.get_width() / 2,
@@ -295,7 +295,7 @@ class PerformanceVisualizer:
295
295
  ax3.grid(True, axis="y", alpha=0.3)
296
296
 
297
297
  # Add value labels
298
- for bar, value in zip(bars3, durations):
298
+ for bar, value in zip(bars3, durations, strict=False):
299
299
  if value > 0:
300
300
  ax3.text(
301
301
  bar.get_x() + bar.get_width() / 2,
@@ -314,7 +314,7 @@ class PerformanceVisualizer:
314
314
  return output_path
315
315
 
316
316
  def _create_node_performance_comparison(
317
- self, tasks: List[TaskRun], output_path: Path
317
+ self, tasks: list[TaskRun], output_path: Path
318
318
  ) -> Path:
319
319
  """Create performance comparison radar chart."""
320
320
  # Group tasks by node type
@@ -385,7 +385,9 @@ class PerformanceVisualizer:
385
385
 
386
386
  colors = plt.cm.tab10(np.linspace(0, 1, len(avg_metrics)))
387
387
 
388
- for (node_type, metrics), color in zip(avg_metrics.items(), colors):
388
+ for (node_type, metrics), color in zip(
389
+ avg_metrics.items(), colors, strict=False
390
+ ):
389
391
  values = list(metrics.values())
390
392
 
391
393
  # Normalize values to 0-100 scale for better visualization
@@ -404,7 +406,7 @@ class PerformanceVisualizer:
404
406
  }
405
407
 
406
408
  normalized_values = []
407
- for cat, val in zip(categories, values):
409
+ for cat, val in zip(categories, values, strict=False):
408
410
  normalized_values.append((val / max_vals[cat]) * 100)
409
411
 
410
412
  normalized_values += normalized_values[:1]
@@ -435,7 +437,7 @@ class PerformanceVisualizer:
435
437
 
436
438
  return output_path
437
439
 
438
- def _create_io_analysis(self, tasks: List[TaskRun], output_path: Path) -> Path:
440
+ def _create_io_analysis(self, tasks: list[TaskRun], output_path: Path) -> Path:
439
441
  """Create I/O operations analysis chart."""
440
442
  fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
441
443
 
@@ -543,7 +545,7 @@ class PerformanceVisualizer:
543
545
  return output_path
544
546
 
545
547
  def _create_performance_heatmap(
546
- self, tasks: List[TaskRun], output_path: Path
548
+ self, tasks: list[TaskRun], output_path: Path
547
549
  ) -> Path:
548
550
  """Create performance metrics heatmap."""
549
551
  # Prepare data matrix
@@ -636,7 +638,7 @@ class PerformanceVisualizer:
636
638
  return output_path
637
639
 
638
640
  def _create_performance_report(
639
- self, run: Any, tasks: List[TaskRun], output_path: Path
641
+ self, run: Any, tasks: list[TaskRun], output_path: Path
640
642
  ) -> Path:
641
643
  """Create markdown performance report."""
642
644
  lines = []
@@ -718,9 +720,7 @@ class PerformanceVisualizer:
718
720
 
719
721
  return output_path
720
722
 
721
- def compare_runs(
722
- self, run_ids: List[str], output_path: Optional[Path] = None
723
- ) -> Path:
723
+ def compare_runs(self, run_ids: list[str], output_path: Path | None = None) -> Path:
724
724
  """Compare performance across multiple runs."""
725
725
  if output_path is None:
726
726
  # Use centralized output directory
@@ -27,7 +27,7 @@ from dataclasses import dataclass, field
27
27
  from datetime import datetime
28
28
  from enum import Enum
29
29
  from pathlib import Path
30
- from typing import Any, Dict, List, Optional, Union
30
+ from typing import Any
31
31
 
32
32
  import numpy as np
33
33
 
@@ -86,7 +86,7 @@ class PerformanceInsight:
86
86
  title: str
87
87
  description: str
88
88
  recommendation: str
89
- metrics: Dict[str, Any] = field(default_factory=dict)
89
+ metrics: dict[str, Any] = field(default_factory=dict)
90
90
 
91
91
 
92
92
  @dataclass
@@ -134,9 +134,7 @@ class WorkflowPerformanceReporter:
134
134
  report = reporter.generate_report(run_id, output_path="report.html")
135
135
  """
136
136
 
137
- def __init__(
138
- self, task_manager: TaskManager, config: Optional[ReportConfig] = None
139
- ):
137
+ def __init__(self, task_manager: TaskManager, config: ReportConfig | None = None):
140
138
  """Initialize performance reporter.
141
139
 
142
140
  Args:
@@ -151,9 +149,9 @@ class WorkflowPerformanceReporter:
151
149
  def generate_report(
152
150
  self,
153
151
  run_id: str,
154
- output_path: Optional[Union[str, Path]] = None,
152
+ output_path: str | Path | None = None,
155
153
  format: ReportFormat = ReportFormat.HTML,
156
- compare_runs: Optional[List[str]] = None,
154
+ compare_runs: list[str] | None = None,
157
155
  ) -> Path:
158
156
  """Generate comprehensive performance report.
159
157
 
@@ -211,7 +209,7 @@ class WorkflowPerformanceReporter:
211
209
  self.logger.info(f"Generated {format.value.upper()} report: {output_path}")
212
210
  return output_path
213
211
 
214
- def _analyze_workflow_run(self, run_id: str) -> Dict[str, Any]:
212
+ def _analyze_workflow_run(self, run_id: str) -> dict[str, Any]:
215
213
  """Perform detailed analysis of a workflow run.
216
214
 
217
215
  Args:
@@ -264,7 +262,7 @@ class WorkflowPerformanceReporter:
264
262
  }
265
263
 
266
264
  def _calculate_workflow_summary(
267
- self, run: Any, tasks: List[TaskRun]
265
+ self, run: Any, tasks: list[TaskRun]
268
266
  ) -> WorkflowSummary:
269
267
  """Calculate summary statistics for the workflow run."""
270
268
  summary = WorkflowSummary(
@@ -340,7 +338,7 @@ class WorkflowPerformanceReporter:
340
338
 
341
339
  return summary
342
340
 
343
- def _analyze_task_performance(self, tasks: List[TaskRun]) -> Dict[str, Any]:
341
+ def _analyze_task_performance(self, tasks: list[TaskRun]) -> dict[str, Any]:
344
342
  """Analyze performance patterns across tasks."""
345
343
  analysis = {
346
344
  "by_node_type": {},
@@ -403,7 +401,7 @@ class WorkflowPerformanceReporter:
403
401
 
404
402
  return analysis
405
403
 
406
- def _identify_bottlenecks(self, tasks: List[TaskRun]) -> List[Dict[str, Any]]:
404
+ def _identify_bottlenecks(self, tasks: list[TaskRun]) -> list[dict[str, Any]]:
407
405
  """Identify performance bottlenecks in the workflow."""
408
406
  bottlenecks = []
409
407
 
@@ -497,7 +495,7 @@ class WorkflowPerformanceReporter:
497
495
 
498
496
  return sorted(bottlenecks, key=lambda x: x["value"], reverse=True)
499
497
 
500
- def _analyze_resource_utilization(self, tasks: List[TaskRun]) -> Dict[str, Any]:
498
+ def _analyze_resource_utilization(self, tasks: list[TaskRun]) -> dict[str, Any]:
501
499
  """Analyze overall resource utilization patterns."""
502
500
  analysis = {
503
501
  "cpu_distribution": {},
@@ -581,7 +579,7 @@ class WorkflowPerformanceReporter:
581
579
 
582
580
  return analysis
583
581
 
584
- def _analyze_errors(self, tasks: List[TaskRun]) -> Dict[str, Any]:
582
+ def _analyze_errors(self, tasks: list[TaskRun]) -> dict[str, Any]:
585
583
  """Analyze error patterns and failure modes."""
586
584
  analysis = {
587
585
  "error_summary": {},
@@ -634,7 +632,7 @@ class WorkflowPerformanceReporter:
634
632
 
635
633
  return analysis
636
634
 
637
- def _generate_insights(self, analysis: Dict[str, Any]) -> List[PerformanceInsight]:
635
+ def _generate_insights(self, analysis: dict[str, Any]) -> list[PerformanceInsight]:
638
636
  """Generate actionable insights from analysis results."""
639
637
  insights = []
640
638
 
@@ -741,8 +739,8 @@ class WorkflowPerformanceReporter:
741
739
  return insights
742
740
 
743
741
  def _generate_analysis_charts(
744
- self, run_id: str, tasks: List[TaskRun]
745
- ) -> Dict[str, str]:
742
+ self, run_id: str, tasks: list[TaskRun]
743
+ ) -> dict[str, str]:
746
744
  """Generate analysis charts and return file paths."""
747
745
  charts = {}
748
746
 
@@ -755,7 +753,7 @@ class WorkflowPerformanceReporter:
755
753
 
756
754
  return charts
757
755
 
758
- def _compare_runs(self, run_ids: List[str]) -> Dict[str, Any]:
756
+ def _compare_runs(self, run_ids: list[str]) -> dict[str, Any]:
759
757
  """Compare performance across multiple runs."""
760
758
  comparison = {"runs": [], "trends": {}, "relative_performance": {}}
761
759
 
@@ -814,9 +812,9 @@ class WorkflowPerformanceReporter:
814
812
 
815
813
  def _generate_html_report(
816
814
  self,
817
- analysis: Dict[str, Any],
818
- insights: List[PerformanceInsight],
819
- comparison_data: Optional[Dict[str, Any]] = None,
815
+ analysis: dict[str, Any],
816
+ insights: list[PerformanceInsight],
817
+ comparison_data: dict[str, Any] | None = None,
820
818
  ) -> str:
821
819
  """Generate HTML report content."""
822
820
  run_info = analysis["run_info"]
@@ -982,9 +980,9 @@ class WorkflowPerformanceReporter:
982
980
 
983
981
  def _generate_markdown_report(
984
982
  self,
985
- analysis: Dict[str, Any],
986
- insights: List[PerformanceInsight],
987
- comparison_data: Optional[Dict[str, Any]] = None,
983
+ analysis: dict[str, Any],
984
+ insights: list[PerformanceInsight],
985
+ comparison_data: dict[str, Any] | None = None,
988
986
  ) -> str:
989
987
  """Generate Markdown report content."""
990
988
  run_info = analysis["run_info"]
@@ -1098,9 +1096,9 @@ class WorkflowPerformanceReporter:
1098
1096
 
1099
1097
  def _generate_json_report(
1100
1098
  self,
1101
- analysis: Dict[str, Any],
1102
- insights: List[PerformanceInsight],
1103
- comparison_data: Optional[Dict[str, Any]] = None,
1099
+ analysis: dict[str, Any],
1100
+ insights: list[PerformanceInsight],
1101
+ comparison_data: dict[str, Any] | None = None,
1104
1102
  ) -> str:
1105
1103
  """Generate JSON report content."""
1106
1104
  report_data = {
@@ -1144,7 +1142,7 @@ class WorkflowPerformanceReporter:
1144
1142
 
1145
1143
  return json.dumps(report_data, indent=2, default=str)
1146
1144
 
1147
- def _generate_comparison_html(self, comparison_data: Dict[str, Any]) -> str:
1145
+ def _generate_comparison_html(self, comparison_data: dict[str, Any]) -> str:
1148
1146
  """Generate HTML for run comparison section."""
1149
1147
  runs = comparison_data.get("runs", [])
1150
1148
  trends = comparison_data.get("trends", {})
@@ -2,7 +2,7 @@
2
2
 
3
3
  import logging
4
4
  import uuid
5
- from typing import Any, Dict, List, Optional
5
+ from typing import Any
6
6
 
7
7
  from kailash.sdk_exceptions import ConnectionError, WorkflowValidationError
8
8
  from kailash.workflow.graph import Workflow
@@ -15,15 +15,15 @@ class WorkflowBuilder:
15
15
 
16
16
  def __init__(self):
17
17
  """Initialize an empty workflow builder."""
18
- self.nodes: Dict[str, Dict[str, Any]] = {}
19
- self.connections: List[Dict[str, str]] = []
20
- self._metadata: Dict[str, Any] = {}
18
+ self.nodes: dict[str, dict[str, Any]] = {}
19
+ self.connections: list[dict[str, str]] = []
20
+ self._metadata: dict[str, Any] = {}
21
21
 
22
22
  def add_node(
23
23
  self,
24
24
  node_type: str,
25
- node_id: Optional[str] = None,
26
- config: Optional[Dict[str, Any]] = None,
25
+ node_id: str | None = None,
26
+ config: dict[str, Any] | None = None,
27
27
  ) -> str:
28
28
  """
29
29
  Add a node to the workflow.
@@ -106,7 +106,7 @@ class WorkflowBuilder:
106
106
  self._metadata.update(kwargs)
107
107
  return self
108
108
 
109
- def build(self, workflow_id: Optional[str] = None, **kwargs) -> Workflow:
109
+ def build(self, workflow_id: str | None = None, **kwargs) -> Workflow:
110
110
  """
111
111
  Build and return a Workflow instance.
112
112
 
@@ -193,7 +193,7 @@ class WorkflowBuilder:
193
193
  return self
194
194
 
195
195
  @classmethod
196
- def from_dict(cls, config: Dict[str, Any]) -> "WorkflowBuilder":
196
+ def from_dict(cls, config: dict[str, Any]) -> "WorkflowBuilder":
197
197
  """
198
198
  Create builder from dictionary configuration.
199
199