kailash 0.9.18__py3-none-any.whl → 0.9.19__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/mcp_server/subscriptions.py +3 -3
- kailash/nodes/data/async_sql.py +93 -26
- kailash/runtime/local.py +4 -1
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/METADATA +1 -1
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/RECORD +10 -10
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/WHEEL +0 -0
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/entry_points.txt +0 -0
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/licenses/NOTICE +0 -0
- {kailash-0.9.18.dist-info → kailash-0.9.19.dist-info}/top_level.txt +0 -0
@@ -1075,9 +1075,9 @@ class ResourceSubscriptionManager:
|
|
1075
1075
|
This method should be overridden or configured to fetch actual resource data.
|
1076
1076
|
For now, it returns basic resource information from the monitored state.
|
1077
1077
|
"""
|
1078
|
-
async with self.
|
1079
|
-
if uri in self.
|
1080
|
-
state = self.
|
1078
|
+
async with self.resource_monitor._lock:
|
1079
|
+
if uri in self.resource_monitor._resource_states:
|
1080
|
+
state = self.resource_monitor._resource_states[uri]
|
1081
1081
|
return {
|
1082
1082
|
"uri": uri,
|
1083
1083
|
"content": state.get("content", {}),
|
kailash/nodes/data/async_sql.py
CHANGED
@@ -1530,15 +1530,28 @@ class SQLiteAdapter(DatabaseAdapter):
|
|
1530
1530
|
|
1531
1531
|
if fetch_mode == FetchMode.ONE:
|
1532
1532
|
row = await cursor.fetchone()
|
1533
|
-
|
1533
|
+
result = self._convert_row(dict(row)) if row else None
|
1534
1534
|
elif fetch_mode == FetchMode.ALL:
|
1535
1535
|
rows = await cursor.fetchall()
|
1536
|
-
|
1536
|
+
result = [self._convert_row(dict(row)) for row in rows]
|
1537
1537
|
elif fetch_mode == FetchMode.MANY:
|
1538
1538
|
if not fetch_size:
|
1539
1539
|
raise ValueError("fetch_size required for MANY mode")
|
1540
1540
|
rows = await cursor.fetchmany(fetch_size)
|
1541
|
-
|
1541
|
+
result = [self._convert_row(dict(row)) for row in rows]
|
1542
|
+
else:
|
1543
|
+
result = []
|
1544
|
+
|
1545
|
+
# Check if this was an INSERT and capture lastrowid for SQLite
|
1546
|
+
if query.strip().upper().startswith("INSERT") and (
|
1547
|
+
not result or result == [] or result is None
|
1548
|
+
):
|
1549
|
+
# For INSERT without RETURNING, capture lastrowid
|
1550
|
+
lastrowid = cursor.lastrowid if hasattr(cursor, "lastrowid") else None
|
1551
|
+
if lastrowid is not None:
|
1552
|
+
return {"lastrowid": lastrowid}
|
1553
|
+
|
1554
|
+
return result
|
1542
1555
|
else:
|
1543
1556
|
# Create new connection for non-transactional queries
|
1544
1557
|
if self._is_memory_db:
|
@@ -1557,6 +1570,19 @@ class SQLiteAdapter(DatabaseAdapter):
|
|
1557
1570
|
raise ValueError("fetch_size required for MANY mode")
|
1558
1571
|
rows = await cursor.fetchmany(fetch_size)
|
1559
1572
|
result = [self._convert_row(dict(row)) for row in rows]
|
1573
|
+
else:
|
1574
|
+
result = []
|
1575
|
+
|
1576
|
+
# Check if this was an INSERT and capture lastrowid for SQLite
|
1577
|
+
if query.strip().upper().startswith("INSERT") and (
|
1578
|
+
not result or result == []
|
1579
|
+
):
|
1580
|
+
# For INSERT without RETURNING, capture lastrowid
|
1581
|
+
lastrowid = (
|
1582
|
+
cursor.lastrowid if hasattr(cursor, "lastrowid") else None
|
1583
|
+
)
|
1584
|
+
if lastrowid is not None:
|
1585
|
+
result = {"lastrowid": lastrowid}
|
1560
1586
|
|
1561
1587
|
# Commit for memory databases (needed for INSERT/UPDATE/DELETE)
|
1562
1588
|
await db.commit()
|
@@ -1577,9 +1603,24 @@ class SQLiteAdapter(DatabaseAdapter):
|
|
1577
1603
|
if not fetch_size:
|
1578
1604
|
raise ValueError("fetch_size required for MANY mode")
|
1579
1605
|
rows = await cursor.fetchmany(fetch_size)
|
1580
|
-
|
1606
|
+
result = [self._convert_row(dict(row)) for row in rows]
|
1607
|
+
else:
|
1608
|
+
result = []
|
1581
1609
|
|
1582
|
-
|
1610
|
+
# Check if this was an INSERT and capture lastrowid for SQLite
|
1611
|
+
if query.strip().upper().startswith("INSERT") and (
|
1612
|
+
not result or result == []
|
1613
|
+
):
|
1614
|
+
# For INSERT without RETURNING, capture lastrowid
|
1615
|
+
lastrowid = (
|
1616
|
+
cursor.lastrowid if hasattr(cursor, "lastrowid") else None
|
1617
|
+
)
|
1618
|
+
if lastrowid is not None:
|
1619
|
+
await db.commit() # Commit before returning
|
1620
|
+
return {"lastrowid": lastrowid}
|
1621
|
+
|
1622
|
+
await db.commit()
|
1623
|
+
return result
|
1583
1624
|
|
1584
1625
|
async def execute_many(
|
1585
1626
|
self,
|
@@ -3421,28 +3462,37 @@ class AsyncSQLDatabaseNode(AsyncNode):
|
|
3421
3462
|
parameter_types=parameter_types,
|
3422
3463
|
)
|
3423
3464
|
|
3424
|
-
#
|
3425
|
-
result
|
3465
|
+
# Check for special SQLite lastrowid result
|
3466
|
+
if isinstance(result, dict) and "lastrowid" in result:
|
3467
|
+
# This is a special SQLite INSERT result
|
3468
|
+
formatted_data = result # Keep as-is
|
3469
|
+
row_count = 1 # One row was inserted
|
3470
|
+
else:
|
3471
|
+
# Ensure all data is JSON-serializable (safety net for adapter inconsistencies)
|
3472
|
+
result = self._ensure_serializable(result)
|
3426
3473
|
|
3427
|
-
|
3428
|
-
|
3474
|
+
# Format results based on requested format
|
3475
|
+
formatted_data = self._format_results(result, result_format)
|
3476
|
+
row_count = None # Will be calculated below
|
3429
3477
|
|
3430
3478
|
# For DataFrame, we need special handling for row count
|
3431
|
-
row_count
|
3432
|
-
|
3433
|
-
|
3434
|
-
|
3435
|
-
|
3436
|
-
|
3479
|
+
if row_count is None: # Only calculate if not already set
|
3480
|
+
if result_format == "dataframe":
|
3481
|
+
try:
|
3482
|
+
row_count = len(formatted_data)
|
3483
|
+
except:
|
3484
|
+
# If pandas isn't available, formatted_data is still a list
|
3485
|
+
row_count = (
|
3486
|
+
len(result)
|
3487
|
+
if isinstance(result, list)
|
3488
|
+
else (1 if result else 0)
|
3489
|
+
)
|
3490
|
+
else:
|
3437
3491
|
row_count = (
|
3438
3492
|
len(result)
|
3439
3493
|
if isinstance(result, list)
|
3440
3494
|
else (1 if result else 0)
|
3441
3495
|
)
|
3442
|
-
else:
|
3443
|
-
row_count = (
|
3444
|
-
len(result) if isinstance(result, list) else (1 if result else 0)
|
3445
|
-
)
|
3446
3496
|
|
3447
3497
|
# Extract column names if available
|
3448
3498
|
columns = []
|
@@ -4677,13 +4727,30 @@ class AsyncSQLDatabaseNode(AsyncNode):
|
|
4677
4727
|
self._adapter = None
|
4678
4728
|
|
4679
4729
|
def __del__(self):
|
4680
|
-
"""Ensure connections are closed."""
|
4730
|
+
"""Ensure connections are closed safely."""
|
4681
4731
|
if self._adapter and self._connected:
|
4682
|
-
#
|
4732
|
+
# Try to schedule cleanup, but be resilient to event loop issues
|
4683
4733
|
try:
|
4684
|
-
|
4685
|
-
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4734
|
+
import asyncio
|
4735
|
+
|
4736
|
+
# Check if there's a running event loop that's not closed
|
4737
|
+
try:
|
4738
|
+
loop = asyncio.get_running_loop()
|
4739
|
+
if loop and not loop.is_closed():
|
4740
|
+
# Create cleanup task only if loop is healthy
|
4741
|
+
try:
|
4742
|
+
loop.create_task(self.cleanup())
|
4743
|
+
except RuntimeError as e:
|
4744
|
+
# Loop might be closing, ignore gracefully
|
4745
|
+
logger.debug(f"Could not schedule cleanup task: {e}")
|
4746
|
+
else:
|
4747
|
+
logger.debug("Event loop is closed, skipping async cleanup")
|
4748
|
+
except RuntimeError:
|
4749
|
+
# No running event loop - this is normal during shutdown
|
4750
|
+
logger.debug(
|
4751
|
+
"No running event loop for cleanup, connections will be cleaned by GC"
|
4752
|
+
)
|
4753
|
+
except Exception as e:
|
4754
|
+
# Complete fallback - any unexpected error should not crash __del__
|
4755
|
+
logger.debug(f"Error during connection cleanup: {e}")
|
4689
4756
|
pass
|
kailash/runtime/local.py
CHANGED
@@ -2333,7 +2333,10 @@ class LocalRuntime:
|
|
2333
2333
|
else:
|
2334
2334
|
# Standard node execution (backward compatibility)
|
2335
2335
|
try:
|
2336
|
-
if hasattr(node, "
|
2336
|
+
if hasattr(node, "execute_async"):
|
2337
|
+
# For AsyncNode and its subclasses, use execute_async which handles event loop properly
|
2338
|
+
node_result = await node.execute_async(**inputs)
|
2339
|
+
elif hasattr(node, "async_run"):
|
2337
2340
|
node_result = await node.async_run(**inputs)
|
2338
2341
|
else:
|
2339
2342
|
node_result = node.execute(**inputs)
|
@@ -93,7 +93,7 @@ kailash/mcp_server/oauth.py,sha256=GFC2O2ueiTTI6V-91Huevhc3K8CxrHe22knuHfuCTqY,5
|
|
93
93
|
kailash/mcp_server/protocol.py,sha256=NIdEwJT21JT9ItajXniPNvCbZtTbpqyOC_ZezqsguGE,35694
|
94
94
|
kailash/mcp_server/registry_integration.py,sha256=B8CSLq_O1ea3cXrbVjC3bB_OFgHIP-KS9dk77mNM02I,19791
|
95
95
|
kailash/mcp_server/server.py,sha256=yFp1F4QQl6gkTY_9JJWmiMiwfT-zACLJLubz-NR5sCw,108675
|
96
|
-
kailash/mcp_server/subscriptions.py,sha256=
|
96
|
+
kailash/mcp_server/subscriptions.py,sha256=UK0Ssjab-lHJ16DFPi6lmvLh5xMYNRZia0DgYb6aQ60,58586
|
97
97
|
kailash/mcp_server/transports.py,sha256=fBa7CTVYTDb0ZbBQTsZ2d8rKvcVuqBIteczq8eqarr4,49919
|
98
98
|
kailash/mcp_server/servers/ai_registry.py,sha256=IdF_keUuJlMsvjLjSAykxxbm46K4qA7eCj7T-lYSrzk,10007
|
99
99
|
kailash/mcp_server/utils/__init__.py,sha256=R20N-iiKXUPxc9MOh6vPO1vIfkPmwhEQ5KNFgGd4xSs,771
|
@@ -220,7 +220,7 @@ kailash/nodes/compliance/data_retention.py,sha256=90bH_eGwlcDzUdklAJeXQM-RcuLUGQ
|
|
220
220
|
kailash/nodes/compliance/gdpr.py,sha256=ZMoHZjAo4QtGwtFCzGMrAUBFV3TbZOnJ5DZGZS87Bas,70548
|
221
221
|
kailash/nodes/data/__init__.py,sha256=f0h4ysvXxlyFcNJLvDyXrgJ0ixwDF1cS0pJ2QNPakhg,5213
|
222
222
|
kailash/nodes/data/async_connection.py,sha256=wfArHs9svU48bxGZIiixSV2YVn9cukNgEjagwTRu6J4,17250
|
223
|
-
kailash/nodes/data/async_sql.py,sha256=
|
223
|
+
kailash/nodes/data/async_sql.py,sha256=9C-XRTDrzpVwFRrI13ym539UajT0Qgh9jmIjisDPi28,188864
|
224
224
|
kailash/nodes/data/async_vector.py,sha256=HtwQLO25IXu8Vq80qzU8rMkUAKPQ2qM0x8YxjXHlygU,21005
|
225
225
|
kailash/nodes/data/bulk_operations.py,sha256=WVopmosVkIlweFxVt3boLdCPc93EqpYyQ1Ez9mCIt0c,34453
|
226
226
|
kailash/nodes/data/directory.py,sha256=fbfLqD_ijRubk-4xew3604QntPsyDxqaF4k6TpfyjDg,9923
|
@@ -341,7 +341,7 @@ kailash/runtime/async_local.py,sha256=sYNggSU0R-oo8cCvU5ayodDBqASzUhxu994ZvZxDSC
|
|
341
341
|
kailash/runtime/compatibility_reporter.py,sha256=TOQD0ODnJdsxEPyNSYOV_zQxu60X_yvHeu26seFOMEA,19807
|
342
342
|
kailash/runtime/docker.py,sha256=sZknVl1PCGfAZeyc0-exTuKlllSyjYlFIgJoiB3CRNs,23500
|
343
343
|
kailash/runtime/hierarchical_switch_executor.py,sha256=k6aPGbpf6z2m6dTbHrEyuDR8ZCvOqUanBGYp70arQn0,20782
|
344
|
-
kailash/runtime/local.py,sha256=
|
344
|
+
kailash/runtime/local.py,sha256=nIQRWUwSHVg2Daafq_JggBLf-zTDBaGMcwObBzVI0po,201389
|
345
345
|
kailash/runtime/parallel.py,sha256=-M9VVG36RxnrrmdbcBe9IjQWb58tAEEo76RQQ2uIXaE,21084
|
346
346
|
kailash/runtime/parallel_cyclic.py,sha256=yANZHnePjhCPuCFbq3lFQA1K6jbCv5Of5-vIKbCsmZk,19863
|
347
347
|
kailash/runtime/parameter_injection.py,sha256=kG4GhmarsRr5t3VDFbc2G1HSbsZJg6UmienHCE2Ru7o,14852
|
@@ -424,10 +424,10 @@ kailash/workflow/templates.py,sha256=XQMAKZXC2dlxgMMQhSEOWAF3hIbe9JJt9j_THchhAm8
|
|
424
424
|
kailash/workflow/type_inference.py,sha256=i1F7Yd_Z3elTXrthsLpqGbOnQBIVVVEjhRpI0HrIjd0,24492
|
425
425
|
kailash/workflow/validation.py,sha256=LdbIPQSokCqSLfWTBhJR82pa_0va44pcVu9dpEM4rvY,45177
|
426
426
|
kailash/workflow/visualization.py,sha256=nHBW-Ai8QBMZtn2Nf3EE1_aiMGi9S6Ui_BfpA5KbJPU,23187
|
427
|
-
kailash-0.9.
|
428
|
-
kailash-0.9.
|
429
|
-
kailash-0.9.
|
430
|
-
kailash-0.9.
|
431
|
-
kailash-0.9.
|
432
|
-
kailash-0.9.
|
433
|
-
kailash-0.9.
|
427
|
+
kailash-0.9.19.dist-info/licenses/LICENSE,sha256=9GYZHXVUmx6FdFRNzOeE_w7a_aEGeYbqTVmFtJlrbGk,13438
|
428
|
+
kailash-0.9.19.dist-info/licenses/NOTICE,sha256=9ssIK4LcHSTFqriXGdteMpBPTS1rSLlYtjppZ_bsjZ0,723
|
429
|
+
kailash-0.9.19.dist-info/METADATA,sha256=RY2liVVkhKdErnyayfo4_vH2OyMVKgvtvimhAT7JWvA,23528
|
430
|
+
kailash-0.9.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
431
|
+
kailash-0.9.19.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
|
432
|
+
kailash-0.9.19.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
|
433
|
+
kailash-0.9.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|