kailash 0.9.20__tar.gz → 0.9.22__tar.gz
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-0.9.20/src/kailash.egg-info → kailash-0.9.22}/PKG-INFO +10 -3
- {kailash-0.9.20 → kailash-0.9.22}/README.md +9 -2
- {kailash-0.9.20 → kailash-0.9.22}/pyproject.toml +1 -1
- {kailash-0.9.20 → kailash-0.9.22}/setup.py +1 -1
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/__init__.py +1 -1
- kailash-0.9.22/src/kailash/api/tests/test_workflow_api_404.py +202 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/workflow_api.py +33 -1
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/base.py +34 -5
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/code/python.py +10 -4
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/async_sql.py +76 -10
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/security.py +63 -17
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/graph.py +5 -5
- {kailash-0.9.20 → kailash-0.9.22/src/kailash.egg-info}/PKG-INFO +10 -3
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/SOURCES.txt +1 -0
- {kailash-0.9.20 → kailash-0.9.22}/LICENSE +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/MANIFEST.in +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/NOTICE +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/setup.cfg +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/__main__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/access_control/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/access_control/managers.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/access_control/rule_evaluators.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/access_control.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/access_control_abac.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/adapters/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/adapters/mcp_platform_adapter.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/analysis/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/analysis/conditional_branch_analyzer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/auth.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/custom_nodes.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/custom_nodes_secure.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/gateway.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/mcp_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/api/studio.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/api_channel.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/base.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/cli_channel.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/event_router.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/mcp_channel.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/channels/session.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/cli/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/cli/commands.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/cli/validate_imports.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/cli/validation_audit.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/client/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/client/enhanced_client.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/config/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/config/database_config.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/actors/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/actors/adaptive_pool_controller.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/actors/connection_actor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/actors/supervisor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/ml/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/ml/query_patterns.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/monitoring/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/monitoring/connection_metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/optimization/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/resilience/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/resilience/bulkhead.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/resilience/circuit_breaker.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/core/resilience/health_monitor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/database/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/database/execution_pipeline.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/compliance.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/consistency.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/coordination/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/coordination/global_ordering.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/coordination/leader_election.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/coordination/partition_detector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/coordination/raft.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/discovery.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/location.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/migration/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/migration/edge_migration_service.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/migration/edge_migrator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/monitoring/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/monitoring/edge_monitor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/prediction/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/prediction/predictive_warmer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/cloud_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/cost_optimizer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/docker_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/kubernetes_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/platform_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/predictive_scaler.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/resource_analyzer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/edge/resource/resource_pools.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/gateway/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/gateway/api.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/gateway/enhanced_gateway.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/gateway/resource_resolver.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/gateway/security.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/integrations/dataflow_edge.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/manifest.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/advanced_features.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/ai_registry_server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/auth.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/client.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/client_new.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/discovery.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/errors.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/oauth.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/protocol.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/registry_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/servers/ai_registry.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/subscriptions.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/transports.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/utils/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/utils/cache.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/utils/config.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/utils/formatters.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/mcp_server/utils/metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/access_control.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/auth_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/exceptions.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/jwt_auth.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/auth/utils.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/communication/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/communication/ai_chat.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/communication/api_gateway.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/communication/events.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/communication/realtime.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/core/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/core/agent_ui.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/core/schema.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/core/workflows.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/base.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/base_models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/enums.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/migrations.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/repositories.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/database/session_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/checkpoint_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/deduplicator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/durable_gateway.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/durable_request.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/event_store.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/gateway/storage_backends.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/mcp/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/mcp/client_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/middleware/mcp/enhanced_server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/cli.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/compatibility_checker.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/configuration_validator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/documentation_generator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/examples/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/examples/complete_migration_example.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/migration_assistant.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/performance_comparator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/regression_detector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/tests/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/tests/test_compatibility_checker.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/tests/test_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/tests/test_migration_assistant.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/migration/tests/test_performance_comparator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/monitoring/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/monitoring/alerts.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/monitoring/asyncsql_metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/monitoring/metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/__init___original.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/audit_log.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/permission_check.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/role_management.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/schema.sql +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/schema_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/security_event.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/tenant_isolation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/transaction_utils.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/admin/user_management.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/a2a.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/agents.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/ai_providers.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/embedding_generator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/hybrid_search.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/intelligent_agent_orchestrator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/iterative_llm_agent.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/llm_agent.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/self_organizing.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/semantic_memory.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/streaming_analytics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ai/vision_utils.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/alerts/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/alerts/base.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/alerts/discord.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/auth.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/graphql.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/http.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/monitoring.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/rate_limiting.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/rest.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/api/security.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/directory_integration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/enterprise_auth_provider.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/mfa.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/risk_assessment.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/session_management.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/auth/sso.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/base_async.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/base_cycle_aware.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/base_with_acl.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/cache/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/cache/cache.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/cache/cache_invalidation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/cache/redis_pool_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/code/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/code/async_python.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/compliance/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/compliance/data_retention.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/compliance/gdpr.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/async_connection.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/async_vector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/bulk_operations.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/directory.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/event_generation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/file_discovery.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/optimistic_locking.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/query_builder.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/query_cache.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/query_pipeline.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/query_router.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/readers.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/redis.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/retrieval.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/sharepoint_graph.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/sources.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/sql.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/streaming.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/vector_db.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/workflow_connection_pool.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/data/writers.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/base.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/cloud_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/coordination.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/docker_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/edge_data.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/edge_migration_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/edge_monitoring_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/edge_state.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/edge_warming_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/kubernetes_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/platform_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/resource_analyzer_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/resource_optimizer_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/edge/resource_scaler_node.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/audit_logger.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/batch_processor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/data_lineage.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/mcp_executor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/service_discovery.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/enterprise/tenant_assignment.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/governance.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/async_operations.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/convergence.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/intelligent_merge.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/loop.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/operations.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/logic/workflow.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/mixins/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/mixins/event_emitter.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/mixins/mcp.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/mixins/security.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/mixins.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/connection_dashboard.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/deadlock_detector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/health_check.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/log_processor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/metrics_collector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/performance_anomaly.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/performance_benchmark.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/race_condition_detector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/transaction_metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/monitoring/transaction_monitor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/ports.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/advanced.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/agentic.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/conversational.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/evaluation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/federated.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/graph.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/multimodal.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/optimized.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/privacy.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/query_processing.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/realtime.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/registry.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/router.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/similarity.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/strategies.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/rag/workflows.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/abac_evaluator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/audit_log.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/behavior_analysis.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/credential_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/rotating_credentials.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/security_event.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/security/threat_detection.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/system/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/system/command_parser.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/testing/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/testing/credential_testing.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/distributed_transaction_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/saga_coordinator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/saga_state_storage.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/saga_step.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/transaction_context.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transaction/two_phase_commit.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transform/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transform/chunkers.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transform/formatters.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/transform/processors.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/validation/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/validation/test_executor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/validation/validation_nodes.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/nodes/validation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/planning/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/planning/dynamic_execution_planner.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/resources/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/resources/factory.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/resources/health.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/resources/reference.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/resources/registry.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/access_controlled.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/async_local.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/compatibility_reporter.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/docker.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/hierarchical_switch_executor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/local.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/monitoring/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/monitoring/runtime_monitor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/parallel.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/parallel_cyclic.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/parameter_injection.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/parameter_injector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/performance_monitor.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/resource_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/runner.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/secret_provider.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/testing.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/connection_context.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/enhanced_error_formatter.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/error_categorizer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/import_validator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/metrics.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/performance.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/runtime/validation/suggestion_engine.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/sdk_exceptions.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/servers/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/servers/durable_workflow_server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/servers/enterprise_workflow_server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/servers/gateway.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/servers/workflow_server.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/testing/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/testing/async_test_case.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/testing/async_utils.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/testing/fixtures.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/testing/mock_registry.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/metrics_collector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/storage/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/storage/base.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/storage/database.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/tracking/storage/filesystem.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/circular_dependency_detector.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/data_paths.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/data_validation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/export.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/migrations/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/migrations/generator.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/migrations/models.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/migrations/runner.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/resource_manager.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/secure_logging.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/utils/templates.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/visualization/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/visualization/api.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/visualization/dashboard.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/visualization/performance.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/visualization/reports.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/__init__.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/async_builder.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/async_patterns.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/builder.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/contracts.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/convergence.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_analyzer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_builder.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_config.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_debugger.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_exceptions.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_profiler.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cycle_state.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/cyclic_runner.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/edge_infrastructure.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/input_handling.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/mermaid_visualizer.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/migration.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/mock_registry.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/resilience.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/runner.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/safety.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/state.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/templates.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/type_inference.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/validation.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash/workflow/visualization.py +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/dependency_links.txt +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/entry_points.txt +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/not-zip-safe +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/requires.txt +0 -0
- {kailash-0.9.20 → kailash-0.9.22}/src/kailash.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kailash
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.22
|
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
|
@@ -122,11 +122,18 @@ Dynamic: requires-python
|
|
122
122
|
|
123
123
|
---
|
124
124
|
|
125
|
-
## 🔥 Latest Release: v0.9.
|
125
|
+
## 🔥 Latest Release: v0.9.21 (October 8, 2025)
|
126
126
|
|
127
|
-
**
|
127
|
+
**AsyncSQL Event Loop Isolation Fix**
|
128
128
|
|
129
129
|
### 🐛 Critical Bug Fixes
|
130
|
+
- **Event Loop Isolation**: Fixed "Event loop is closed" errors in AsyncSQLDatabaseNode
|
131
|
+
- Automatic connection pool isolation per event loop
|
132
|
+
- Prevents pool sharing across different event loops (FastAPI, sequential workflows)
|
133
|
+
- Backward compatible - no code changes required
|
134
|
+
- <5% performance overhead
|
135
|
+
|
136
|
+
### Previous Release: v0.9.20 (October 6, 2025)
|
130
137
|
- **Mock Provider Bypass**: Removed hardcoded `if provider == "mock"` logic from LLMAgentNode
|
131
138
|
- **Tool Execution Flow**: Unified provider response generation for all providers
|
132
139
|
- **Provider Registry**: All providers now use consistent registry path
|
@@ -22,11 +22,18 @@
|
|
22
22
|
|
23
23
|
---
|
24
24
|
|
25
|
-
## 🔥 Latest Release: v0.9.
|
25
|
+
## 🔥 Latest Release: v0.9.21 (October 8, 2025)
|
26
26
|
|
27
|
-
**
|
27
|
+
**AsyncSQL Event Loop Isolation Fix**
|
28
28
|
|
29
29
|
### 🐛 Critical Bug Fixes
|
30
|
+
- **Event Loop Isolation**: Fixed "Event loop is closed" errors in AsyncSQLDatabaseNode
|
31
|
+
- Automatic connection pool isolation per event loop
|
32
|
+
- Prevents pool sharing across different event loops (FastAPI, sequential workflows)
|
33
|
+
- Backward compatible - no code changes required
|
34
|
+
- <5% performance overhead
|
35
|
+
|
36
|
+
### Previous Release: v0.9.20 (October 6, 2025)
|
30
37
|
- **Mock Provider Bypass**: Removed hardcoded `if provider == "mock"` logic from LLMAgentNode
|
31
38
|
- **Tool Execution Flow**: Unified provider response generation for all providers
|
32
39
|
- **Provider Registry**: All providers now use consistent registry path
|
@@ -13,7 +13,7 @@ with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
|
|
13
13
|
# Package configuration
|
14
14
|
setup(
|
15
15
|
name="kailash",
|
16
|
-
version="0.9.
|
16
|
+
version="0.9.22",
|
17
17
|
author="Integrum",
|
18
18
|
author_email="info@integrum.com",
|
19
19
|
description="Python SDK for the Kailash container-node architecture",
|
@@ -0,0 +1,202 @@
|
|
1
|
+
"""
|
2
|
+
Tests for WorkflowAPI Custom 404 Handler
|
3
|
+
|
4
|
+
Tests that WorkflowAPI provides helpful 404 error messages
|
5
|
+
with available endpoints when wrong paths are accessed.
|
6
|
+
|
7
|
+
These tests follow TDD: They will FAIL initially until the 404 handler is implemented.
|
8
|
+
This is expected behavior - we write tests FIRST, then implement.
|
9
|
+
"""
|
10
|
+
|
11
|
+
import pytest
|
12
|
+
from fastapi.testclient import TestClient
|
13
|
+
|
14
|
+
from kailash.api.workflow_api import WorkflowAPI
|
15
|
+
from kailash.workflow.builder import WorkflowBuilder
|
16
|
+
|
17
|
+
|
18
|
+
@pytest.fixture
|
19
|
+
def simple_workflow_api():
|
20
|
+
"""Simple WorkflowAPI for testing"""
|
21
|
+
workflow = WorkflowBuilder()
|
22
|
+
workflow.add_node(
|
23
|
+
"PythonCodeNode", "test", {"code": "result = {'message': 'test'}"}
|
24
|
+
)
|
25
|
+
api = WorkflowAPI(workflow.build())
|
26
|
+
return api
|
27
|
+
|
28
|
+
|
29
|
+
def test_404_returns_helpful_json(simple_workflow_api):
|
30
|
+
"""Test that 404 errors return helpful JSON with available endpoints."""
|
31
|
+
client = TestClient(simple_workflow_api.app)
|
32
|
+
|
33
|
+
# Try to access non-existent path
|
34
|
+
response = client.get("/nonexistent")
|
35
|
+
|
36
|
+
# Should return 404
|
37
|
+
assert response.status_code == 404
|
38
|
+
|
39
|
+
# Should be JSON
|
40
|
+
assert response.headers["content-type"] == "application/json"
|
41
|
+
|
42
|
+
# Should have helpful error message
|
43
|
+
data = response.json()
|
44
|
+
assert "error" in data or "detail" in data, "404 response should have error field"
|
45
|
+
|
46
|
+
# Should mention endpoints or provide helpful info
|
47
|
+
response_str = str(data).lower()
|
48
|
+
has_endpoint_info = (
|
49
|
+
"endpoint" in response_str
|
50
|
+
or "available" in response_str
|
51
|
+
or "path" in response_str
|
52
|
+
)
|
53
|
+
assert has_endpoint_info, "404 response should mention endpoints or paths"
|
54
|
+
|
55
|
+
|
56
|
+
def test_404_lists_available_endpoints(simple_workflow_api):
|
57
|
+
"""Test that 404 response includes list of available endpoints."""
|
58
|
+
client = TestClient(simple_workflow_api.app)
|
59
|
+
|
60
|
+
# Try to access non-existent path
|
61
|
+
response = client.get("/invalid_path")
|
62
|
+
|
63
|
+
assert response.status_code == 404
|
64
|
+
|
65
|
+
data = response.json()
|
66
|
+
|
67
|
+
# Should have some reference to available endpoints
|
68
|
+
response_str = str(data)
|
69
|
+
endpoints = []
|
70
|
+
|
71
|
+
# Check if standard endpoints are mentioned
|
72
|
+
if "/execute" in response_str:
|
73
|
+
endpoints.append("/execute")
|
74
|
+
if "/workflow/info" in response_str or "/info" in response_str:
|
75
|
+
endpoints.append("/workflow/info")
|
76
|
+
if "/health" in response_str:
|
77
|
+
endpoints.append("/health")
|
78
|
+
|
79
|
+
# Should mention at least 2 of the 3 standard endpoints
|
80
|
+
assert (
|
81
|
+
len(endpoints) >= 2
|
82
|
+
), f"404 response should mention available endpoints. Found: {endpoints}"
|
83
|
+
|
84
|
+
|
85
|
+
def test_404_provides_helpful_hint(simple_workflow_api):
|
86
|
+
"""Test that 404 response provides actionable hint."""
|
87
|
+
client = TestClient(simple_workflow_api.app)
|
88
|
+
|
89
|
+
# Try wrong path
|
90
|
+
response = client.get("/wrong")
|
91
|
+
|
92
|
+
assert response.status_code == 404
|
93
|
+
|
94
|
+
data = response.json()
|
95
|
+
response_str = str(data).lower()
|
96
|
+
|
97
|
+
# Should have hint, message, or suggestion
|
98
|
+
has_helpful_content = (
|
99
|
+
"hint" in response_str
|
100
|
+
or "try" in response_str
|
101
|
+
or "use" in response_str
|
102
|
+
or "most common" in response_str
|
103
|
+
or "suggestion" in response_str
|
104
|
+
or "did you mean" in response_str
|
105
|
+
)
|
106
|
+
|
107
|
+
assert (
|
108
|
+
has_helpful_content
|
109
|
+
), "404 response should provide helpful hints or suggestions"
|
110
|
+
|
111
|
+
|
112
|
+
def test_404_includes_documentation_link(simple_workflow_api):
|
113
|
+
"""Test that 404 response includes link to documentation."""
|
114
|
+
client = TestClient(simple_workflow_api.app)
|
115
|
+
|
116
|
+
response = client.get("/missing")
|
117
|
+
|
118
|
+
assert response.status_code == 404
|
119
|
+
data = response.json()
|
120
|
+
|
121
|
+
# Should have docs link or path
|
122
|
+
response_str = str(data).lower()
|
123
|
+
has_docs_reference = (
|
124
|
+
"docs" in response_str
|
125
|
+
or "documentation" in response_str
|
126
|
+
or "/docs" in response_str
|
127
|
+
)
|
128
|
+
assert has_docs_reference, "404 response should reference documentation"
|
129
|
+
|
130
|
+
|
131
|
+
def test_404_handler_for_root_path(simple_workflow_api):
|
132
|
+
"""Test 404 handler when accessing root path with wrong method."""
|
133
|
+
client = TestClient(simple_workflow_api.app)
|
134
|
+
|
135
|
+
# Try to GET root (only POST is typically defined for execute)
|
136
|
+
response = client.get("/")
|
137
|
+
|
138
|
+
# Could be 404 or 405 Method Not Allowed
|
139
|
+
assert response.status_code in [
|
140
|
+
404,
|
141
|
+
405,
|
142
|
+
], f"Expected 404 or 405, got {response.status_code}"
|
143
|
+
|
144
|
+
# If 404, should have helpful info
|
145
|
+
if response.status_code == 404:
|
146
|
+
data = response.json()
|
147
|
+
response_str = str(data).lower()
|
148
|
+
|
149
|
+
# Should mention execute or available methods
|
150
|
+
has_helpful_info = (
|
151
|
+
"execute" in response_str
|
152
|
+
or "post" in response_str
|
153
|
+
or "endpoint" in response_str
|
154
|
+
)
|
155
|
+
assert (
|
156
|
+
has_helpful_info
|
157
|
+
), "404 on root should mention execute endpoint or POST method"
|
158
|
+
|
159
|
+
|
160
|
+
def test_404_handler_preserves_fastapi_routes(simple_workflow_api):
|
161
|
+
"""Test that valid routes still work after adding 404 handler."""
|
162
|
+
client = TestClient(simple_workflow_api.app)
|
163
|
+
|
164
|
+
# Valid route should work
|
165
|
+
response = client.get("/health")
|
166
|
+
|
167
|
+
# Health endpoint should return 200
|
168
|
+
assert (
|
169
|
+
response.status_code == 200
|
170
|
+
), "Valid routes should still work after adding 404 handler"
|
171
|
+
|
172
|
+
# Should return JSON
|
173
|
+
assert response.headers["content-type"] == "application/json"
|
174
|
+
|
175
|
+
|
176
|
+
def test_404_response_format_consistency(simple_workflow_api):
|
177
|
+
"""Test that 404 responses have consistent format."""
|
178
|
+
client = TestClient(simple_workflow_api.app)
|
179
|
+
|
180
|
+
# Try multiple invalid paths
|
181
|
+
paths = ["/invalid1", "/wrong/path", "/nonexistent/endpoint"]
|
182
|
+
|
183
|
+
for path in paths:
|
184
|
+
response = client.get(path)
|
185
|
+
assert response.status_code == 404
|
186
|
+
|
187
|
+
# All should return JSON
|
188
|
+
assert (
|
189
|
+
response.headers["content-type"] == "application/json"
|
190
|
+
), f"404 response for {path} should be JSON"
|
191
|
+
|
192
|
+
# All should have error structure
|
193
|
+
data = response.json()
|
194
|
+
assert isinstance(
|
195
|
+
data, dict
|
196
|
+
), f"404 response for {path} should be a JSON object"
|
197
|
+
|
198
|
+
# Should have at least one error-related field
|
199
|
+
has_error_field = any(key in data for key in ["error", "detail", "message"])
|
200
|
+
assert (
|
201
|
+
has_error_field
|
202
|
+
), f"404 response for {path} should have error/detail/message field"
|
@@ -12,7 +12,7 @@ from typing import Any
|
|
12
12
|
|
13
13
|
import uvicorn
|
14
14
|
from fastapi import BackgroundTasks, FastAPI, HTTPException, Request
|
15
|
-
from fastapi.responses import StreamingResponse
|
15
|
+
from fastapi.responses import JSONResponse, StreamingResponse
|
16
16
|
from pydantic import BaseModel, Field
|
17
17
|
|
18
18
|
from kailash.runtime.local import LocalRuntime
|
@@ -129,6 +129,38 @@ class WorkflowAPI:
|
|
129
129
|
def _setup_routes(self):
|
130
130
|
"""Setup API routes dynamically based on workflow."""
|
131
131
|
|
132
|
+
# Custom 404 handler for helpful error messages
|
133
|
+
@self.app.exception_handler(404)
|
134
|
+
async def custom_404_handler(request: Request, exc):
|
135
|
+
"""Provide helpful 404 error with available endpoints."""
|
136
|
+
return JSONResponse(
|
137
|
+
status_code=404,
|
138
|
+
content={
|
139
|
+
"error": "Endpoint not found",
|
140
|
+
"path": request.url.path,
|
141
|
+
"message": "The requested endpoint does not exist for this workflow.",
|
142
|
+
"available_endpoints": [
|
143
|
+
{
|
144
|
+
"method": "POST",
|
145
|
+
"path": "/execute",
|
146
|
+
"description": "Execute the workflow with input parameters",
|
147
|
+
},
|
148
|
+
{
|
149
|
+
"method": "GET",
|
150
|
+
"path": "/workflow/info",
|
151
|
+
"description": "Get workflow metadata and structure",
|
152
|
+
},
|
153
|
+
{
|
154
|
+
"method": "GET",
|
155
|
+
"path": "/health",
|
156
|
+
"description": "Check workflow API health status",
|
157
|
+
},
|
158
|
+
],
|
159
|
+
"hint": "Most common: POST to /execute endpoint with JSON body containing 'inputs' field",
|
160
|
+
"documentation": "/docs",
|
161
|
+
},
|
162
|
+
)
|
163
|
+
|
132
164
|
# Root execution endpoint (convenience for direct workflow execution)
|
133
165
|
@self.app.post("/")
|
134
166
|
async def execute_workflow_root(
|
@@ -202,11 +202,13 @@ class Node(ABC):
|
|
202
202
|
- Validates parameters are correctly specified
|
203
203
|
"""
|
204
204
|
try:
|
205
|
-
|
205
|
+
# Use _node_id for internal node identifier (namespace separation)
|
206
|
+
# This prevents collision with user's 'id' parameter
|
207
|
+
self._node_id = kwargs.get("_node_id", self.__class__.__name__)
|
206
208
|
self.metadata = kwargs.get(
|
207
209
|
"metadata",
|
208
210
|
NodeMetadata(
|
209
|
-
id=self.id
|
211
|
+
id=self._node_id, # NodeMetadata still uses 'id' internally
|
210
212
|
name=kwargs.get("name", self.__class__.__name__),
|
211
213
|
description=kwargs.get("description", self.__doc__ or ""),
|
212
214
|
version=kwargs.get("version", "1.0.0"),
|
@@ -214,7 +216,7 @@ class Node(ABC):
|
|
214
216
|
tags=kwargs.get("tags", set()),
|
215
217
|
),
|
216
218
|
)
|
217
|
-
self.logger = logging.getLogger(f"kailash.nodes.{self.
|
219
|
+
self.logger = logging.getLogger(f"kailash.nodes.{self._node_id}")
|
218
220
|
|
219
221
|
# Filter out internal fields from config with comprehensive parameter handling
|
220
222
|
# Get parameter definitions once and cache for both filtering and validation
|
@@ -232,11 +234,12 @@ class Node(ABC):
|
|
232
234
|
|
233
235
|
# Comprehensive parameter filtering: handle ALL potential conflicts
|
234
236
|
# Fields that are always internal (never user parameters)
|
235
|
-
always_internal = {"metadata"}
|
237
|
+
always_internal = {"metadata", "_node_id"}
|
236
238
|
|
237
239
|
# Fields that can be either internal or user parameters
|
240
|
+
# Note: 'id' removed from this list - users can now use 'id' freely
|
241
|
+
# since node identifier is now '_node_id'
|
238
242
|
potentially_user_params = {
|
239
|
-
"id",
|
240
243
|
"name",
|
241
244
|
"description",
|
242
245
|
"version",
|
@@ -344,6 +347,32 @@ class Node(ABC):
|
|
344
347
|
self._workflow_context = {}
|
345
348
|
self._workflow_context[key] = value
|
346
349
|
|
350
|
+
@property
|
351
|
+
def id(self) -> str:
|
352
|
+
"""
|
353
|
+
Backward compatibility property for node identifier.
|
354
|
+
|
355
|
+
Returns the node's identifier (_node_id). This property maintains
|
356
|
+
backward compatibility for code that accesses node.id.
|
357
|
+
|
358
|
+
The internal identifier is now _node_id to prevent namespace collision
|
359
|
+
with user's 'id' parameter.
|
360
|
+
"""
|
361
|
+
return self._node_id
|
362
|
+
|
363
|
+
@id.setter
|
364
|
+
def id(self, value: str):
|
365
|
+
"""
|
366
|
+
Setter for backward compatibility with code that sets node.id.
|
367
|
+
|
368
|
+
This allows graph.py and other code to set the node identifier
|
369
|
+
while internally using _node_id for namespace separation.
|
370
|
+
|
371
|
+
Args:
|
372
|
+
value: The node identifier to set
|
373
|
+
"""
|
374
|
+
self._node_id = value
|
375
|
+
|
347
376
|
@abstractmethod
|
348
377
|
def get_parameters(self) -> dict[str, NodeParameter]:
|
349
378
|
"""Define the parameters this node accepts.
|
@@ -412,8 +412,11 @@ class CodeExecutor:
|
|
412
412
|
# Check code safety first
|
413
413
|
is_safe, violations, imports_found = self.check_code_safety(code)
|
414
414
|
|
415
|
-
# Sanitize inputs
|
416
|
-
|
415
|
+
# Sanitize inputs with python_exec context
|
416
|
+
# Python code execution via exec() does not need shell metacharacter sanitization
|
417
|
+
sanitized_inputs = validate_node_parameters(
|
418
|
+
inputs, self.security_config, context="python_exec"
|
419
|
+
)
|
417
420
|
|
418
421
|
# Create isolated namespace
|
419
422
|
import builtins
|
@@ -572,8 +575,11 @@ class CodeExecutor:
|
|
572
575
|
Raises:
|
573
576
|
NodeExecutionError: If function execution fails
|
574
577
|
"""
|
575
|
-
# Sanitize inputs for security
|
576
|
-
|
578
|
+
# Sanitize inputs for security with python_exec context
|
579
|
+
# Python function execution does not need shell metacharacter sanitization
|
580
|
+
sanitized_inputs = validate_node_parameters(
|
581
|
+
inputs, self.security_config, context="python_exec"
|
582
|
+
)
|
577
583
|
|
578
584
|
try:
|
579
585
|
# Get function signature
|
@@ -3255,8 +3255,17 @@ class AsyncSQLDatabaseNode(AsyncNode):
|
|
3255
3255
|
|
3256
3256
|
def _generate_pool_key(self) -> str:
|
3257
3257
|
"""Generate a unique key for connection pool sharing."""
|
3258
|
-
#
|
3258
|
+
# Get event loop ID for isolation
|
3259
|
+
try:
|
3260
|
+
loop = asyncio.get_running_loop()
|
3261
|
+
loop_id = str(id(loop))
|
3262
|
+
except RuntimeError:
|
3263
|
+
# No running loop (initialization phase)
|
3264
|
+
loop_id = "no_loop"
|
3265
|
+
|
3266
|
+
# Create a unique key based on event loop and connection parameters
|
3259
3267
|
key_parts = [
|
3268
|
+
loop_id, # Event loop isolation
|
3260
3269
|
self.config.get("database_type", ""),
|
3261
3270
|
self.config.get("connection_string", "")
|
3262
3271
|
or (
|
@@ -3295,16 +3304,30 @@ class AsyncSQLDatabaseNode(AsyncNode):
|
|
3295
3304
|
):
|
3296
3305
|
|
3297
3306
|
if self._pool_key in self._shared_pools:
|
3298
|
-
#
|
3307
|
+
# Validate pool's event loop is still running before reuse
|
3299
3308
|
adapter, ref_count = self._shared_pools[self._pool_key]
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3309
|
+
|
3310
|
+
try:
|
3311
|
+
# Check if we have a running event loop
|
3312
|
+
pool_loop = asyncio.get_running_loop()
|
3313
|
+
# If we got here, loop is running - safe to reuse
|
3314
|
+
self._shared_pools[self._pool_key] = (
|
3315
|
+
adapter,
|
3316
|
+
ref_count + 1,
|
3317
|
+
)
|
3318
|
+
self._adapter = adapter
|
3319
|
+
self._connected = True
|
3320
|
+
logger.debug(
|
3321
|
+
f"Using class-level shared pool for {self.id}"
|
3322
|
+
)
|
3323
|
+
return self._adapter
|
3324
|
+
except RuntimeError:
|
3325
|
+
# Loop is closed - remove stale pool
|
3326
|
+
logger.warning(
|
3327
|
+
f"Removing stale pool for {self._pool_key} - event loop closed"
|
3328
|
+
)
|
3329
|
+
del self._shared_pools[self._pool_key]
|
3330
|
+
# Fall through to create new pool
|
3308
3331
|
|
3309
3332
|
# Create new shared pool
|
3310
3333
|
self._adapter = await self._create_adapter()
|
@@ -4000,8 +4023,51 @@ class AsyncSQLDatabaseNode(AsyncNode):
|
|
4000
4023
|
|
4001
4024
|
metrics["pools"].append(pool_info)
|
4002
4025
|
|
4026
|
+
# Clean up stale pools from closed event loops
|
4027
|
+
cleaned_pools = cls._cleanup_closed_loop_pools()
|
4028
|
+
if cleaned_pools > 0:
|
4029
|
+
metrics["cleaned_stale_pools"] = cleaned_pools
|
4030
|
+
|
4003
4031
|
return metrics
|
4004
4032
|
|
4033
|
+
@classmethod
|
4034
|
+
def _cleanup_closed_loop_pools(cls) -> int:
|
4035
|
+
"""
|
4036
|
+
Clean up pools from closed event loops.
|
4037
|
+
|
4038
|
+
Returns:
|
4039
|
+
Number of pools removed
|
4040
|
+
"""
|
4041
|
+
removed_count = 0
|
4042
|
+
keys_to_remove = []
|
4043
|
+
|
4044
|
+
for pool_key in list(cls._shared_pools.keys()):
|
4045
|
+
# Extract loop ID from pool key (first part before "|")
|
4046
|
+
parts = pool_key.split("|")
|
4047
|
+
if len(parts) > 0:
|
4048
|
+
loop_id_str = parts[0]
|
4049
|
+
|
4050
|
+
# Check if this pool's event loop is still running
|
4051
|
+
try:
|
4052
|
+
current_loop = asyncio.get_running_loop()
|
4053
|
+
current_loop_id = str(id(current_loop))
|
4054
|
+
|
4055
|
+
# If loop IDs don't match and pool is stale, mark for removal
|
4056
|
+
if loop_id_str != current_loop_id and loop_id_str != "no_loop":
|
4057
|
+
keys_to_remove.append(pool_key)
|
4058
|
+
except RuntimeError:
|
4059
|
+
# No current loop - mark old pools for removal
|
4060
|
+
if loop_id_str != "no_loop":
|
4061
|
+
keys_to_remove.append(pool_key)
|
4062
|
+
|
4063
|
+
# Remove stale pools
|
4064
|
+
for key in keys_to_remove:
|
4065
|
+
if key in cls._shared_pools:
|
4066
|
+
del cls._shared_pools[key]
|
4067
|
+
removed_count += 1
|
4068
|
+
|
4069
|
+
return removed_count
|
4070
|
+
|
4005
4071
|
@classmethod
|
4006
4072
|
async def clear_shared_pools(cls) -> None:
|
4007
4073
|
"""Clear all shared connection pools. Use with caution!"""
|