kailash 0.3.0__py3-none-any.whl → 0.3.1__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 (114) hide show
  1. kailash/__init__.py +1 -1
  2. kailash/access_control.py +40 -39
  3. kailash/api/auth.py +26 -32
  4. kailash/api/custom_nodes.py +29 -29
  5. kailash/api/custom_nodes_secure.py +35 -35
  6. kailash/api/database.py +17 -17
  7. kailash/api/gateway.py +19 -19
  8. kailash/api/mcp_integration.py +24 -23
  9. kailash/api/studio.py +45 -45
  10. kailash/api/workflow_api.py +8 -8
  11. kailash/cli/commands.py +5 -8
  12. kailash/manifest.py +42 -42
  13. kailash/mcp/__init__.py +1 -1
  14. kailash/mcp/ai_registry_server.py +20 -20
  15. kailash/mcp/client.py +9 -11
  16. kailash/mcp/client_new.py +10 -10
  17. kailash/mcp/server.py +1 -2
  18. kailash/mcp/server_enhanced.py +449 -0
  19. kailash/mcp/servers/ai_registry.py +6 -6
  20. kailash/mcp/utils/__init__.py +31 -0
  21. kailash/mcp/utils/cache.py +267 -0
  22. kailash/mcp/utils/config.py +263 -0
  23. kailash/mcp/utils/formatters.py +293 -0
  24. kailash/mcp/utils/metrics.py +418 -0
  25. kailash/nodes/ai/agents.py +9 -9
  26. kailash/nodes/ai/ai_providers.py +33 -34
  27. kailash/nodes/ai/embedding_generator.py +31 -32
  28. kailash/nodes/ai/intelligent_agent_orchestrator.py +62 -66
  29. kailash/nodes/ai/iterative_llm_agent.py +48 -48
  30. kailash/nodes/ai/llm_agent.py +32 -33
  31. kailash/nodes/ai/models.py +13 -13
  32. kailash/nodes/ai/self_organizing.py +44 -44
  33. kailash/nodes/api/auth.py +11 -11
  34. kailash/nodes/api/graphql.py +13 -13
  35. kailash/nodes/api/http.py +19 -19
  36. kailash/nodes/api/monitoring.py +20 -20
  37. kailash/nodes/api/rate_limiting.py +9 -13
  38. kailash/nodes/api/rest.py +29 -29
  39. kailash/nodes/api/security.py +44 -47
  40. kailash/nodes/base.py +21 -23
  41. kailash/nodes/base_async.py +7 -7
  42. kailash/nodes/base_cycle_aware.py +12 -12
  43. kailash/nodes/base_with_acl.py +5 -5
  44. kailash/nodes/code/python.py +56 -55
  45. kailash/nodes/data/directory.py +6 -6
  46. kailash/nodes/data/event_generation.py +10 -10
  47. kailash/nodes/data/file_discovery.py +28 -31
  48. kailash/nodes/data/readers.py +8 -8
  49. kailash/nodes/data/retrieval.py +10 -10
  50. kailash/nodes/data/sharepoint_graph.py +17 -17
  51. kailash/nodes/data/sources.py +5 -5
  52. kailash/nodes/data/sql.py +13 -13
  53. kailash/nodes/data/streaming.py +25 -25
  54. kailash/nodes/data/vector_db.py +22 -22
  55. kailash/nodes/data/writers.py +7 -7
  56. kailash/nodes/logic/async_operations.py +17 -17
  57. kailash/nodes/logic/convergence.py +11 -11
  58. kailash/nodes/logic/loop.py +4 -4
  59. kailash/nodes/logic/operations.py +11 -11
  60. kailash/nodes/logic/workflow.py +8 -9
  61. kailash/nodes/mixins/mcp.py +17 -17
  62. kailash/nodes/mixins.py +8 -10
  63. kailash/nodes/transform/chunkers.py +3 -3
  64. kailash/nodes/transform/formatters.py +7 -7
  65. kailash/nodes/transform/processors.py +10 -10
  66. kailash/runtime/access_controlled.py +18 -18
  67. kailash/runtime/async_local.py +17 -19
  68. kailash/runtime/docker.py +20 -22
  69. kailash/runtime/local.py +16 -16
  70. kailash/runtime/parallel.py +23 -23
  71. kailash/runtime/parallel_cyclic.py +27 -27
  72. kailash/runtime/runner.py +6 -6
  73. kailash/runtime/testing.py +20 -20
  74. kailash/sdk_exceptions.py +0 -58
  75. kailash/security.py +14 -26
  76. kailash/tracking/manager.py +38 -38
  77. kailash/tracking/metrics_collector.py +15 -14
  78. kailash/tracking/models.py +53 -53
  79. kailash/tracking/storage/base.py +7 -17
  80. kailash/tracking/storage/database.py +22 -23
  81. kailash/tracking/storage/filesystem.py +38 -40
  82. kailash/utils/export.py +21 -21
  83. kailash/utils/templates.py +2 -3
  84. kailash/visualization/api.py +30 -34
  85. kailash/visualization/dashboard.py +17 -17
  86. kailash/visualization/performance.py +16 -16
  87. kailash/visualization/reports.py +25 -27
  88. kailash/workflow/builder.py +8 -8
  89. kailash/workflow/convergence.py +13 -12
  90. kailash/workflow/cycle_analyzer.py +30 -32
  91. kailash/workflow/cycle_builder.py +12 -12
  92. kailash/workflow/cycle_config.py +16 -15
  93. kailash/workflow/cycle_debugger.py +40 -40
  94. kailash/workflow/cycle_exceptions.py +29 -29
  95. kailash/workflow/cycle_profiler.py +21 -21
  96. kailash/workflow/cycle_state.py +20 -22
  97. kailash/workflow/cyclic_runner.py +44 -44
  98. kailash/workflow/graph.py +40 -40
  99. kailash/workflow/mermaid_visualizer.py +9 -11
  100. kailash/workflow/migration.py +22 -22
  101. kailash/workflow/mock_registry.py +6 -6
  102. kailash/workflow/runner.py +9 -9
  103. kailash/workflow/safety.py +12 -13
  104. kailash/workflow/state.py +8 -11
  105. kailash/workflow/templates.py +19 -19
  106. kailash/workflow/validation.py +14 -14
  107. kailash/workflow/visualization.py +22 -22
  108. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/METADATA +53 -5
  109. kailash-0.3.1.dist-info/RECORD +136 -0
  110. kailash-0.3.0.dist-info/RECORD +0 -130
  111. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/WHEEL +0 -0
  112. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/entry_points.txt +0 -0
  113. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/licenses/LICENSE +0 -0
  114. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/top_level.txt +0 -0
kailash/nodes/api/auth.py CHANGED
@@ -12,7 +12,7 @@ Key Components:
12
12
 
13
13
  import base64
14
14
  import time
15
- from typing import Any, Dict
15
+ from typing import Any
16
16
 
17
17
  import requests
18
18
 
@@ -42,7 +42,7 @@ class BasicAuthNode(Node):
42
42
  - RESTClientNode: Uses auth headers for API calls
43
43
  """
44
44
 
45
- def get_parameters(self) -> Dict[str, NodeParameter]:
45
+ def get_parameters(self) -> dict[str, NodeParameter]:
46
46
  """Define the parameters this node accepts.
47
47
 
48
48
  Returns:
@@ -63,7 +63,7 @@ class BasicAuthNode(Node):
63
63
  ),
64
64
  }
65
65
 
66
- def get_output_schema(self) -> Dict[str, NodeParameter]:
66
+ def get_output_schema(self) -> dict[str, NodeParameter]:
67
67
  """Define the output schema for this node.
68
68
 
69
69
  Returns:
@@ -84,7 +84,7 @@ class BasicAuthNode(Node):
84
84
  ),
85
85
  }
86
86
 
87
- def run(self, **kwargs) -> Dict[str, Any]:
87
+ def run(self, **kwargs) -> dict[str, Any]:
88
88
  """Generate Basic Authentication headers.
89
89
 
90
90
  Args:
@@ -162,7 +162,7 @@ class OAuth2Node(Node):
162
162
  self.token_data = None # Will store token information
163
163
  self.token_expires_at = 0 # Timestamp when token expires
164
164
 
165
- def get_parameters(self) -> Dict[str, NodeParameter]:
165
+ def get_parameters(self) -> dict[str, NodeParameter]:
166
166
  """Define the parameters this node accepts.
167
167
 
168
168
  Returns:
@@ -236,7 +236,7 @@ class OAuth2Node(Node):
236
236
  ),
237
237
  }
238
238
 
239
- def get_output_schema(self) -> Dict[str, NodeParameter]:
239
+ def get_output_schema(self) -> dict[str, NodeParameter]:
240
240
  """Define the output schema for this node.
241
241
 
242
242
  Returns:
@@ -269,7 +269,7 @@ class OAuth2Node(Node):
269
269
  ),
270
270
  }
271
271
 
272
- def _get_token(self, **kwargs) -> Dict[str, Any]:
272
+ def _get_token(self, **kwargs) -> dict[str, Any]:
273
273
  """Get an OAuth token using the configured grant type.
274
274
 
275
275
  This method handles different grant types with appropriate parameters.
@@ -359,7 +359,7 @@ class OAuth2Node(Node):
359
359
  f"Failed to parse OAuth token response: {str(e)}"
360
360
  ) from e
361
361
 
362
- def run(self, **kwargs) -> Dict[str, Any]:
362
+ def run(self, **kwargs) -> dict[str, Any]:
363
363
  """Get OAuth authentication headers.
364
364
 
365
365
  This method handles token acquisition, caching, and renewal based on
@@ -444,7 +444,7 @@ class APIKeyNode(Node):
444
444
  - RESTClientNode: Uses auth data for API calls
445
445
  """
446
446
 
447
- def get_parameters(self) -> Dict[str, NodeParameter]:
447
+ def get_parameters(self) -> dict[str, NodeParameter]:
448
448
  """Define the parameters this node accepts.
449
449
 
450
450
  Returns:
@@ -477,7 +477,7 @@ class APIKeyNode(Node):
477
477
  ),
478
478
  }
479
479
 
480
- def get_output_schema(self) -> Dict[str, NodeParameter]:
480
+ def get_output_schema(self) -> dict[str, NodeParameter]:
481
481
  """Define the output schema for this node.
482
482
 
483
483
  Returns:
@@ -510,7 +510,7 @@ class APIKeyNode(Node):
510
510
  ),
511
511
  }
512
512
 
513
- def run(self, **kwargs) -> Dict[str, Any]:
513
+ def run(self, **kwargs) -> dict[str, Any]:
514
514
  """Generate API key authentication data.
515
515
 
516
516
  Args:
@@ -10,7 +10,7 @@ Key Components:
10
10
  - GraphQL query building and response handling utilities
11
11
  """
12
12
 
13
- from typing import Any, Dict, Optional
13
+ from typing import Any
14
14
 
15
15
  from kailash.nodes.api.http import AsyncHTTPRequestNode, HTTPRequestNode
16
16
  from kailash.nodes.base import Node, NodeParameter, register_node
@@ -60,7 +60,7 @@ class GraphQLClientNode(Node):
60
60
  super().__init__(**kwargs)
61
61
  self.http_node = HTTPRequestNode(**kwargs)
62
62
 
63
- def get_parameters(self) -> Dict[str, NodeParameter]:
63
+ def get_parameters(self) -> dict[str, NodeParameter]:
64
64
  """Define the parameters this node accepts.
65
65
 
66
66
  Returns:
@@ -137,7 +137,7 @@ class GraphQLClientNode(Node):
137
137
  ),
138
138
  }
139
139
 
140
- def get_output_schema(self) -> Dict[str, NodeParameter]:
140
+ def get_output_schema(self) -> dict[str, NodeParameter]:
141
141
  """Define the output schema for this node.
142
142
 
143
143
  Returns:
@@ -173,9 +173,9 @@ class GraphQLClientNode(Node):
173
173
  def _build_graphql_payload(
174
174
  self,
175
175
  query: str,
176
- variables: Dict[str, Any] = None,
177
- operation_name: Optional[str] = None,
178
- ) -> Dict[str, Any]:
176
+ variables: dict[str, Any] = None,
177
+ operation_name: str | None = None,
178
+ ) -> dict[str, Any]:
179
179
  """Build a GraphQL request payload.
180
180
 
181
181
  Args:
@@ -197,8 +197,8 @@ class GraphQLClientNode(Node):
197
197
  return payload
198
198
 
199
199
  def _process_graphql_response(
200
- self, response: Dict[str, Any], flatten_response: bool = False
201
- ) -> Dict[str, Any]:
200
+ self, response: dict[str, Any], flatten_response: bool = False
201
+ ) -> dict[str, Any]:
202
202
  """Process a GraphQL response.
203
203
 
204
204
  Args:
@@ -241,7 +241,7 @@ class GraphQLClientNode(Node):
241
241
 
242
242
  return {"data": data, "errors": errors, "success": success}
243
243
 
244
- def run(self, **kwargs) -> Dict[str, Any]:
244
+ def run(self, **kwargs) -> dict[str, Any]:
245
245
  """Execute a GraphQL query or mutation.
246
246
 
247
247
  Args:
@@ -362,7 +362,7 @@ class AsyncGraphQLClientNode(AsyncNode):
362
362
  self.http_node = AsyncHTTPRequestNode(**kwargs)
363
363
  self.graphql_node = GraphQLClientNode(**kwargs)
364
364
 
365
- def get_parameters(self) -> Dict[str, NodeParameter]:
365
+ def get_parameters(self) -> dict[str, NodeParameter]:
366
366
  """Define the parameters this node accepts.
367
367
 
368
368
  Returns:
@@ -371,7 +371,7 @@ class AsyncGraphQLClientNode(AsyncNode):
371
371
  # Same parameters as the synchronous version
372
372
  return self.graphql_node.get_parameters()
373
373
 
374
- def get_output_schema(self) -> Dict[str, NodeParameter]:
374
+ def get_output_schema(self) -> dict[str, NodeParameter]:
375
375
  """Define the output schema for this node.
376
376
 
377
377
  Returns:
@@ -380,7 +380,7 @@ class AsyncGraphQLClientNode(AsyncNode):
380
380
  # Same output schema as the synchronous version
381
381
  return self.graphql_node.get_output_schema()
382
382
 
383
- def run(self, **kwargs) -> Dict[str, Any]:
383
+ def run(self, **kwargs) -> dict[str, Any]:
384
384
  """Synchronous version of the GraphQL request, for compatibility.
385
385
 
386
386
  This is implemented for compatibility but users should use the
@@ -399,7 +399,7 @@ class AsyncGraphQLClientNode(AsyncNode):
399
399
  # Forward to the synchronous GraphQL node
400
400
  return self.graphql_node.run(**kwargs)
401
401
 
402
- async def async_run(self, **kwargs) -> Dict[str, Any]:
402
+ async def async_run(self, **kwargs) -> dict[str, Any]:
403
403
  """Execute a GraphQL query or mutation asynchronously.
404
404
 
405
405
  Args:
kailash/nodes/api/http.py CHANGED
@@ -8,7 +8,7 @@ import asyncio
8
8
  import base64
9
9
  import time
10
10
  from enum import Enum
11
- from typing import Any, Dict, Optional
11
+ from typing import Any
12
12
 
13
13
  import aiohttp
14
14
  import requests
@@ -48,8 +48,8 @@ class HTTPResponse(BaseModel):
48
48
  """
49
49
 
50
50
  status_code: int
51
- headers: Dict[str, str]
52
- content_type: Optional[str] = None
51
+ headers: dict[str, str]
52
+ content_type: str | None = None
53
53
  content: Any # Can be dict, str, bytes depending on response format
54
54
  response_time_ms: float
55
55
  url: str
@@ -194,7 +194,7 @@ class HTTPRequestNode(Node):
194
194
  super().__init__(**kwargs)
195
195
  self.session = requests.Session()
196
196
 
197
- def get_parameters(self) -> Dict[str, NodeParameter]:
197
+ def get_parameters(self) -> dict[str, NodeParameter]:
198
198
  """Define the parameters this node accepts.
199
199
 
200
200
  Returns:
@@ -328,7 +328,7 @@ class HTTPRequestNode(Node):
328
328
  ),
329
329
  }
330
330
 
331
- def get_output_schema(self) -> Dict[str, NodeParameter]:
331
+ def get_output_schema(self) -> dict[str, NodeParameter]:
332
332
  """Define the output schema for this node.
333
333
 
334
334
  Returns:
@@ -358,10 +358,10 @@ class HTTPRequestNode(Node):
358
358
  def _apply_authentication(
359
359
  self,
360
360
  headers: dict,
361
- auth_type: Optional[str],
362
- auth_token: Optional[str],
363
- auth_username: Optional[str],
364
- auth_password: Optional[str],
361
+ auth_type: str | None,
362
+ auth_token: str | None,
363
+ auth_username: str | None,
364
+ auth_password: str | None,
365
365
  api_key_header: str,
366
366
  ) -> dict:
367
367
  """Apply authentication to request headers.
@@ -398,7 +398,7 @@ class HTTPRequestNode(Node):
398
398
 
399
399
  return auth_headers
400
400
 
401
- def run(self, **kwargs) -> Dict[str, Any]:
401
+ def run(self, **kwargs) -> dict[str, Any]:
402
402
  """Execute an HTTP request.
403
403
 
404
404
  Args:
@@ -683,7 +683,7 @@ class AsyncHTTPRequestNode(AsyncNode):
683
683
  super().__init__(**kwargs)
684
684
  self._session = None # Will be created when needed
685
685
 
686
- def get_parameters(self) -> Dict[str, NodeParameter]:
686
+ def get_parameters(self) -> dict[str, NodeParameter]:
687
687
  """Define the parameters this node accepts.
688
688
 
689
689
  Returns:
@@ -692,7 +692,7 @@ class AsyncHTTPRequestNode(AsyncNode):
692
692
  # Same parameters as the synchronous version
693
693
  return HTTPRequestNode().get_parameters()
694
694
 
695
- def get_output_schema(self) -> Dict[str, NodeParameter]:
695
+ def get_output_schema(self) -> dict[str, NodeParameter]:
696
696
  """Define the output schema for this node.
697
697
 
698
698
  Returns:
@@ -704,10 +704,10 @@ class AsyncHTTPRequestNode(AsyncNode):
704
704
  def _apply_authentication(
705
705
  self,
706
706
  headers: dict,
707
- auth_type: Optional[str],
708
- auth_token: Optional[str],
709
- auth_username: Optional[str],
710
- auth_password: Optional[str],
707
+ auth_type: str | None,
708
+ auth_token: str | None,
709
+ auth_username: str | None,
710
+ auth_password: str | None,
711
711
  api_key_header: str,
712
712
  ) -> dict:
713
713
  """Apply authentication to request headers.
@@ -744,7 +744,7 @@ class AsyncHTTPRequestNode(AsyncNode):
744
744
 
745
745
  return auth_headers
746
746
 
747
- def run(self, **kwargs) -> Dict[str, Any]:
747
+ def run(self, **kwargs) -> dict[str, Any]:
748
748
  """Synchronous version of the request, for compatibility.
749
749
 
750
750
  This is implemented for compatibility but users should use the
@@ -763,7 +763,7 @@ class AsyncHTTPRequestNode(AsyncNode):
763
763
  http_node = HTTPRequestNode(**self.config)
764
764
  return http_node.run(**kwargs)
765
765
 
766
- async def async_run(self, **kwargs) -> Dict[str, Any]:
766
+ async def async_run(self, **kwargs) -> dict[str, Any]:
767
767
  """Execute an HTTP request asynchronously.
768
768
 
769
769
  Args:
@@ -937,7 +937,7 @@ class AsyncHTTPRequestNode(AsyncNode):
937
937
 
938
938
  return result
939
939
 
940
- except (aiohttp.ClientError, asyncio.TimeoutError) as e:
940
+ except (TimeoutError, aiohttp.ClientError) as e:
941
941
  self.logger.warning(f"Async request failed: {str(e)}")
942
942
 
943
943
  # Last attempt, no more retries
@@ -4,8 +4,8 @@ import asyncio
4
4
  import socket
5
5
  import subprocess
6
6
  import time
7
- from datetime import datetime, timezone
8
- from typing import Any, Dict, List
7
+ from datetime import UTC, datetime
8
+ from typing import Any
9
9
 
10
10
  import requests
11
11
 
@@ -92,7 +92,7 @@ class HealthCheckNode(Node):
92
92
  >>> assert 'health_results' in result
93
93
  """
94
94
 
95
- def get_parameters(self) -> Dict[str, NodeParameter]:
95
+ def get_parameters(self) -> dict[str, NodeParameter]:
96
96
  return {
97
97
  "targets": NodeParameter(
98
98
  name="targets",
@@ -130,7 +130,7 @@ class HealthCheckNode(Node):
130
130
  ),
131
131
  }
132
132
 
133
- def run(self, **kwargs) -> Dict[str, Any]:
133
+ def run(self, **kwargs) -> dict[str, Any]:
134
134
  targets = kwargs["targets"]
135
135
  timeout = kwargs.get("timeout", 30)
136
136
  retries = kwargs.get("retries", 2)
@@ -162,12 +162,12 @@ class HealthCheckNode(Node):
162
162
  "healthy_count": len([r for r in results if r["status"] == "healthy"]),
163
163
  "unhealthy_count": len([r for r in results if r["status"] == "unhealthy"]),
164
164
  "execution_time": execution_time,
165
- "timestamp": datetime.now(timezone.utc).isoformat() + "Z",
165
+ "timestamp": datetime.now(UTC).isoformat() + "Z",
166
166
  }
167
167
 
168
168
  async def _run_checks_parallel(
169
- self, targets: List[Dict], timeout: int, retries: int, include_metrics: bool
170
- ) -> List[Dict[str, Any]]:
169
+ self, targets: list[dict], timeout: int, retries: int, include_metrics: bool
170
+ ) -> list[dict[str, Any]]:
171
171
  """Run health checks in parallel using asyncio."""
172
172
 
173
173
  async def run_single_check(target):
@@ -184,8 +184,8 @@ class HealthCheckNode(Node):
184
184
  return await asyncio.gather(*tasks, return_exceptions=True)
185
185
 
186
186
  def _run_checks_sequential(
187
- self, targets: List[Dict], timeout: int, retries: int, include_metrics: bool
188
- ) -> List[Dict[str, Any]]:
187
+ self, targets: list[dict], timeout: int, retries: int, include_metrics: bool
188
+ ) -> list[dict[str, Any]]:
189
189
  """Run health checks sequentially."""
190
190
  return [
191
191
  self._perform_health_check(target, timeout, retries, include_metrics)
@@ -193,8 +193,8 @@ class HealthCheckNode(Node):
193
193
  ]
194
194
 
195
195
  def _perform_health_check(
196
- self, target: Dict, timeout: int, retries: int, include_metrics: bool
197
- ) -> Dict[str, Any]:
196
+ self, target: dict, timeout: int, retries: int, include_metrics: bool
197
+ ) -> dict[str, Any]:
198
198
  """Perform a single health check with retry logic."""
199
199
 
200
200
  check_type = target.get("type", "unknown")
@@ -228,7 +228,7 @@ class HealthCheckNode(Node):
228
228
  result["check_id"] = check_id
229
229
  result["check_type"] = check_type
230
230
  result["target"] = target
231
- result["timestamp"] = datetime.now(timezone.utc).isoformat() + "Z"
231
+ result["timestamp"] = datetime.now(UTC).isoformat() + "Z"
232
232
 
233
233
  # If successful, return immediately
234
234
  if result["status"] == "healthy":
@@ -245,7 +245,7 @@ class HealthCheckNode(Node):
245
245
  "details": {"error": str(e), "error_type": type(e).__name__},
246
246
  "response_time": time.time() - start_time,
247
247
  "attempt": attempt + 1,
248
- "timestamp": datetime.now(timezone.utc).isoformat() + "Z",
248
+ "timestamp": datetime.now(UTC).isoformat() + "Z",
249
249
  }
250
250
 
251
251
  # Wait before retry (exponential backoff)
@@ -253,7 +253,7 @@ class HealthCheckNode(Node):
253
253
 
254
254
  return result
255
255
 
256
- def _check_http(self, target: Dict, timeout: int) -> Dict[str, Any]:
256
+ def _check_http(self, target: dict, timeout: int) -> dict[str, Any]:
257
257
  """Perform HTTP health check."""
258
258
  url = target["url"]
259
259
  expected_status = target.get("expected_status", 200)
@@ -296,7 +296,7 @@ class HealthCheckNode(Node):
296
296
  },
297
297
  }
298
298
 
299
- def _check_tcp(self, target: Dict, timeout: int) -> Dict[str, Any]:
299
+ def _check_tcp(self, target: dict, timeout: int) -> dict[str, Any]:
300
300
  """Perform TCP port connectivity check."""
301
301
  host = target["host"]
302
302
  port = target["port"]
@@ -321,7 +321,7 @@ class HealthCheckNode(Node):
321
321
  finally:
322
322
  sock.close()
323
323
 
324
- def _check_disk(self, target: Dict) -> Dict[str, Any]:
324
+ def _check_disk(self, target: dict) -> dict[str, Any]:
325
325
  """Perform disk space check."""
326
326
  import shutil
327
327
 
@@ -365,7 +365,7 @@ class HealthCheckNode(Node):
365
365
  "details": {"path": path, "error": str(e)},
366
366
  }
367
367
 
368
- def _check_command(self, target: Dict, timeout: int) -> Dict[str, Any]:
368
+ def _check_command(self, target: dict, timeout: int) -> dict[str, Any]:
369
369
  """Perform custom command health check."""
370
370
  command = target["command"]
371
371
  expected_exit_code = target.get("expected_exit_code", 0)
@@ -409,7 +409,7 @@ class HealthCheckNode(Node):
409
409
  "details": {"command": command, "timeout": timeout},
410
410
  }
411
411
 
412
- def _check_database(self, target: Dict, timeout: int) -> Dict[str, Any]:
412
+ def _check_database(self, target: dict, timeout: int) -> dict[str, Any]:
413
413
  """Perform database connectivity check."""
414
414
  # This is a simplified example - in production, you'd use actual database drivers
415
415
  db_type = target.get("db_type", "postgresql")
@@ -421,8 +421,8 @@ class HealthCheckNode(Node):
421
421
  return self._check_tcp({"host": host, "port": port}, timeout)
422
422
 
423
423
  def _generate_summary(
424
- self, results: List[Dict], execution_time: float
425
- ) -> Dict[str, Any]:
424
+ self, results: list[dict], execution_time: float
425
+ ) -> dict[str, Any]:
426
426
  """Generate summary statistics from health check results."""
427
427
  total_checks = len(results)
428
428
  healthy_checks = len([r for r in results if r.get("status") == "healthy"])
@@ -17,7 +17,7 @@ import time
17
17
  from abc import ABC, abstractmethod
18
18
  from collections import deque
19
19
  from dataclasses import dataclass
20
- from typing import Any, Dict, Optional
20
+ from typing import Any
21
21
 
22
22
  from kailash.nodes.base import Node, NodeParameter, register_node
23
23
  from kailash.nodes.base_async import AsyncNode
@@ -34,7 +34,7 @@ class RateLimitConfig:
34
34
  max_requests: int = 100 # Maximum requests allowed
35
35
  time_window: float = 60.0 # Time window in seconds
36
36
  strategy: str = "token_bucket" # Rate limiting strategy
37
- burst_limit: Optional[int] = None # Maximum burst requests (for token bucket)
37
+ burst_limit: int | None = None # Maximum burst requests (for token bucket)
38
38
  backoff_factor: float = 1.0 # Backoff factor when rate limited
39
39
  max_backoff: float = 300.0 # Maximum backoff time in seconds
40
40
 
@@ -61,7 +61,6 @@ class RateLimiter(ABC):
61
61
  Returns:
62
62
  True if request can proceed, False if rate limited
63
63
  """
64
- pass
65
64
 
66
65
  @abstractmethod
67
66
  def wait_time(self) -> float:
@@ -70,7 +69,6 @@ class RateLimiter(ABC):
70
69
  Returns:
71
70
  Wait time in seconds (0 if can proceed immediately)
72
71
  """
73
- pass
74
72
 
75
73
  @abstractmethod
76
74
  def consume(self) -> bool:
@@ -79,12 +77,10 @@ class RateLimiter(ABC):
79
77
  Returns:
80
78
  True if token was consumed, False if rate limited
81
79
  """
82
- pass
83
80
 
84
81
  @abstractmethod
85
82
  def reset(self) -> None:
86
83
  """Reset the rate limiter state."""
87
- pass
88
84
 
89
85
 
90
86
  class TokenBucketRateLimiter(RateLimiter):
@@ -295,7 +291,7 @@ class RateLimitedAPINode(Node):
295
291
  self.rate_limiter = create_rate_limiter(rate_limit_config)
296
292
  self.config = rate_limit_config
297
293
 
298
- def get_parameters(self) -> Dict[str, NodeParameter]:
294
+ def get_parameters(self) -> dict[str, NodeParameter]:
299
295
  """Define the parameters this node accepts.
300
296
 
301
297
  Returns:
@@ -326,7 +322,7 @@ class RateLimitedAPINode(Node):
326
322
 
327
323
  return params
328
324
 
329
- def get_output_schema(self) -> Dict[str, NodeParameter]:
325
+ def get_output_schema(self) -> dict[str, NodeParameter]:
330
326
  """Define the output schema for this node.
331
327
 
332
328
  Returns:
@@ -345,7 +341,7 @@ class RateLimitedAPINode(Node):
345
341
 
346
342
  return schema
347
343
 
348
- def run(self, **kwargs) -> Dict[str, Any]:
344
+ def run(self, **kwargs) -> dict[str, Any]:
349
345
  """Execute the wrapped node with rate limiting.
350
346
 
351
347
  Args:
@@ -463,7 +459,7 @@ class AsyncRateLimitedAPINode(AsyncNode):
463
459
  self.config = rate_limit_config
464
460
  self.sync_node = RateLimitedAPINode(wrapped_node, rate_limit_config, **kwargs)
465
461
 
466
- def get_parameters(self) -> Dict[str, NodeParameter]:
462
+ def get_parameters(self) -> dict[str, NodeParameter]:
467
463
  """Define the parameters this node accepts.
468
464
 
469
465
  Returns:
@@ -471,7 +467,7 @@ class AsyncRateLimitedAPINode(AsyncNode):
471
467
  """
472
468
  return self.sync_node.get_parameters()
473
469
 
474
- def get_output_schema(self) -> Dict[str, NodeParameter]:
470
+ def get_output_schema(self) -> dict[str, NodeParameter]:
475
471
  """Define the output schema for this node.
476
472
 
477
473
  Returns:
@@ -479,7 +475,7 @@ class AsyncRateLimitedAPINode(AsyncNode):
479
475
  """
480
476
  return self.sync_node.get_output_schema()
481
477
 
482
- def run(self, **kwargs) -> Dict[str, Any]:
478
+ def run(self, **kwargs) -> dict[str, Any]:
483
479
  """Synchronous version for compatibility.
484
480
 
485
481
  Args:
@@ -490,7 +486,7 @@ class AsyncRateLimitedAPINode(AsyncNode):
490
486
  """
491
487
  return self.sync_node.run(**kwargs)
492
488
 
493
- async def async_run(self, **kwargs) -> Dict[str, Any]:
489
+ async def async_run(self, **kwargs) -> dict[str, Any]:
494
490
  """Execute the wrapped async node with rate limiting.
495
491
 
496
492
  Args: