julee 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- julee/api/app.py +9 -8
- julee/api/dependencies.py +15 -15
- julee/api/requests.py +10 -9
- julee/api/responses.py +2 -1
- julee/api/routers/__init__.py +5 -5
- julee/api/routers/assembly_specifications.py +5 -4
- julee/api/routers/documents.py +1 -1
- julee/api/routers/knowledge_service_configs.py +4 -3
- julee/api/routers/knowledge_service_queries.py +7 -6
- julee/api/routers/system.py +4 -3
- julee/api/routers/workflows.py +4 -5
- julee/api/services/system_initialization.py +6 -6
- julee/api/tests/routers/test_assembly_specifications.py +4 -3
- julee/api/tests/routers/test_documents.py +5 -4
- julee/api/tests/routers/test_knowledge_service_configs.py +7 -6
- julee/api/tests/routers/test_knowledge_service_queries.py +4 -3
- julee/api/tests/routers/test_system.py +5 -4
- julee/api/tests/routers/test_workflows.py +5 -4
- julee/api/tests/test_app.py +5 -4
- julee/api/tests/test_dependencies.py +3 -2
- julee/api/tests/test_requests.py +2 -1
- julee/contrib/__init__.py +15 -0
- julee/contrib/polling/__init__.py +47 -0
- julee/contrib/polling/domain/__init__.py +17 -0
- julee/contrib/polling/domain/models/__init__.py +13 -0
- julee/contrib/polling/domain/models/polling_config.py +39 -0
- julee/contrib/polling/domain/services/__init__.py +11 -0
- julee/contrib/polling/domain/services/poller.py +39 -0
- julee/contrib/polling/infrastructure/__init__.py +15 -0
- julee/contrib/polling/infrastructure/services/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/http/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/http/http_poller_service.py +80 -0
- julee/contrib/polling/infrastructure/temporal/__init__.py +20 -0
- julee/contrib/polling/infrastructure/temporal/activities.py +42 -0
- julee/contrib/polling/infrastructure/temporal/activity_names.py +20 -0
- julee/contrib/polling/infrastructure/temporal/proxies.py +45 -0
- julee/contrib/polling/tests/__init__.py +6 -0
- julee/contrib/polling/tests/unit/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/__init__.py +7 -0
- julee/contrib/polling/tests/unit/infrastructure/services/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/http/__init__.py +7 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/http/test_http_poller_service.py +163 -0
- julee/docs/__init__.py +5 -0
- julee/docs/sphinx_hcd/__init__.py +82 -0
- julee/docs/sphinx_hcd/accelerators.py +1078 -0
- julee/docs/sphinx_hcd/apps.py +499 -0
- julee/docs/sphinx_hcd/config.py +148 -0
- julee/docs/sphinx_hcd/epics.py +448 -0
- julee/docs/sphinx_hcd/integrations.py +306 -0
- julee/docs/sphinx_hcd/journeys.py +783 -0
- julee/docs/sphinx_hcd/personas.py +435 -0
- julee/docs/sphinx_hcd/stories.py +932 -0
- julee/docs/sphinx_hcd/utils.py +180 -0
- julee/domain/models/__init__.py +5 -6
- julee/domain/models/assembly/assembly.py +7 -7
- julee/domain/models/assembly/tests/factories.py +2 -1
- julee/domain/models/assembly/tests/test_assembly.py +16 -13
- julee/domain/models/assembly_specification/assembly_specification.py +11 -10
- julee/domain/models/assembly_specification/knowledge_service_query.py +14 -9
- julee/domain/models/assembly_specification/tests/factories.py +2 -1
- julee/domain/models/assembly_specification/tests/test_assembly_specification.py +9 -6
- julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +3 -1
- julee/domain/models/custom_fields/content_stream.py +3 -2
- julee/domain/models/custom_fields/tests/test_custom_fields.py +2 -1
- julee/domain/models/document/document.py +12 -10
- julee/domain/models/document/tests/factories.py +3 -2
- julee/domain/models/document/tests/test_document.py +6 -3
- julee/domain/models/knowledge_service_config/knowledge_service_config.py +4 -4
- julee/domain/models/policy/__init__.py +4 -4
- julee/domain/models/policy/document_policy_validation.py +17 -17
- julee/domain/models/policy/policy.py +12 -10
- julee/domain/models/policy/tests/factories.py +2 -1
- julee/domain/models/policy/tests/test_document_policy_validation.py +3 -1
- julee/domain/models/policy/tests/test_policy.py +2 -1
- julee/domain/repositories/__init__.py +3 -3
- julee/domain/repositories/assembly.py +3 -1
- julee/domain/repositories/assembly_specification.py +2 -0
- julee/domain/repositories/base.py +33 -16
- julee/domain/repositories/document.py +3 -1
- julee/domain/repositories/document_policy_validation.py +3 -1
- julee/domain/repositories/knowledge_service_config.py +2 -0
- julee/domain/repositories/knowledge_service_query.py +1 -0
- julee/domain/repositories/policy.py +3 -1
- julee/domain/use_cases/decorators.py +3 -2
- julee/domain/use_cases/extract_assemble_data.py +23 -13
- julee/domain/use_cases/initialize_system_data.py +13 -13
- julee/domain/use_cases/tests/test_extract_assemble_data.py +10 -10
- julee/domain/use_cases/tests/test_initialize_system_data.py +2 -2
- julee/domain/use_cases/tests/test_validate_document.py +11 -11
- julee/domain/use_cases/validate_document.py +26 -15
- julee/maintenance/__init__.py +1 -0
- julee/maintenance/release.py +188 -0
- julee/repositories/__init__.py +4 -1
- julee/repositories/memory/assembly.py +6 -5
- julee/repositories/memory/assembly_specification.py +9 -9
- julee/repositories/memory/base.py +12 -11
- julee/repositories/memory/document.py +8 -7
- julee/repositories/memory/document_policy_validation.py +7 -6
- julee/repositories/memory/knowledge_service_config.py +9 -7
- julee/repositories/memory/knowledge_service_query.py +9 -7
- julee/repositories/memory/policy.py +6 -5
- julee/repositories/memory/tests/test_document.py +6 -4
- julee/repositories/memory/tests/test_document_policy_validation.py +2 -1
- julee/repositories/memory/tests/test_policy.py +2 -1
- julee/repositories/minio/assembly.py +4 -4
- julee/repositories/minio/assembly_specification.py +6 -8
- julee/repositories/minio/client.py +22 -25
- julee/repositories/minio/document.py +11 -11
- julee/repositories/minio/document_policy_validation.py +5 -5
- julee/repositories/minio/knowledge_service_config.py +8 -8
- julee/repositories/minio/knowledge_service_query.py +6 -9
- julee/repositories/minio/policy.py +4 -4
- julee/repositories/minio/tests/fake_client.py +11 -9
- julee/repositories/minio/tests/test_assembly.py +3 -1
- julee/repositories/minio/tests/test_assembly_specification.py +2 -1
- julee/repositories/minio/tests/test_client_protocol.py +5 -5
- julee/repositories/minio/tests/test_document.py +7 -6
- julee/repositories/minio/tests/test_document_policy_validation.py +3 -1
- julee/repositories/minio/tests/test_knowledge_service_config.py +4 -2
- julee/repositories/minio/tests/test_knowledge_service_query.py +3 -2
- julee/repositories/minio/tests/test_policy.py +3 -1
- julee/repositories/temporal/activities.py +5 -5
- julee/repositories/temporal/proxies.py +5 -5
- julee/services/knowledge_service/__init__.py +1 -2
- julee/services/knowledge_service/anthropic/knowledge_service.py +8 -7
- julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +11 -10
- julee/services/knowledge_service/factory.py +8 -8
- julee/services/knowledge_service/knowledge_service.py +22 -18
- julee/services/knowledge_service/memory/knowledge_service.py +13 -12
- julee/services/knowledge_service/memory/test_knowledge_service.py +10 -7
- julee/services/knowledge_service/test_factory.py +11 -10
- julee/services/temporal/activities.py +10 -10
- julee/services/temporal/proxies.py +2 -2
- julee/util/domain.py +6 -6
- julee/util/repos/minio/file_storage.py +8 -9
- julee/util/repos/temporal/client_proxies/file_storage.py +3 -4
- julee/util/repos/temporal/data_converter.py +6 -6
- julee/util/repos/temporal/minio_file_storage.py +1 -1
- julee/util/repos/temporal/proxies/file_storage.py +2 -3
- julee/util/repositories.py +6 -7
- julee/util/temporal/activities.py +1 -1
- julee/util/temporal/decorators.py +28 -33
- julee/util/tests/test_decorators.py +13 -15
- julee/util/validation/repository.py +3 -3
- julee/util/validation/type_guards.py +12 -11
- julee/worker.py +9 -8
- julee/workflows/__init__.py +2 -2
- julee/workflows/extract_assemble.py +2 -1
- julee/workflows/validate_document.py +3 -2
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/METADATA +4 -1
- julee-0.1.3.dist-info/RECORD +197 -0
- julee-0.1.1.dist-info/RECORD +0 -161
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/WHEEL +0 -0
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/top_level.txt +0 -0
|
@@ -8,11 +8,13 @@ All domain models use Pydantic BaseModel for validation, serialization,
|
|
|
8
8
|
and type safety, following the patterns established in the sample project.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from
|
|
12
|
-
from pydantic import ValidationInfo
|
|
13
|
-
from typing import Callable, Optional, List, Dict, Any
|
|
11
|
+
from collections.abc import Callable
|
|
14
12
|
from datetime import datetime, timezone
|
|
15
13
|
from enum import Enum
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator
|
|
17
|
+
|
|
16
18
|
from julee.domain.models.custom_fields.content_stream import (
|
|
17
19
|
ContentStream,
|
|
18
20
|
)
|
|
@@ -75,21 +77,21 @@ class Document(BaseModel):
|
|
|
75
77
|
|
|
76
78
|
# Document processing state
|
|
77
79
|
status: DocumentStatus = DocumentStatus.CAPTURED
|
|
78
|
-
knowledge_service_id:
|
|
79
|
-
assembly_types:
|
|
80
|
+
knowledge_service_id: str | None = None
|
|
81
|
+
assembly_types: list[str] = Field(default_factory=list)
|
|
80
82
|
|
|
81
83
|
# Timestamps
|
|
82
|
-
created_at:
|
|
84
|
+
created_at: datetime | None = Field(
|
|
83
85
|
default_factory=lambda: datetime.now(timezone.utc)
|
|
84
86
|
)
|
|
85
|
-
updated_at:
|
|
87
|
+
updated_at: datetime | None = Field(
|
|
86
88
|
default_factory=lambda: datetime.now(timezone.utc)
|
|
87
89
|
)
|
|
88
90
|
|
|
89
91
|
# Additional data and content stream
|
|
90
|
-
additional_metadata:
|
|
91
|
-
content:
|
|
92
|
-
content_string:
|
|
92
|
+
additional_metadata: dict[str, Any] = Field(default_factory=dict)
|
|
93
|
+
content: ContentStream | None = Field(default=None, exclude=True)
|
|
94
|
+
content_string: str | None = Field(
|
|
93
95
|
default=None,
|
|
94
96
|
description="Small content as string (few KB max). Use for "
|
|
95
97
|
"workflow-generated content to avoid ContentStream serialization "
|
|
@@ -8,14 +8,15 @@ Document domain objects with sensible defaults.
|
|
|
8
8
|
import io
|
|
9
9
|
from datetime import datetime, timezone
|
|
10
10
|
from typing import Any
|
|
11
|
+
|
|
11
12
|
from factory.base import Factory
|
|
12
|
-
from factory.faker import Faker
|
|
13
13
|
from factory.declarations import LazyAttribute, LazyFunction
|
|
14
|
+
from factory.faker import Faker
|
|
14
15
|
|
|
15
|
-
from julee.domain.models.document import Document, DocumentStatus
|
|
16
16
|
from julee.domain.models.custom_fields.content_stream import (
|
|
17
17
|
ContentStream,
|
|
18
18
|
)
|
|
19
|
+
from julee.domain.models.document import Document, DocumentStatus
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
# Helper functions to generate content bytes consistently
|
|
@@ -19,11 +19,14 @@ Design decisions documented:
|
|
|
19
19
|
- Documents act as readable streams with standard methods
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
import pytest
|
|
23
22
|
import json
|
|
24
23
|
|
|
24
|
+
import pytest
|
|
25
|
+
from pydantic import ValidationError
|
|
26
|
+
|
|
25
27
|
from julee.domain.models.document import Document
|
|
26
|
-
|
|
28
|
+
|
|
29
|
+
from .factories import ContentStreamFactory, DocumentFactory
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
class TestDocumentInstantiation:
|
|
@@ -164,7 +167,7 @@ class TestDocumentInstantiation:
|
|
|
164
167
|
assert doc.content_multihash.strip() == multihash.strip()
|
|
165
168
|
else:
|
|
166
169
|
# Should raise validation error
|
|
167
|
-
with pytest.raises(
|
|
170
|
+
with pytest.raises((ValueError, ValidationError)):
|
|
168
171
|
Document(
|
|
169
172
|
document_id=document_id,
|
|
170
173
|
original_filename=original_filename,
|
|
@@ -13,11 +13,11 @@ All domain models use Pydantic BaseModel for validation, serialization,
|
|
|
13
13
|
and type safety, following the patterns established in the sample project.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from pydantic import BaseModel, Field, field_validator
|
|
17
|
-
from typing import Optional
|
|
18
16
|
from datetime import datetime, timezone
|
|
19
17
|
from enum import Enum
|
|
20
18
|
|
|
19
|
+
from pydantic import BaseModel, Field, field_validator
|
|
20
|
+
|
|
21
21
|
|
|
22
22
|
class ServiceApi(str, Enum):
|
|
23
23
|
"""Supported knowledge service APIs."""
|
|
@@ -48,10 +48,10 @@ class KnowledgeServiceConfig(BaseModel):
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
# Timestamps
|
|
51
|
-
created_at:
|
|
51
|
+
created_at: datetime | None = Field(
|
|
52
52
|
default_factory=lambda: datetime.now(timezone.utc)
|
|
53
53
|
)
|
|
54
|
-
updated_at:
|
|
54
|
+
updated_at: datetime | None = Field(
|
|
55
55
|
default_factory=lambda: datetime.now(timezone.utc)
|
|
56
56
|
)
|
|
57
57
|
|
|
@@ -17,11 +17,11 @@ All domain models use Pydantic BaseModel for validation, serialization,
|
|
|
17
17
|
and type safety, following the patterns established in the sample project.
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
-
from pydantic import BaseModel, Field, field_validator
|
|
21
|
-
from typing import Optional, List, Tuple
|
|
22
20
|
from datetime import datetime, timezone
|
|
23
21
|
from enum import Enum
|
|
24
22
|
|
|
23
|
+
from pydantic import BaseModel, Field, field_validator
|
|
24
|
+
|
|
25
25
|
|
|
26
26
|
class DocumentPolicyValidationStatus(str, Enum):
|
|
27
27
|
"""Status of a document policy validation process."""
|
|
@@ -70,7 +70,7 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
70
70
|
status: DocumentPolicyValidationStatus = DocumentPolicyValidationStatus.PENDING
|
|
71
71
|
|
|
72
72
|
# Initial validation results
|
|
73
|
-
validation_scores:
|
|
73
|
+
validation_scores: list[tuple[str, int]] = Field(
|
|
74
74
|
default_factory=list,
|
|
75
75
|
description="List of (knowledge_service_query_id, actual_score) "
|
|
76
76
|
"tuples representing the scores achieved during initial validation. "
|
|
@@ -78,13 +78,13 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# Transformation results (if applicable)
|
|
81
|
-
transformed_document_id:
|
|
81
|
+
transformed_document_id: str | None = Field(
|
|
82
82
|
default=None,
|
|
83
83
|
description="ID of the document after transformations have been "
|
|
84
84
|
"applied. Only present if the policy includes transformation queries "
|
|
85
85
|
"and they were executed",
|
|
86
86
|
)
|
|
87
|
-
post_transform_validation_scores:
|
|
87
|
+
post_transform_validation_scores: list[tuple[str, int]] | None = Field(
|
|
88
88
|
default=None,
|
|
89
89
|
description="List of (knowledge_service_query_id, actual_score) "
|
|
90
90
|
"tuples representing scores achieved after transformation. "
|
|
@@ -93,19 +93,19 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
93
93
|
)
|
|
94
94
|
|
|
95
95
|
# Validation metadata
|
|
96
|
-
started_at:
|
|
96
|
+
started_at: datetime | None = Field(
|
|
97
97
|
default_factory=lambda: datetime.now(timezone.utc),
|
|
98
98
|
description="When the validation process was initiated",
|
|
99
99
|
)
|
|
100
|
-
completed_at:
|
|
100
|
+
completed_at: datetime | None = Field(
|
|
101
101
|
default=None, description="When the validation process completed"
|
|
102
102
|
)
|
|
103
|
-
error_message:
|
|
103
|
+
error_message: str | None = Field(
|
|
104
104
|
default=None, description="Error message if validation process failed"
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
# Results summary
|
|
108
|
-
passed:
|
|
108
|
+
passed: bool | None = Field(
|
|
109
109
|
default=None,
|
|
110
110
|
description="Whether the document passed policy validation. "
|
|
111
111
|
"None while validation is in progress, True/False when complete",
|
|
@@ -128,8 +128,8 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
128
128
|
@field_validator("validation_scores")
|
|
129
129
|
@classmethod
|
|
130
130
|
def validation_scores_must_be_valid(
|
|
131
|
-
cls, v:
|
|
132
|
-
) ->
|
|
131
|
+
cls, v: list[tuple[str, int]]
|
|
132
|
+
) -> list[tuple[str, int]]:
|
|
133
133
|
if not isinstance(v, list):
|
|
134
134
|
raise ValueError("Validation scores must be a list")
|
|
135
135
|
|
|
@@ -142,8 +142,8 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
142
142
|
@field_validator("post_transform_validation_scores")
|
|
143
143
|
@classmethod
|
|
144
144
|
def post_transform_scores_must_be_valid(
|
|
145
|
-
cls, v:
|
|
146
|
-
) ->
|
|
145
|
+
cls, v: list[tuple[str, int]] | None
|
|
146
|
+
) -> list[tuple[str, int]] | None:
|
|
147
147
|
if v is None:
|
|
148
148
|
return v
|
|
149
149
|
|
|
@@ -158,7 +158,7 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
158
158
|
|
|
159
159
|
@field_validator("error_message")
|
|
160
160
|
@classmethod
|
|
161
|
-
def error_message_must_be_valid(cls, v:
|
|
161
|
+
def error_message_must_be_valid(cls, v: str | None) -> str | None:
|
|
162
162
|
if v is None:
|
|
163
163
|
return v
|
|
164
164
|
if not isinstance(v, str):
|
|
@@ -167,7 +167,7 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
167
167
|
|
|
168
168
|
@field_validator("transformed_document_id")
|
|
169
169
|
@classmethod
|
|
170
|
-
def transformed_document_id_must_be_valid(cls, v:
|
|
170
|
+
def transformed_document_id_must_be_valid(cls, v: str | None) -> str | None:
|
|
171
171
|
if v is None:
|
|
172
172
|
return v
|
|
173
173
|
if not isinstance(v, str) or not v.strip():
|
|
@@ -178,8 +178,8 @@ class DocumentPolicyValidation(BaseModel):
|
|
|
178
178
|
|
|
179
179
|
@classmethod
|
|
180
180
|
def _validate_score_tuples(
|
|
181
|
-
cls, scores:
|
|
182
|
-
) ->
|
|
181
|
+
cls, scores: list[tuple[str, int]], field_name: str
|
|
182
|
+
) -> list[tuple[str, int]]:
|
|
183
183
|
"""Helper method to validate score tuple lists."""
|
|
184
184
|
validated_scores = []
|
|
185
185
|
query_ids_seen = set()
|
|
@@ -13,11 +13,11 @@ All domain models use Pydantic BaseModel for validation, serialization,
|
|
|
13
13
|
and type safety, following the patterns established in the sample project.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from pydantic import BaseModel, Field, field_validator
|
|
17
|
-
from typing import Optional, List, Tuple
|
|
18
16
|
from datetime import datetime, timezone
|
|
19
17
|
from enum import Enum
|
|
20
18
|
|
|
19
|
+
from pydantic import BaseModel, Field, field_validator
|
|
20
|
+
|
|
21
21
|
|
|
22
22
|
class PolicyStatus(str, Enum):
|
|
23
23
|
"""Status of a policy configuration."""
|
|
@@ -38,9 +38,11 @@ class Policy(BaseModel):
|
|
|
38
38
|
be applied to improve document quality before re-validation.
|
|
39
39
|
|
|
40
40
|
The policy operates in two modes:
|
|
41
|
+
|
|
41
42
|
1. Validation-only: Calculates scores and passes/fails based on criteria
|
|
42
43
|
2. Validation with transformation: Calculates scores, applies
|
|
43
44
|
transformations, then re-calculates scores for final pass/fail
|
|
45
|
+
|
|
44
46
|
"""
|
|
45
47
|
|
|
46
48
|
# Core policy identification
|
|
@@ -53,12 +55,12 @@ class Policy(BaseModel):
|
|
|
53
55
|
|
|
54
56
|
# Policy configuration
|
|
55
57
|
status: PolicyStatus = PolicyStatus.ACTIVE
|
|
56
|
-
validation_scores:
|
|
58
|
+
validation_scores: list[tuple[str, int]] = Field(
|
|
57
59
|
description="List of (knowledge_service_query_id, required_score) "
|
|
58
60
|
"tuples where required_score is between 0 and 100. All scores "
|
|
59
61
|
"must be met or exceeded for the policy to pass"
|
|
60
62
|
)
|
|
61
|
-
transformation_queries:
|
|
63
|
+
transformation_queries: list[str] | None = Field(
|
|
62
64
|
default=None,
|
|
63
65
|
description="Optional list of knowledge service query IDs for "
|
|
64
66
|
"transformations to apply before re-validation. If not provided "
|
|
@@ -67,10 +69,10 @@ class Policy(BaseModel):
|
|
|
67
69
|
|
|
68
70
|
# Policy metadata
|
|
69
71
|
version: str = Field(default="0.1.0", description="Policy version")
|
|
70
|
-
created_at:
|
|
72
|
+
created_at: datetime | None = Field(
|
|
71
73
|
default_factory=lambda: datetime.now(timezone.utc)
|
|
72
74
|
)
|
|
73
|
-
updated_at:
|
|
75
|
+
updated_at: datetime | None = Field(default=None)
|
|
74
76
|
|
|
75
77
|
@field_validator("policy_id")
|
|
76
78
|
@classmethod
|
|
@@ -96,8 +98,8 @@ class Policy(BaseModel):
|
|
|
96
98
|
@field_validator("validation_scores")
|
|
97
99
|
@classmethod
|
|
98
100
|
def validation_scores_must_be_valid(
|
|
99
|
-
cls, v:
|
|
100
|
-
) ->
|
|
101
|
+
cls, v: list[tuple[str, int]]
|
|
102
|
+
) -> list[tuple[str, int]]:
|
|
101
103
|
if not isinstance(v, list):
|
|
102
104
|
raise ValueError("Validation scores must be a list")
|
|
103
105
|
|
|
@@ -145,8 +147,8 @@ class Policy(BaseModel):
|
|
|
145
147
|
@field_validator("transformation_queries")
|
|
146
148
|
@classmethod
|
|
147
149
|
def transformation_queries_must_be_valid(
|
|
148
|
-
cls, v:
|
|
149
|
-
) ->
|
|
150
|
+
cls, v: list[str] | None
|
|
151
|
+
) -> list[str] | None:
|
|
150
152
|
if v is None:
|
|
151
153
|
return v
|
|
152
154
|
|
|
@@ -6,9 +6,10 @@ Policy domain objects with sensible defaults.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from datetime import datetime, timezone
|
|
9
|
+
|
|
9
10
|
from factory.base import Factory
|
|
10
|
-
from factory.faker import Faker
|
|
11
11
|
from factory.declarations import LazyFunction
|
|
12
|
+
from factory.faker import Faker
|
|
12
13
|
|
|
13
14
|
from julee.domain.models.policy import (
|
|
14
15
|
DocumentPolicyValidation,
|
|
@@ -13,14 +13,16 @@ Tests focus on:
|
|
|
13
13
|
- Edge cases and error conditions
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
import pytest
|
|
17
16
|
from datetime import datetime, timezone
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
18
19
|
from pydantic import ValidationError
|
|
19
20
|
|
|
20
21
|
from julee.domain.models.policy import (
|
|
21
22
|
DocumentPolicyValidation,
|
|
22
23
|
DocumentPolicyValidationStatus,
|
|
23
24
|
)
|
|
25
|
+
|
|
24
26
|
from .factories import DocumentPolicyValidationFactory
|
|
25
27
|
|
|
26
28
|
|
|
@@ -5,8 +5,9 @@ These tests verify the behavior of Policy domain objects,
|
|
|
5
5
|
including validation, serialization, and business logic.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import pytest
|
|
9
8
|
from datetime import datetime, timezone
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
10
11
|
from pydantic import ValidationError
|
|
11
12
|
|
|
12
13
|
from julee.domain.models.policy import (
|
|
@@ -6,14 +6,14 @@ Extract, Assemble, Publish workflow, following the Clean Architecture
|
|
|
6
6
|
patterns established in the Fun-Police framework.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from .base import BaseRepository
|
|
10
|
-
from .document import DocumentRepository
|
|
11
9
|
from .assembly import AssemblyRepository
|
|
12
10
|
from .assembly_specification import AssemblySpecificationRepository
|
|
11
|
+
from .base import BaseRepository
|
|
12
|
+
from .document import DocumentRepository
|
|
13
|
+
from .document_policy_validation import DocumentPolicyValidationRepository
|
|
13
14
|
from .knowledge_service_config import KnowledgeServiceConfigRepository
|
|
14
15
|
from .knowledge_service_query import KnowledgeServiceQueryRepository
|
|
15
16
|
from .policy import PolicyRepository
|
|
16
|
-
from .document_policy_validation import DocumentPolicyValidationRepository
|
|
17
17
|
|
|
18
18
|
__all__ = [
|
|
19
19
|
"BaseRepository",
|
|
@@ -27,8 +27,10 @@ In Temporal workflow contexts, these protocols are implemented by workflow
|
|
|
27
27
|
stubs that delegate to activities for durability and proper error handling.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
from typing import
|
|
30
|
+
from typing import Protocol, runtime_checkable
|
|
31
|
+
|
|
31
32
|
from julee.domain.models import Assembly
|
|
33
|
+
|
|
32
34
|
from .base import BaseRepository
|
|
33
35
|
|
|
34
36
|
|
|
@@ -30,9 +30,11 @@ stubs that delegate to activities for durability and proper error handling.
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
from typing import Protocol, runtime_checkable
|
|
33
|
+
|
|
33
34
|
from julee.domain.models.assembly_specification import (
|
|
34
35
|
AssemblySpecification,
|
|
35
36
|
)
|
|
37
|
+
|
|
36
38
|
from .base import BaseRepository
|
|
37
39
|
|
|
38
40
|
|
|
@@ -23,7 +23,8 @@ In Temporal workflow contexts, these protocols are implemented by workflow
|
|
|
23
23
|
stubs that delegate to activities for durability and proper error handling.
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
-
from typing import Protocol,
|
|
26
|
+
from typing import Protocol, TypeVar, runtime_checkable
|
|
27
|
+
|
|
27
28
|
from pydantic import BaseModel
|
|
28
29
|
|
|
29
30
|
# Type variable bound to Pydantic BaseModel for domain entities
|
|
@@ -42,7 +43,7 @@ class BaseRepository(Protocol[T]):
|
|
|
42
43
|
T: The domain entity type (must extend Pydantic BaseModel)
|
|
43
44
|
"""
|
|
44
45
|
|
|
45
|
-
async def get(self, entity_id: str) ->
|
|
46
|
+
async def get(self, entity_id: str) -> T | None:
|
|
46
47
|
"""Retrieve an entity by ID.
|
|
47
48
|
|
|
48
49
|
Args:
|
|
@@ -51,14 +52,16 @@ class BaseRepository(Protocol[T]):
|
|
|
51
52
|
Returns:
|
|
52
53
|
Entity if found, None otherwise
|
|
53
54
|
|
|
54
|
-
Implementation Notes
|
|
55
|
+
.. rubric:: Implementation Notes
|
|
56
|
+
|
|
55
57
|
- Must be idempotent: multiple calls return same result
|
|
56
58
|
- Should handle missing entities gracefully (return None)
|
|
57
59
|
- Loads complete entity with all relationships
|
|
60
|
+
|
|
58
61
|
"""
|
|
59
62
|
...
|
|
60
63
|
|
|
61
|
-
async def get_many(self, entity_ids:
|
|
64
|
+
async def get_many(self, entity_ids: list[str]) -> dict[str, T | None]:
|
|
62
65
|
"""Retrieve multiple entities by ID.
|
|
63
66
|
|
|
64
67
|
Args:
|
|
@@ -67,7 +70,8 @@ class BaseRepository(Protocol[T]):
|
|
|
67
70
|
Returns:
|
|
68
71
|
Dict mapping entity_id to entity (or None if not found)
|
|
69
72
|
|
|
70
|
-
Implementation Notes
|
|
73
|
+
.. rubric:: Implementation Notes
|
|
74
|
+
|
|
71
75
|
- Must be idempotent: multiple calls return same result
|
|
72
76
|
- Should handle missing entities gracefully (return None for missing)
|
|
73
77
|
- Implementations may optimize with batch operations or fall back
|
|
@@ -75,10 +79,12 @@ class BaseRepository(Protocol[T]):
|
|
|
75
79
|
- Keys in returned dict correspond exactly to input entity_ids
|
|
76
80
|
- Missing entities have None values in the returned dict
|
|
77
81
|
|
|
78
|
-
Workflow Context
|
|
82
|
+
.. rubric:: Workflow Context
|
|
83
|
+
|
|
79
84
|
In Temporal workflows, this method is implemented as an activity
|
|
80
85
|
to ensure batch operations are durably stored and consistent
|
|
81
86
|
across workflow replays.
|
|
87
|
+
|
|
82
88
|
"""
|
|
83
89
|
...
|
|
84
90
|
|
|
@@ -88,38 +94,46 @@ class BaseRepository(Protocol[T]):
|
|
|
88
94
|
Args:
|
|
89
95
|
entity: Complete entity to save
|
|
90
96
|
|
|
91
|
-
Implementation Notes
|
|
97
|
+
.. rubric:: Implementation Notes
|
|
98
|
+
|
|
92
99
|
- Must be idempotent: saving same entity state is safe
|
|
93
100
|
- Should update the updated_at timestamp
|
|
94
101
|
- Must save complete entity with all relationships
|
|
95
102
|
- Handles both new entities and updates to existing ones
|
|
103
|
+
|
|
96
104
|
"""
|
|
97
105
|
...
|
|
98
106
|
|
|
99
|
-
async def list_all(self) ->
|
|
107
|
+
async def list_all(self) -> list[T]:
|
|
100
108
|
"""List all entities.
|
|
101
109
|
|
|
102
110
|
Returns:
|
|
103
111
|
List of all entities in the repository
|
|
104
112
|
|
|
105
|
-
Implementation Notes
|
|
113
|
+
.. rubric:: Implementation Notes
|
|
114
|
+
|
|
106
115
|
- Must be idempotent: multiple calls return same result
|
|
107
116
|
- Returns empty list if no entities exist
|
|
108
117
|
- Should return entities in a consistent order (e.g., by ID)
|
|
109
118
|
- For large datasets, consider pagination at the use case level
|
|
110
119
|
|
|
111
|
-
Workflow Context
|
|
120
|
+
.. rubric:: Workflow Context
|
|
121
|
+
|
|
112
122
|
In Temporal workflows, this method is implemented as an activity
|
|
113
123
|
to ensure the list operation is durably stored and consistent
|
|
114
124
|
across workflow replays.
|
|
115
125
|
|
|
116
|
-
Default Implementation
|
|
126
|
+
.. rubric:: Default Implementation
|
|
127
|
+
|
|
117
128
|
Base protocol provides a default that returns empty list.
|
|
118
129
|
Repository implementations should override this method as needed.
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
.. note::
|
|
132
|
+
|
|
133
|
+
This default implementation returns empty list to avoid
|
|
134
|
+
breaking existing repositories. Specific repositories should
|
|
135
|
+
implement proper list_all() functionality as needed.
|
|
136
|
+
|
|
123
137
|
"""
|
|
124
138
|
return []
|
|
125
139
|
|
|
@@ -132,15 +146,18 @@ class BaseRepository(Protocol[T]):
|
|
|
132
146
|
Returns:
|
|
133
147
|
Unique entity ID string
|
|
134
148
|
|
|
135
|
-
Implementation Notes
|
|
149
|
+
.. rubric:: Implementation Notes
|
|
150
|
+
|
|
136
151
|
- Must generate globally unique identifiers
|
|
137
152
|
- May use UUIDs, database sequences, or distributed ID generators
|
|
138
153
|
- Should be fast and reliable
|
|
139
154
|
- Failure here should be rare but handled gracefully
|
|
140
155
|
|
|
141
|
-
Workflow Context
|
|
156
|
+
.. rubric:: Workflow Context
|
|
157
|
+
|
|
142
158
|
In Temporal workflows, this method is implemented as an activity
|
|
143
159
|
to ensure the generated ID is durably stored and consistent
|
|
144
160
|
across workflow replays.
|
|
161
|
+
|
|
145
162
|
"""
|
|
146
163
|
...
|
|
@@ -29,8 +29,10 @@ In Temporal workflow contexts, these protocols are implemented by workflow
|
|
|
29
29
|
stubs that delegate to activities for durability and proper error handling.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
from typing import
|
|
32
|
+
from typing import Protocol, runtime_checkable
|
|
33
|
+
|
|
33
34
|
from julee.domain.models import Document
|
|
35
|
+
|
|
34
36
|
from .base import BaseRepository
|
|
35
37
|
|
|
36
38
|
|
|
@@ -29,8 +29,10 @@ In Temporal workflow contexts, these protocols are implemented by workflow
|
|
|
29
29
|
stubs that delegate to activities for durability and proper error handling.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
from typing import
|
|
32
|
+
from typing import Protocol, runtime_checkable
|
|
33
|
+
|
|
33
34
|
from julee.domain.models.policy import DocumentPolicyValidation
|
|
35
|
+
|
|
34
36
|
from .base import BaseRepository
|
|
35
37
|
|
|
36
38
|
|
|
@@ -31,9 +31,11 @@ stubs that delegate to activities for durability and proper error handling.
|
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
33
|
from typing import Protocol, runtime_checkable
|
|
34
|
+
|
|
34
35
|
from julee.domain.models.knowledge_service_config import (
|
|
35
36
|
KnowledgeServiceConfig,
|
|
36
37
|
)
|
|
38
|
+
|
|
37
39
|
from .base import BaseRepository
|
|
38
40
|
|
|
39
41
|
|
|
@@ -29,8 +29,10 @@ In Temporal workflow contexts, these protocols are implemented by workflow
|
|
|
29
29
|
stubs that delegate to activities for durability and proper error handling.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
from typing import
|
|
32
|
+
from typing import Protocol, runtime_checkable
|
|
33
|
+
|
|
33
34
|
from julee.domain.models import Policy
|
|
35
|
+
|
|
34
36
|
from .base import BaseRepository
|
|
35
37
|
|
|
36
38
|
|
|
@@ -7,8 +7,9 @@ following the patterns established in the sample use cases.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
|
+
from collections.abc import Awaitable, Callable
|
|
10
11
|
from functools import wraps
|
|
11
|
-
from typing import Any,
|
|
12
|
+
from typing import Any, TypeVar
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
|
|
@@ -17,7 +18,7 @@ F = TypeVar("F", bound=Callable[..., Awaitable[Any]])
|
|
|
17
18
|
|
|
18
19
|
def try_use_case_step(
|
|
19
20
|
step_name: str,
|
|
20
|
-
extra_context:
|
|
21
|
+
extra_context: dict[str, Any] | None = None,
|
|
21
22
|
) -> Callable[[F], F]:
|
|
22
23
|
"""
|
|
23
24
|
Decorator that wraps use case steps with consistent error handling and
|