julee 0.1.4__tar.gz → 0.1.5__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.
- julee-0.1.5/PKG-INFO +103 -0
- julee-0.1.5/README.md +38 -0
- {julee-0.1.4 → julee-0.1.5}/pyproject.toml +12 -1
- {julee-0.1.4 → julee-0.1.5}/src/julee/__init__.py +1 -1
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_assembly_specifications.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_documents.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_knowledge_service_configs.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_knowledge_service_queries.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_system.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/test_workflows.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/test_app.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/test_dependencies.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/test_requests.py +2 -0
- julee-0.1.5/src/julee/contrib/polling/__init__.py +50 -0
- julee-0.1.5/src/julee/contrib/polling/apps/__init__.py +17 -0
- julee-0.1.5/src/julee/contrib/polling/apps/worker/__init__.py +17 -0
- julee-0.1.5/src/julee/contrib/polling/apps/worker/pipelines.py +288 -0
- julee-0.1.5/src/julee/contrib/polling/domain/__init__.py +15 -0
- julee-0.1.5/src/julee/contrib/polling/domain/models/__init__.py +12 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/domain/models/polling_config.py +18 -1
- julee-0.1.5/src/julee/contrib/polling/domain/services/__init__.py +12 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/domain/services/poller.py +1 -1
- julee-0.1.5/src/julee/contrib/polling/infrastructure/__init__.py +16 -0
- julee-0.1.5/src/julee/contrib/polling/infrastructure/services/__init__.py +13 -0
- julee-0.1.5/src/julee/contrib/polling/infrastructure/services/polling/__init__.py +13 -0
- julee-0.1.5/src/julee/contrib/polling/infrastructure/services/polling/http/__init__.py +13 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/infrastructure/services/polling/http/http_poller_service.py +5 -2
- julee-0.1.5/src/julee/contrib/polling/infrastructure/temporal/__init__.py +20 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/infrastructure/temporal/activities.py +1 -1
- julee-0.1.5/src/julee/contrib/polling/infrastructure/temporal/manager.py +291 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/infrastructure/temporal/proxies.py +1 -1
- julee-0.1.5/src/julee/contrib/polling/tests/unit/apps/worker/test_pipelines.py +580 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/infrastructure/services/polling/http/test_http_poller_service.py +40 -2
- julee-0.1.5/src/julee/contrib/polling/tests/unit/infrastructure/temporal/__init__.py +7 -0
- julee-0.1.5/src/julee/contrib/polling/tests/unit/infrastructure/temporal/test_manager.py +475 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly/tests/test_assembly.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/tests/test_assembly_specification.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/custom_fields/tests/test_custom_fields.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/document/tests/test_document.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/tests/test_document_policy_validation.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/tests/test_policy.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/tests/test_extract_assemble_data.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/tests/test_initialize_system_data.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/tests/test_validate_document.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/maintenance/release.py +10 -5
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/tests/test_document.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/tests/test_document_policy_validation.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/tests/test_policy.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_assembly.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_assembly_specification.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_client_protocol.py +3 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_document.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_document_policy_validation.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_knowledge_service_config.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_knowledge_service_query.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/test_policy.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/memory/test_knowledge_service.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/test_factory.py +2 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/tests/test_decorators.py +2 -0
- julee-0.1.5/src/julee.egg-info/PKG-INFO +103 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee.egg-info/SOURCES.txt +7 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee.egg-info/requires.txt +1 -0
- julee-0.1.4/PKG-INFO +0 -197
- julee-0.1.4/README.md +0 -133
- julee-0.1.4/src/julee/contrib/polling/__init__.py +0 -47
- julee-0.1.4/src/julee/contrib/polling/domain/__init__.py +0 -17
- julee-0.1.4/src/julee/contrib/polling/domain/models/__init__.py +0 -13
- julee-0.1.4/src/julee/contrib/polling/domain/services/__init__.py +0 -11
- julee-0.1.4/src/julee/contrib/polling/infrastructure/__init__.py +0 -15
- julee-0.1.4/src/julee/contrib/polling/infrastructure/services/__init__.py +0 -12
- julee-0.1.4/src/julee/contrib/polling/infrastructure/services/polling/__init__.py +0 -12
- julee-0.1.4/src/julee/contrib/polling/infrastructure/services/polling/http/__init__.py +0 -12
- julee-0.1.4/src/julee/contrib/polling/infrastructure/temporal/__init__.py +0 -20
- julee-0.1.4/src/julee.egg-info/PKG-INFO +0 -197
- {julee-0.1.4 → julee-0.1.5}/LICENSE +0 -0
- {julee-0.1.4 → julee-0.1.5}/MANIFEST.in +0 -0
- {julee-0.1.4 → julee-0.1.5}/setup.cfg +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/app.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/dependencies.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/requests.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/responses.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/assembly_specifications.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/documents.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/knowledge_service_configs.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/knowledge_service_queries.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/system.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/routers/workflows.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/services/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/services/system_initialization.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/api/tests/routers/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/infrastructure/temporal/activity_names.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/infrastructure/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/infrastructure/services/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/infrastructure/services/polling/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/contrib/polling/tests/unit/infrastructure/services/polling/http/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/accelerators.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/apps.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/config.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/epics.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/integrations.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/journeys.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/personas.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/stories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/docs/sphinx_hcd/utils.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly/assembly.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly/tests/factories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/assembly_specification.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/knowledge_service_query.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/assembly_specification/tests/factories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/custom_fields/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/custom_fields/content_stream.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/custom_fields/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/document/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/document/document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/document/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/document/tests/factories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/knowledge_service_config/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/knowledge_service_config/knowledge_service_config.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/document_policy_validation.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/policy.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/models/policy/tests/factories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/assembly.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/assembly_specification.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/base.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/document_policy_validation.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/knowledge_service_config.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/knowledge_service_query.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/repositories/policy.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/decorators.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/extract_assemble_data.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/initialize_system_data.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/domain/use_cases/validate_document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/fixtures/documents.yaml +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/fixtures/knowledge_service_configs.yaml +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/fixtures/knowledge_service_queries.yaml +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/maintenance/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/assembly.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/assembly_specification.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/base.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/document_policy_validation.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/knowledge_service_config.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/knowledge_service_query.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/policy.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/memory/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/assembly.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/assembly_specification.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/client.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/document_policy_validation.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/knowledge_service_config.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/knowledge_service_query.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/policy.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/minio/tests/fake_client.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/temporal/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/temporal/activities.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/temporal/activity_names.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/repositories/temporal/proxies.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/anthropic/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/anthropic/knowledge_service.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/factory.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/knowledge_service.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/memory/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/knowledge_service/memory/knowledge_service.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/temporal/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/temporal/activities.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/temporal/activity_names.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/services/temporal/proxies.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/domain.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/minio/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/minio/file_storage.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/client_proxies/file_storage.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/data_converter.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/minio_file_storage.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/proxies/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repos/temporal/proxies/file_storage.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/repositories.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/temporal/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/temporal/activities.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/temporal/decorators.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/tests/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/validation/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/validation/repository.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/util/validation/type_guards.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/worker.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/workflows/__init__.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/workflows/extract_assemble.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee/workflows/validate_document.py +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee.egg-info/dependency_links.txt +0 -0
- {julee-0.1.4 → julee-0.1.5}/src/julee.egg-info/top_level.txt +0 -0
julee-0.1.5/PKG-INFO
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: julee
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: Julee - Clean architecture for accountable and transparent digital supply chains
|
|
5
|
+
Author-email: Pyx Industries <chris@pyx.io>
|
|
6
|
+
License: GPL-3.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/pyx-industries/julee
|
|
8
|
+
Project-URL: Repository, https://github.com/pyx-industries/julee
|
|
9
|
+
Project-URL: Documentation, https://github.com/pyx-industries/julee#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/pyx-industries/julee/issues
|
|
11
|
+
Keywords: temporal,workflow,document-processing,ai,supply-chain
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: fastapi>=0.100.0
|
|
23
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
24
|
+
Requires-Dist: python-multipart
|
|
25
|
+
Requires-Dist: fastapi-pagination>=0.12.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0.0
|
|
27
|
+
Requires-Dist: temporalio[pydantic]>=1.3.0
|
|
28
|
+
Requires-Dist: minio>=7.0.0
|
|
29
|
+
Requires-Dist: anthropic>=0.66.0
|
|
30
|
+
Requires-Dist: click>=0.8.0
|
|
31
|
+
Requires-Dist: Jinja2>=3.0.0
|
|
32
|
+
Requires-Dist: PyYAML>=6.0.0
|
|
33
|
+
Requires-Dist: python-magic>=0.4.27
|
|
34
|
+
Requires-Dist: multihash>=0.1.1
|
|
35
|
+
Requires-Dist: six>=1.16.0
|
|
36
|
+
Requires-Dist: jsonschema>=4.0.0
|
|
37
|
+
Requires-Dist: jsonpointer>=3.0.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-xdist>=3.5.0; extra == "dev"
|
|
43
|
+
Requires-Dist: hypothesis>=6.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: factory-boy>=3.2.0; extra == "dev"
|
|
45
|
+
Requires-Dist: mypy>=1.7.0; extra == "dev"
|
|
46
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
47
|
+
Requires-Dist: types-jsonschema; extra == "dev"
|
|
48
|
+
Requires-Dist: types-python-dateutil; extra == "dev"
|
|
49
|
+
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
50
|
+
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
51
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
52
|
+
Requires-Dist: bandit; extra == "dev"
|
|
53
|
+
Requires-Dist: pip-tools>=7.0.0; extra == "dev"
|
|
54
|
+
Requires-Dist: asyncpg; extra == "dev"
|
|
55
|
+
Provides-Extra: docs
|
|
56
|
+
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
57
|
+
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "docs"
|
|
58
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
|
|
59
|
+
Requires-Dist: furo>=2023.9.10; extra == "docs"
|
|
60
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.25.0; extra == "docs"
|
|
61
|
+
Requires-Dist: sphinxcontrib-mermaid>=0.9.2; extra == "docs"
|
|
62
|
+
Requires-Dist: sphinxcontrib-plantuml>=0.25; extra == "docs"
|
|
63
|
+
Requires-Dist: sphinx-autoapi>=3.0.0; extra == "docs"
|
|
64
|
+
Dynamic: license-file
|
|
65
|
+
|
|
66
|
+
# Julee
|
|
67
|
+
|
|
68
|
+
Clean architecture for accountable and transparent digital supply chains.
|
|
69
|
+
|
|
70
|
+
Julee is a Python framework for building resilient, auditable business processes using Temporal workflows. Solutions are organized around your business domain—your bounded contexts become "accelerators" that speak your business language, not framework jargon.
|
|
71
|
+
|
|
72
|
+
**Use Julee when:** processes must be done correctly, may be complex or long-running, need compliance audit trails (responsible AI, algorithmic due-diligence), or depend on unreliable services that may fail, timeout, or be rate-limited.
|
|
73
|
+
|
|
74
|
+
**Core concepts:** Accelerators are collections of pipelines that automate a business area. Pipelines are use cases wrapped with Temporal, providing durability (survives crashes), reliability (automatic retries), observability (complete execution history), and supply chain provenance (audit trails that become "digital product passports").
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install julee
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Runtime Dependencies
|
|
83
|
+
|
|
84
|
+
Julee applications require: [Temporal](https://temporal.io/) (workflow orchestration), S3-compatible object storage (e.g. MinIO), PostgreSQL (for Temporal).
|
|
85
|
+
|
|
86
|
+
## Documentation
|
|
87
|
+
|
|
88
|
+
Full documentation at [julee.readthedocs.io](https://julee.readthedocs.io), package on [PyPI](https://pypi.org/project/julee/).
|
|
89
|
+
|
|
90
|
+
## Example
|
|
91
|
+
|
|
92
|
+
This repository includes a Docker Compose example demonstrating a meeting minutes extraction system:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cp .env.example .env # Add your ANTHROPIC_API_KEY
|
|
96
|
+
docker compose up --build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
See the `demo-ui/` directory for the UI source.
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
GPL-3.0 — see [LICENSE](LICENSE) for details.
|
julee-0.1.5/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Julee
|
|
2
|
+
|
|
3
|
+
Clean architecture for accountable and transparent digital supply chains.
|
|
4
|
+
|
|
5
|
+
Julee is a Python framework for building resilient, auditable business processes using Temporal workflows. Solutions are organized around your business domain—your bounded contexts become "accelerators" that speak your business language, not framework jargon.
|
|
6
|
+
|
|
7
|
+
**Use Julee when:** processes must be done correctly, may be complex or long-running, need compliance audit trails (responsible AI, algorithmic due-diligence), or depend on unreliable services that may fail, timeout, or be rate-limited.
|
|
8
|
+
|
|
9
|
+
**Core concepts:** Accelerators are collections of pipelines that automate a business area. Pipelines are use cases wrapped with Temporal, providing durability (survives crashes), reliability (automatic retries), observability (complete execution history), and supply chain provenance (audit trails that become "digital product passports").
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install julee
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Runtime Dependencies
|
|
18
|
+
|
|
19
|
+
Julee applications require: [Temporal](https://temporal.io/) (workflow orchestration), S3-compatible object storage (e.g. MinIO), PostgreSQL (for Temporal).
|
|
20
|
+
|
|
21
|
+
## Documentation
|
|
22
|
+
|
|
23
|
+
Full documentation at [julee.readthedocs.io](https://julee.readthedocs.io), package on [PyPI](https://pypi.org/project/julee/).
|
|
24
|
+
|
|
25
|
+
## Example
|
|
26
|
+
|
|
27
|
+
This repository includes a Docker Compose example demonstrating a meeting minutes extraction system:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cp .env.example .env # Add your ANTHROPIC_API_KEY
|
|
31
|
+
docker compose up --build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
See the `demo-ui/` directory for the UI source.
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
GPL-3.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "julee"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
description = "Julee - Clean architecture for accountable and transparent digital supply chains"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -54,6 +54,7 @@ dev = [
|
|
|
54
54
|
"pytest>=8.0.0",
|
|
55
55
|
"pytest-asyncio>=1.0.0",
|
|
56
56
|
"pytest-cov>=4.1.0",
|
|
57
|
+
"pytest-xdist>=3.5.0",
|
|
57
58
|
"hypothesis>=6.0.0",
|
|
58
59
|
"factory-boy>=3.2.0",
|
|
59
60
|
# Type checking
|
|
@@ -106,10 +107,20 @@ asyncio_mode = "auto"
|
|
|
106
107
|
addopts = [
|
|
107
108
|
"--strict-markers",
|
|
108
109
|
"--tb=short",
|
|
110
|
+
"-n", "auto",
|
|
111
|
+
"--dist", "loadgroup",
|
|
109
112
|
"--cov=src/julee",
|
|
110
113
|
"--cov-report=term-missing",
|
|
111
114
|
"--cov-report=html",
|
|
112
115
|
]
|
|
116
|
+
markers = [
|
|
117
|
+
"unit: Unit tests (fast, isolated)",
|
|
118
|
+
"integration: Integration tests (slower, with dependencies)",
|
|
119
|
+
"e2e: End-to-end tests (slowest, full stack)",
|
|
120
|
+
"llm: Tests that use real LLM API calls (slow, costs money)",
|
|
121
|
+
"contract: Contract tests (verify external API shapes and mock fidelity)",
|
|
122
|
+
"slow: Slow tests (stress tests, load tests)",
|
|
123
|
+
]
|
|
113
124
|
|
|
114
125
|
[tool.coverage.run]
|
|
115
126
|
source = ["src/julee"]
|
|
@@ -18,6 +18,8 @@ from julee.api.routers.documents import router
|
|
|
18
18
|
from julee.domain.models.document import Document, DocumentStatus
|
|
19
19
|
from julee.repositories.memory import MemoryDocumentRepository
|
|
20
20
|
|
|
21
|
+
pytestmark = pytest.mark.unit
|
|
22
|
+
|
|
21
23
|
|
|
22
24
|
@pytest.fixture
|
|
23
25
|
def memory_repo() -> MemoryDocumentRepository:
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Polling Contrib Module.
|
|
3
|
+
|
|
4
|
+
This module provides ready-made polling functionality for external endpoints.
|
|
5
|
+
It follows the Julee contrib module pattern, providing a complete polling
|
|
6
|
+
solution that can be imported and used by Julee solutions.
|
|
7
|
+
|
|
8
|
+
The polling module includes:
|
|
9
|
+
- Domain models for polling configuration and results
|
|
10
|
+
- Service protocols for polling operations
|
|
11
|
+
- HTTP implementation for REST API polling
|
|
12
|
+
- Co-located tests and examples
|
|
13
|
+
|
|
14
|
+
Example usage:
|
|
15
|
+
from julee.contrib.polling.domain.models.polling_config import PollingConfig, PollingProtocol
|
|
16
|
+
from julee.contrib.polling.infrastructure.services.polling.http import HttpPollerService
|
|
17
|
+
from julee.contrib.polling.domain.services.poller import PollerService
|
|
18
|
+
from julee.contrib.polling.domain.models.polling_config import PollingResult
|
|
19
|
+
|
|
20
|
+
# Configure polling
|
|
21
|
+
config = PollingConfig(
|
|
22
|
+
endpoint_identifier="api-v1",
|
|
23
|
+
polling_protocol=PollingProtocol.HTTP,
|
|
24
|
+
connection_params={"url": "https://api.example.com/data"},
|
|
25
|
+
timeout_seconds=30
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Poll the endpoint
|
|
29
|
+
service = HttpPollerService()
|
|
30
|
+
result = await service.poll_endpoint(config)
|
|
31
|
+
|
|
32
|
+
Note: All imports must be explicit to avoid import chains that can pull
|
|
33
|
+
non-deterministic code into Temporal workflows. Import directly from
|
|
34
|
+
the specific modules you need rather than using this convenience module.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# No re-exports to avoid import chains that pull non-deterministic code
|
|
38
|
+
# into Temporal workflows. Import from specific submodules instead:
|
|
39
|
+
#
|
|
40
|
+
# Domain:
|
|
41
|
+
# - from julee.contrib.polling.domain.models.polling_config import PollingConfig, PollingProtocol, PollingResult
|
|
42
|
+
# - from julee.contrib.polling.domain.services.poller import PollerService
|
|
43
|
+
#
|
|
44
|
+
# Infrastructure:
|
|
45
|
+
# - from julee.contrib.polling.infrastructure.services.polling.http import HttpPollerService
|
|
46
|
+
# - from julee.contrib.polling.infrastructure.temporal.manager import PollingManager
|
|
47
|
+
# - from julee.contrib.polling.infrastructure.temporal.proxies import WorkflowPollerServiceProxy
|
|
48
|
+
# - from julee.contrib.polling.infrastructure.temporal.activities import TemporalPollerService
|
|
49
|
+
|
|
50
|
+
__all__ = []
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application entry points for the polling contrib module.
|
|
3
|
+
|
|
4
|
+
This module contains the application-layer components that provide entry points
|
|
5
|
+
for the polling contrib module, including worker pipelines, API routes, and
|
|
6
|
+
CLI commands.
|
|
7
|
+
|
|
8
|
+
Following the ADR contrib module structure, this layer wires together domain
|
|
9
|
+
services and infrastructure implementations into runnable applications.
|
|
10
|
+
|
|
11
|
+
No re-exports to avoid import chains that pull non-deterministic code
|
|
12
|
+
into Temporal workflows. Import directly from specific modules:
|
|
13
|
+
|
|
14
|
+
- from julee.contrib.polling.apps.worker.pipelines import NewDataDetectionPipeline
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__all__ = []
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Worker applications for the polling contrib module.
|
|
3
|
+
|
|
4
|
+
This module contains worker-specific entry points for the polling contrib module,
|
|
5
|
+
including Temporal workflows (pipelines) that orchestrate polling operations
|
|
6
|
+
with durability guarantees.
|
|
7
|
+
|
|
8
|
+
The worker applications in this module can be registered with Temporal workers
|
|
9
|
+
to provide polling capabilities within workflow contexts.
|
|
10
|
+
|
|
11
|
+
No re-exports to avoid import chains that pull non-deterministic code
|
|
12
|
+
into Temporal workflows. Import directly from specific modules:
|
|
13
|
+
|
|
14
|
+
- from julee.contrib.polling.apps.worker.pipelines import NewDataDetectionPipeline
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__all__ = []
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Temporal workflows for polling operations in the Julee polling contrib module.
|
|
3
|
+
|
|
4
|
+
This module contains workflows that orchestrate polling operations with
|
|
5
|
+
Temporal's durability guarantees, providing retry logic, state management,
|
|
6
|
+
and reliable execution for endpoint polling and change detection.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import hashlib
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from temporalio import workflow
|
|
14
|
+
|
|
15
|
+
from julee.contrib.polling.domain.models.polling_config import PollingConfig
|
|
16
|
+
from julee.contrib.polling.infrastructure.temporal.proxies import (
|
|
17
|
+
WorkflowPollerServiceProxy,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@workflow.defn
|
|
24
|
+
class NewDataDetectionPipeline:
|
|
25
|
+
"""
|
|
26
|
+
Temporal workflow for endpoint polling with new data detection.
|
|
27
|
+
|
|
28
|
+
This workflow:
|
|
29
|
+
1. Polls an endpoint using the configured polling service
|
|
30
|
+
2. Compares result with previous completion to detect changes
|
|
31
|
+
3. Triggers downstream processing when new data is detected
|
|
32
|
+
4. Returns completion result for next scheduled execution
|
|
33
|
+
|
|
34
|
+
The workflow uses Temporal's schedule last completion result feature
|
|
35
|
+
to automatically receive the previous execution's result for comparison.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self) -> None:
|
|
39
|
+
self.current_step = "initialized"
|
|
40
|
+
self.endpoint_id: str | None = None
|
|
41
|
+
self.has_new_data: bool = False
|
|
42
|
+
|
|
43
|
+
@workflow.query
|
|
44
|
+
def get_current_step(self) -> str:
|
|
45
|
+
"""Query method to get the current workflow step."""
|
|
46
|
+
return self.current_step
|
|
47
|
+
|
|
48
|
+
@workflow.query
|
|
49
|
+
def get_endpoint_id(self) -> str | None:
|
|
50
|
+
"""Query method to get the endpoint ID being polled."""
|
|
51
|
+
return self.endpoint_id
|
|
52
|
+
|
|
53
|
+
@workflow.query
|
|
54
|
+
def get_has_new_data(self) -> bool:
|
|
55
|
+
"""Query method to check if new data was detected."""
|
|
56
|
+
return self.has_new_data
|
|
57
|
+
|
|
58
|
+
async def trigger_downstream_pipeline(
|
|
59
|
+
self,
|
|
60
|
+
downstream_pipeline: str,
|
|
61
|
+
previous_data: bytes | None,
|
|
62
|
+
new_data: bytes,
|
|
63
|
+
) -> bool:
|
|
64
|
+
"""
|
|
65
|
+
Trigger downstream pipeline workflow.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
downstream_pipeline: Name of the downstream workflow to trigger
|
|
69
|
+
previous_data: Previous content (None if first run)
|
|
70
|
+
new_data: New content that was detected
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
True if successfully triggered, False otherwise
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
# Start external workflow for downstream processing (fire-and-forget)
|
|
77
|
+
await workflow.start_child_workflow(
|
|
78
|
+
downstream_pipeline, # This would be the workflow class name
|
|
79
|
+
args=[previous_data, new_data],
|
|
80
|
+
id=f"downstream-{self.endpoint_id}-{workflow.info().workflow_id}",
|
|
81
|
+
task_queue="downstream-processing-queue",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
workflow.logger.info(
|
|
85
|
+
"Downstream pipeline triggered successfully",
|
|
86
|
+
extra={
|
|
87
|
+
"endpoint_id": self.endpoint_id,
|
|
88
|
+
"downstream_pipeline": downstream_pipeline,
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
workflow.logger.error(
|
|
95
|
+
"Failed to trigger downstream pipeline",
|
|
96
|
+
extra={
|
|
97
|
+
"endpoint_id": self.endpoint_id,
|
|
98
|
+
"downstream_pipeline": downstream_pipeline,
|
|
99
|
+
"error": str(e),
|
|
100
|
+
"error_type": type(e).__name__,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
# Don't fail the polling workflow if downstream trigger fails
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
@workflow.run
|
|
107
|
+
async def run(
|
|
108
|
+
self,
|
|
109
|
+
config: PollingConfig | dict[str, Any],
|
|
110
|
+
downstream_pipeline: str | None = None,
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
"""
|
|
113
|
+
Execute the new data detection workflow.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
config: Configuration for the polling operation (PollingConfig or dict from schedule)
|
|
117
|
+
downstream_pipeline: Optional pipeline to trigger when new data detected
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Completion result containing polling result and detection metadata
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
RuntimeError: If polling or downstream processing fails after retries
|
|
124
|
+
"""
|
|
125
|
+
# Convert dict to PollingConfig if needed (for schedule compatibility)
|
|
126
|
+
# Temporal schedules serialize arguments as dicts, not Pydantic models
|
|
127
|
+
if isinstance(config, dict):
|
|
128
|
+
config = PollingConfig.model_validate(config)
|
|
129
|
+
|
|
130
|
+
self.endpoint_id = config.endpoint_identifier
|
|
131
|
+
|
|
132
|
+
# Fetch previous completion result from Temporal
|
|
133
|
+
previous_completion = workflow.get_last_completion_result()
|
|
134
|
+
|
|
135
|
+
workflow.logger.info(
|
|
136
|
+
"Starting new data detection pipeline",
|
|
137
|
+
extra={
|
|
138
|
+
"endpoint_id": self.endpoint_id,
|
|
139
|
+
"polling_protocol": config.polling_protocol.value,
|
|
140
|
+
"has_previous_completion": previous_completion is not None,
|
|
141
|
+
"workflow_id": workflow.info().workflow_id,
|
|
142
|
+
"run_id": workflow.info().run_id,
|
|
143
|
+
},
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
self.current_step = "polling_endpoint"
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
# Step 1: Poll the endpoint
|
|
150
|
+
polling_service = WorkflowPollerServiceProxy()
|
|
151
|
+
polling_result = await polling_service.poll_endpoint(config)
|
|
152
|
+
|
|
153
|
+
# Extract the timestamp from when polling actually happened
|
|
154
|
+
polled_at = polling_result.polled_at.isoformat()
|
|
155
|
+
|
|
156
|
+
workflow.logger.debug(
|
|
157
|
+
"Polling completed",
|
|
158
|
+
extra={
|
|
159
|
+
"endpoint_id": self.endpoint_id,
|
|
160
|
+
"polling_success": polling_result.success,
|
|
161
|
+
"content_length": len(polling_result.content),
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
self.current_step = "detecting_changes"
|
|
166
|
+
|
|
167
|
+
# Step 2: Detect new data using hash comparison
|
|
168
|
+
current_content = polling_result.content
|
|
169
|
+
current_hash = hashlib.sha256(current_content).hexdigest()
|
|
170
|
+
|
|
171
|
+
previous_hash = None
|
|
172
|
+
if previous_completion and "polling_result" in previous_completion:
|
|
173
|
+
previous_hash = previous_completion["polling_result"].get(
|
|
174
|
+
"content_hash"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
has_new_data = previous_hash != current_hash
|
|
178
|
+
self.has_new_data = has_new_data
|
|
179
|
+
|
|
180
|
+
workflow.logger.info(
|
|
181
|
+
f"DEBUG: Change detection - has_new_data: {has_new_data}, "
|
|
182
|
+
f"is_first_run: {previous_hash is None}, "
|
|
183
|
+
f"current_hash: {current_hash[:8]}..., "
|
|
184
|
+
f"previous_hash: {previous_hash[:8] if previous_hash else 'None'}..."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Step 3: Trigger downstream processing if new data detected
|
|
188
|
+
downstream_triggered = False
|
|
189
|
+
if has_new_data and downstream_pipeline:
|
|
190
|
+
self.current_step = "triggering_downstream"
|
|
191
|
+
|
|
192
|
+
workflow.logger.info(
|
|
193
|
+
"Triggering downstream pipeline",
|
|
194
|
+
extra={
|
|
195
|
+
"endpoint_id": self.endpoint_id,
|
|
196
|
+
"downstream_pipeline": downstream_pipeline,
|
|
197
|
+
"content_length": len(current_content),
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Get previous data for comparison
|
|
202
|
+
previous_data = None
|
|
203
|
+
if previous_completion and "polling_result" in previous_completion:
|
|
204
|
+
prev_content_str = previous_completion["polling_result"].get(
|
|
205
|
+
"content"
|
|
206
|
+
)
|
|
207
|
+
if prev_content_str:
|
|
208
|
+
try:
|
|
209
|
+
previous_data = prev_content_str.encode("utf-8")
|
|
210
|
+
except (UnicodeDecodeError, AttributeError) as e:
|
|
211
|
+
workflow.logger.error(
|
|
212
|
+
"Failed to decode previous content for downstream pipeline",
|
|
213
|
+
extra={
|
|
214
|
+
"endpoint_id": self.endpoint_id,
|
|
215
|
+
"error": str(e),
|
|
216
|
+
"error_type": type(e).__name__,
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
raise RuntimeError(
|
|
220
|
+
f"Previous content is corrupted or invalid: {e}"
|
|
221
|
+
)
|
|
222
|
+
elif previous_hash:
|
|
223
|
+
# We have previous run but no content - this is an error
|
|
224
|
+
workflow.logger.error(
|
|
225
|
+
"Previous content not available for downstream pipeline but previous hash exists",
|
|
226
|
+
extra={
|
|
227
|
+
"endpoint_id": self.endpoint_id,
|
|
228
|
+
"previous_hash": previous_hash,
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
raise RuntimeError(
|
|
232
|
+
"Previous content is missing from completion result but is required for downstream pipeline"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
downstream_triggered = await self.trigger_downstream_pipeline(
|
|
236
|
+
downstream_pipeline,
|
|
237
|
+
previous_data,
|
|
238
|
+
current_content,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
self.current_step = "completed"
|
|
242
|
+
|
|
243
|
+
# Step 4: Return completion result for next scheduled execution
|
|
244
|
+
completion_result = {
|
|
245
|
+
"polling_result": {
|
|
246
|
+
"success": polling_result.success,
|
|
247
|
+
"content_hash": current_hash,
|
|
248
|
+
"content": current_content.decode("utf-8", errors="ignore"),
|
|
249
|
+
"polled_at": polled_at,
|
|
250
|
+
"content_length": len(current_content),
|
|
251
|
+
},
|
|
252
|
+
"detection_result": {
|
|
253
|
+
"has_new_data": has_new_data,
|
|
254
|
+
"previous_hash": previous_hash,
|
|
255
|
+
"current_hash": current_hash,
|
|
256
|
+
},
|
|
257
|
+
"downstream_triggered": downstream_triggered,
|
|
258
|
+
"endpoint_id": self.endpoint_id,
|
|
259
|
+
"completed_at": workflow.now().isoformat(),
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
workflow.logger.info(
|
|
263
|
+
"New data detection pipeline completed successfully",
|
|
264
|
+
extra={
|
|
265
|
+
"endpoint_id": self.endpoint_id,
|
|
266
|
+
"has_new_data": has_new_data,
|
|
267
|
+
"downstream_triggered": downstream_triggered,
|
|
268
|
+
},
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return completion_result
|
|
272
|
+
|
|
273
|
+
except Exception as e:
|
|
274
|
+
self.current_step = "failed"
|
|
275
|
+
|
|
276
|
+
workflow.logger.error(
|
|
277
|
+
"New data detection pipeline failed",
|
|
278
|
+
extra={
|
|
279
|
+
"endpoint_id": self.endpoint_id,
|
|
280
|
+
"error": str(e),
|
|
281
|
+
"error_type": type(e).__name__,
|
|
282
|
+
"current_step": self.current_step,
|
|
283
|
+
},
|
|
284
|
+
exc_info=True,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Re-raise to let Temporal handle retry logic
|
|
288
|
+
raise
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Domain layer for the polling contrib module.
|
|
3
|
+
|
|
4
|
+
This module contains the core domain models, services, and business rules
|
|
5
|
+
for the polling contrib module. It defines the fundamental concepts and
|
|
6
|
+
protocols that govern polling operations.
|
|
7
|
+
|
|
8
|
+
No re-exports to avoid import chains that pull non-deterministic code
|
|
9
|
+
into Temporal workflows. Import directly from specific modules:
|
|
10
|
+
|
|
11
|
+
- from julee.contrib.polling.domain.models.polling_config import PollingConfig, PollingProtocol, PollingResult
|
|
12
|
+
- from julee.contrib.polling.domain.services.poller import PollerService
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__all__ = []
|