kailash 0.9.3__py3-none-any.whl → 0.9.5__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.5.dist-info}/METADATA +21 -12
- {kailash-0.9.3.dist-info → kailash-0.9.5.dist-info}/RECORD +8 -8
- {kailash-0.9.3.dist-info → kailash-0.9.5.dist-info}/WHEEL +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.5.dist-info}/entry_points.txt +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.5.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.9.3.dist-info → kailash-0.9.5.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.5
|
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,27 @@ Dynamic: requires-python
|
|
117
117
|
|
118
118
|
---
|
119
119
|
|
120
|
-
## 🔥 Latest Release: v0.
|
120
|
+
## 🔥 Latest Release: v0.9.5 (July 31, 2025)
|
121
121
|
|
122
|
-
**
|
122
|
+
**PythonCodeNode Serialization Stability & Testing**
|
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
|
+
### 🧪 Comprehensive Regression Test Suite (TODO-129)
|
125
|
+
- **Added**: 33 unit tests validating PythonCodeNode serialization behavior and JSON compatibility
|
126
|
+
- **Added**: 6 integration tests with real infrastructure using only allowed modules
|
127
|
+
- **Added**: 6 E2E tests for complete business workflows and multi-channel consistency
|
128
|
+
- **Impact**: Ensures serialization fix from commit 2fcf8591 (June 11, 2025) stays stable
|
130
129
|
|
131
|
-
|
130
|
+
### 📚 Documentation Clarifications
|
131
|
+
- **Updated**: PythonCodeNode output structure documentation (all outputs wrapped in "result" key)
|
132
|
+
- **Enhanced**: Serialization consistency notes for multi-channel deployment
|
133
|
+
- **Improved**: Testing patterns for node serialization validation
|
134
|
+
|
135
|
+
### 🛡️ Stability Improvements
|
136
|
+
- **Focus**: Testing and documentation release to ensure PythonCodeNode serialization remains stable
|
137
|
+
- **Validation**: Complete test coverage for serialization edge cases
|
138
|
+
- **Quality**: Comprehensive regression prevention for critical workflow components
|
139
|
+
|
140
|
+
[Full Changelog](sdk-users/6-reference/changelogs/releases/v0.9.5-2025-07-31.md) | [Core SDK 0.9.5](https://pypi.org/project/kailash/0.9.5/) | [DataFlow 0.3.4](https://pypi.org/project/kailash-dataflow/0.3.4/)
|
132
141
|
|
133
142
|
## 🎯 What Makes Kailash Different
|
134
143
|
|
@@ -345,7 +354,7 @@ results, run_id = runtime.execute(workflow.build())
|
|
345
354
|
|
346
355
|
## 🚀 Applications Built with Kailash
|
347
356
|
|
348
|
-
### 1. DataFlow - Zero-Config Database Platform (v0.3.
|
357
|
+
### 1. DataFlow - Zero-Config Database Platform (v0.3.3)
|
349
358
|
```bash
|
350
359
|
pip install kailash-dataflow
|
351
360
|
```
|
@@ -353,7 +362,7 @@ pip install kailash-dataflow
|
|
353
362
|
- **Redis caching** with enterprise-grade invalidation
|
354
363
|
- **Automatic API generation** with OpenAPI documentation
|
355
364
|
- **4 production examples** with complete deployment guides
|
356
|
-
- **Latest**: v0.3.
|
365
|
+
- **Latest**: v0.3.3 - Critical connection parsing fix for special characters in passwords
|
357
366
|
|
358
367
|
### 2. Nexus - Multi-Channel Platform (v1.0.3)
|
359
368
|
```bash
|
@@ -1,4 +1,4 @@
|
|
1
|
-
kailash/__init__.py,sha256=
|
1
|
+
kailash/__init__.py,sha256=iwNjVBZF7kF09CsoOP8EUdmUe5uHc-Fdnl8RhXS2OYo,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.5.dist-info/licenses/LICENSE,sha256=Axe6g7bTrJkToK9h9j2SpRUKKNaDZDCo2lQ2zPxCE6s,1065
|
407
|
+
kailash-0.9.5.dist-info/METADATA,sha256=CdfS313HOOe7TPgBqpJaWlrycgXFgPXz_PI3FLihVwc,22298
|
408
|
+
kailash-0.9.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
409
|
+
kailash-0.9.5.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
|
410
|
+
kailash-0.9.5.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
|
411
|
+
kailash-0.9.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|