kailash 0.9.3__py3-none-any.whl → 0.9.4__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 +1 -1
- kailash/runtime/local.py +117 -1
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/METADATA +22 -12
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/RECORD +8 -8
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/WHEEL +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/entry_points.txt +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.4.dist-info}/top_level.txt +0 -0
kailash/__init__.py
CHANGED
kailash/runtime/local.py
CHANGED
@@ -72,6 +72,75 @@ from kailash.workflow.cyclic_runner import CyclicWorkflowExecutor
|
|
72
72
|
|
73
73
|
logger = logging.getLogger(__name__)
|
74
74
|
|
75
|
+
|
76
|
+
class ContentAwareExecutionError(Exception):
|
77
|
+
"""Exception raised when content-aware success detection identifies a failure."""
|
78
|
+
|
79
|
+
pass
|
80
|
+
|
81
|
+
|
82
|
+
def detect_success(result):
|
83
|
+
"""Detect success or failure from a node execution result."""
|
84
|
+
# Handle None result (backward compatibility)
|
85
|
+
if result is None:
|
86
|
+
return True, None
|
87
|
+
|
88
|
+
# Handle non-dict results (backward compatibility)
|
89
|
+
if not isinstance(result, dict):
|
90
|
+
return True, None
|
91
|
+
|
92
|
+
# Handle empty dict (backward compatibility)
|
93
|
+
if not result:
|
94
|
+
return True, None
|
95
|
+
|
96
|
+
# Check for success field
|
97
|
+
if "success" not in result:
|
98
|
+
# No success field, default to success (backward compatibility)
|
99
|
+
return True, None
|
100
|
+
|
101
|
+
success_value = result["success"]
|
102
|
+
|
103
|
+
# Evaluate success value as boolean
|
104
|
+
is_success = bool(success_value)
|
105
|
+
|
106
|
+
if is_success:
|
107
|
+
# Operation succeeded
|
108
|
+
return True, None
|
109
|
+
else:
|
110
|
+
# Operation failed, extract error information
|
111
|
+
error_info = result.get("error", "Operation failed (no error details provided)")
|
112
|
+
return False, error_info
|
113
|
+
|
114
|
+
|
115
|
+
def should_stop_on_content_failure(result, content_aware_mode=True, stop_on_error=True):
|
116
|
+
"""Check if execution should stop based on content indicating failure."""
|
117
|
+
if not content_aware_mode or not stop_on_error:
|
118
|
+
return False, None
|
119
|
+
|
120
|
+
# Use detect_success for the actual detection logic
|
121
|
+
is_success, error_info = detect_success(result)
|
122
|
+
|
123
|
+
if is_success:
|
124
|
+
# Operation succeeded, continue execution
|
125
|
+
return False, None
|
126
|
+
else:
|
127
|
+
# Operation failed, stop execution
|
128
|
+
return True, error_info
|
129
|
+
|
130
|
+
|
131
|
+
def create_content_aware_error(node_id, result, error_message=None):
|
132
|
+
"""Create a ContentAwareExecutionError from node result."""
|
133
|
+
if error_message is None:
|
134
|
+
error_message = result.get("error", "Operation failed")
|
135
|
+
|
136
|
+
error = ContentAwareExecutionError(
|
137
|
+
f"Node '{node_id}' reported failure: {error_message}"
|
138
|
+
)
|
139
|
+
error.node_id = node_id
|
140
|
+
error.failure_data = result
|
141
|
+
return error
|
142
|
+
|
143
|
+
|
75
144
|
# Conditional execution imports (lazy-loaded to avoid circular imports)
|
76
145
|
_ConditionalBranchAnalyzer = None
|
77
146
|
_DynamicExecutionPlanner = None
|
@@ -129,6 +198,7 @@ class LocalRuntime:
|
|
129
198
|
secret_provider: Optional[Any] = None,
|
130
199
|
connection_validation: str = "warn",
|
131
200
|
conditional_execution: str = "route_data",
|
201
|
+
content_aware_success_detection: bool = True,
|
132
202
|
):
|
133
203
|
"""Initialize the unified runtime.
|
134
204
|
|
@@ -150,6 +220,9 @@ class LocalRuntime:
|
|
150
220
|
conditional_execution: Execution strategy for conditional routing:
|
151
221
|
- "route_data": Current behavior - all nodes execute, data routing only (default)
|
152
222
|
- "skip_branches": New behavior - skip unreachable branches entirely
|
223
|
+
content_aware_success_detection: Whether to enable content-aware success detection:
|
224
|
+
- True: Check return value content for success/failure patterns (default)
|
225
|
+
- False: Only use exception-based failure detection (legacy mode)
|
153
226
|
"""
|
154
227
|
# Validate connection_validation parameter
|
155
228
|
valid_conn_modes = {"off", "warn", "strict"}
|
@@ -179,6 +252,7 @@ class LocalRuntime:
|
|
179
252
|
self.resource_limits = resource_limits or {}
|
180
253
|
self.connection_validation = connection_validation
|
181
254
|
self.conditional_execution = conditional_execution
|
255
|
+
self.content_aware_success_detection = content_aware_success_detection
|
182
256
|
self.logger = logger
|
183
257
|
|
184
258
|
# Enterprise feature managers (lazy initialization)
|
@@ -869,6 +943,43 @@ class LocalRuntime:
|
|
869
943
|
if self.debug:
|
870
944
|
self.logger.debug(f"Node {node_id} outputs: {outputs}")
|
871
945
|
|
946
|
+
# Content-aware success detection (CRITICAL FIX)
|
947
|
+
if self.content_aware_success_detection:
|
948
|
+
should_stop, error_message = should_stop_on_content_failure(
|
949
|
+
result=outputs,
|
950
|
+
content_aware_mode=True,
|
951
|
+
stop_on_error=True, # Always stop on content failures when content-aware mode is enabled
|
952
|
+
)
|
953
|
+
|
954
|
+
if should_stop:
|
955
|
+
# Create detailed error for content-aware failure
|
956
|
+
error = create_content_aware_error(
|
957
|
+
node_id=node_id,
|
958
|
+
result=(
|
959
|
+
outputs
|
960
|
+
if isinstance(outputs, dict)
|
961
|
+
else {"error": error_message}
|
962
|
+
),
|
963
|
+
error_message=error_message,
|
964
|
+
)
|
965
|
+
|
966
|
+
# Log the content-aware failure
|
967
|
+
self.logger.error(
|
968
|
+
f"Content-aware failure detected in node {node_id}: {error_message}"
|
969
|
+
)
|
970
|
+
|
971
|
+
# Update task status to failed if task manager exists
|
972
|
+
if task and task_manager:
|
973
|
+
task_manager.update_task_status(
|
974
|
+
task.task_id,
|
975
|
+
TaskStatus.FAILED,
|
976
|
+
error=str(error),
|
977
|
+
ended_at=datetime.now(UTC),
|
978
|
+
)
|
979
|
+
|
980
|
+
# Raise the content-aware execution error
|
981
|
+
raise error
|
982
|
+
|
872
983
|
# Update task status with enhanced metrics
|
873
984
|
if task and task_manager:
|
874
985
|
# Convert performance metrics to TaskMetrics format
|
@@ -922,7 +1033,12 @@ class LocalRuntime:
|
|
922
1033
|
f"Error during node {node_id} cleanup after failure: {cleanup_error}"
|
923
1034
|
)
|
924
1035
|
|
925
|
-
#
|
1036
|
+
# Content-aware execution errors should always stop execution
|
1037
|
+
if isinstance(e, ContentAwareExecutionError):
|
1038
|
+
error_msg = f"Content-aware failure in node '{node_id}': {e}"
|
1039
|
+
raise WorkflowExecutionError(error_msg) from e
|
1040
|
+
|
1041
|
+
# Determine if we should continue for other exceptions
|
926
1042
|
if self._should_stop_on_error(workflow, node_id):
|
927
1043
|
error_msg = f"Node '{node_id}' failed: {e}"
|
928
1044
|
if len(failed_nodes) > 1:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kailash
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.4
|
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
|
@@ -117,18 +117,28 @@ Dynamic: requires-python
|
|
117
117
|
|
118
118
|
---
|
119
119
|
|
120
|
-
## 🔥 Latest Release: v0.
|
120
|
+
## 🔥 Latest Release: v0.9.4 (July 31, 2025)
|
121
121
|
|
122
|
-
**
|
122
|
+
**Critical DataFlow Fixes & Runtime Enhancements**
|
123
123
|
|
124
|
-
|
125
|
-
-
|
126
|
-
-
|
127
|
-
-
|
128
|
-
-
|
129
|
-
- ✅ **Breaking Changes**: See [migration guide](sdk-users/6-reference/changelogs/releases/v0.8.5-2025-07-20.md)
|
124
|
+
### 🛡️ DataFlow Connection String Parsing
|
125
|
+
- **Fixed**: Special characters in passwords (`#`, `$`, `@`, `?`) now work automatically
|
126
|
+
- **Before**: `invalid literal for int() with base 10` errors with special characters
|
127
|
+
- **After**: All passwords work seamlessly without manual URL encoding
|
128
|
+
- **Impact**: Major usability improvement for production deployments
|
130
129
|
|
131
|
-
|
130
|
+
### 🎯 Runtime Content-Aware Success Detection
|
131
|
+
- **New**: LocalRuntime detects `{"success": False}` patterns in node responses
|
132
|
+
- **Benefit**: Earlier failure detection and better error reporting
|
133
|
+
- **Default**: Enabled by default, backward compatible
|
134
|
+
- **Config**: `LocalRuntime(content_aware_success_detection=True)`
|
135
|
+
|
136
|
+
### 📚 Documentation Updates
|
137
|
+
- Updated DataFlow connection examples with special character support
|
138
|
+
- Added runtime configuration options documentation
|
139
|
+
- Enhanced troubleshooting guide with new diagnosis patterns
|
140
|
+
|
141
|
+
[Full Changelog](sdk-users/6-reference/changelogs/releases/v0.9.4-2025-07-31.md) | [Core SDK 0.9.4](https://pypi.org/project/kailash/0.9.4/) | [DataFlow 0.3.3](https://pypi.org/project/kailash-dataflow/0.3.3/)
|
132
142
|
|
133
143
|
## 🎯 What Makes Kailash Different
|
134
144
|
|
@@ -345,7 +355,7 @@ results, run_id = runtime.execute(workflow.build())
|
|
345
355
|
|
346
356
|
## 🚀 Applications Built with Kailash
|
347
357
|
|
348
|
-
### 1. DataFlow - Zero-Config Database Platform (v0.3.
|
358
|
+
### 1. DataFlow - Zero-Config Database Platform (v0.3.3)
|
349
359
|
```bash
|
350
360
|
pip install kailash-dataflow
|
351
361
|
```
|
@@ -353,7 +363,7 @@ pip install kailash-dataflow
|
|
353
363
|
- **Redis caching** with enterprise-grade invalidation
|
354
364
|
- **Automatic API generation** with OpenAPI documentation
|
355
365
|
- **4 production examples** with complete deployment guides
|
356
|
-
- **Latest**: v0.3.
|
366
|
+
- **Latest**: v0.3.3 - Critical connection parsing fix for special characters in passwords
|
357
367
|
|
358
368
|
### 2. Nexus - Multi-Channel Platform (v1.0.3)
|
359
369
|
```bash
|
@@ -1,4 +1,4 @@
|
|
1
|
-
kailash/__init__.py,sha256=
|
1
|
+
kailash/__init__.py,sha256=cYvKipwAgEW7BQ4t7vCdCY9CctztVnWa2il6THIYeW4,2771
|
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
|
@@ -324,7 +324,7 @@ kailash/runtime/async_local.py,sha256=sYNggSU0R-oo8cCvU5ayodDBqASzUhxu994ZvZxDSC
|
|
324
324
|
kailash/runtime/compatibility_reporter.py,sha256=TOQD0ODnJdsxEPyNSYOV_zQxu60X_yvHeu26seFOMEA,19807
|
325
325
|
kailash/runtime/docker.py,sha256=sZknVl1PCGfAZeyc0-exTuKlllSyjYlFIgJoiB3CRNs,23500
|
326
326
|
kailash/runtime/hierarchical_switch_executor.py,sha256=k6aPGbpf6z2m6dTbHrEyuDR8ZCvOqUanBGYp70arQn0,20782
|
327
|
-
kailash/runtime/local.py,sha256=
|
327
|
+
kailash/runtime/local.py,sha256=xDJ7Z9UwqR432rRRUzkOyHJr1ejPE751VB-oW-BuBGE,147155
|
328
328
|
kailash/runtime/parallel.py,sha256=-M9VVG36RxnrrmdbcBe9IjQWb58tAEEo76RQQ2uIXaE,21084
|
329
329
|
kailash/runtime/parallel_cyclic.py,sha256=yANZHnePjhCPuCFbq3lFQA1K6jbCv5Of5-vIKbCsmZk,19863
|
330
330
|
kailash/runtime/parameter_injection.py,sha256=kG4GhmarsRr5t3VDFbc2G1HSbsZJg6UmienHCE2Ru7o,14852
|
@@ -403,9 +403,9 @@ kailash/workflow/templates.py,sha256=XQMAKZXC2dlxgMMQhSEOWAF3hIbe9JJt9j_THchhAm8
|
|
403
403
|
kailash/workflow/type_inference.py,sha256=i1F7Yd_Z3elTXrthsLpqGbOnQBIVVVEjhRpI0HrIjd0,24492
|
404
404
|
kailash/workflow/validation.py,sha256=r2zApGiiG8UEn7p5Ji842l8OR1_KftzDkWc7gg0cac0,44675
|
405
405
|
kailash/workflow/visualization.py,sha256=nHBW-Ai8QBMZtn2Nf3EE1_aiMGi9S6Ui_BfpA5KbJPU,23187
|
406
|
-
kailash-0.9.
|
407
|
-
kailash-0.9.
|
408
|
-
kailash-0.9.
|
409
|
-
kailash-0.9.
|
410
|
-
kailash-0.9.
|
411
|
-
kailash-0.9.
|
406
|
+
kailash-0.9.4.dist-info/licenses/LICENSE,sha256=Axe6g7bTrJkToK9h9j2SpRUKKNaDZDCo2lQ2zPxCE6s,1065
|
407
|
+
kailash-0.9.4.dist-info/METADATA,sha256=YcBgKrE5E7m1D70nINO6sog67Tn7Wcb8s6eF__zybF4,22203
|
408
|
+
kailash-0.9.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
409
|
+
kailash-0.9.4.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
|
410
|
+
kailash-0.9.4.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
|
411
|
+
kailash-0.9.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|