fairagro-middleware-shared 8.6.2__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.
Files changed (26) hide show
  1. fairagro_middleware_shared-8.6.2/.gitignore +229 -0
  2. fairagro_middleware_shared-8.6.2/PKG-INFO +64 -0
  3. fairagro_middleware_shared-8.6.2/README.md +51 -0
  4. fairagro_middleware_shared-8.6.2/pyproject.toml +33 -0
  5. fairagro_middleware_shared-8.6.2/src/middleware/shared/__init__.py +1 -0
  6. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/__init__.py +30 -0
  7. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/common/__init__.py +1 -0
  8. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/common/models.py +104 -0
  9. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/py.typed +0 -0
  10. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v1/__init__.py +1 -0
  11. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v1/models.py +74 -0
  12. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v2/__init__.py +1 -0
  13. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v2/models.py +38 -0
  14. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v3/__init__.py +1 -0
  15. fairagro_middleware_shared-8.6.2/src/middleware/shared/api_models/v3/models.py +106 -0
  16. fairagro_middleware_shared-8.6.2/src/middleware/shared/config/__init__.py +1 -0
  17. fairagro_middleware_shared-8.6.2/src/middleware/shared/config/config_base.py +96 -0
  18. fairagro_middleware_shared-8.6.2/src/middleware/shared/config/config_wrapper.py +372 -0
  19. fairagro_middleware_shared-8.6.2/src/middleware/shared/config/logging.py +25 -0
  20. fairagro_middleware_shared-8.6.2/src/middleware/shared/py.typed +0 -0
  21. fairagro_middleware_shared-8.6.2/src/middleware/shared/tracing.py +154 -0
  22. fairagro_middleware_shared-8.6.2/tests/unit/test_api_models.py +52 -0
  23. fairagro_middleware_shared-8.6.2/tests/unit/test_config_base.py +25 -0
  24. fairagro_middleware_shared-8.6.2/tests/unit/test_config_wrapper.py +288 -0
  25. fairagro_middleware_shared-8.6.2/tests/unit/test_logging.py +96 -0
  26. fairagro_middleware_shared-8.6.2/tests/unit/test_tracing.py +155 -0
@@ -0,0 +1,229 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Allow encrypted .env.integration.enc but ignore any unencrypted .env files
148
+ !.env.integration.enc
149
+
150
+ # Spyder project settings
151
+ .spyderproject
152
+ .spyproject
153
+
154
+ # Rope project settings
155
+ .ropeproject
156
+
157
+ # mkdocs documentation
158
+ /site
159
+
160
+ # mypy
161
+ .mypy_cache/
162
+ .dmypy.json
163
+ dmypy.json
164
+
165
+ # Pyre type checker
166
+ .pyre/
167
+
168
+ # pytype static type analyzer
169
+ .pytype/
170
+
171
+ # Cython debug symbols
172
+ cython_debug/
173
+
174
+ # PyCharm
175
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
176
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
177
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
178
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
179
+ #.idea/
180
+
181
+ # Abstra
182
+ # Abstra is an AI-powered process automation framework.
183
+ # Ignore directories containing user credentials, local state, and settings.
184
+ # Learn more at https://abstra.io/docs
185
+ .abstra/
186
+
187
+ # Visual Studio Code
188
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
189
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
190
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
191
+ # you could uncomment the following to ignore the entire vscode folder
192
+ # .vscode/
193
+
194
+ # Ruff stuff:
195
+ .ruff_cache/
196
+
197
+ # PyPI configuration file
198
+ .pypirc
199
+
200
+ # Cursor
201
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
202
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
203
+ # refer to https://docs.cursor.com/context/ignore-files
204
+ .cursorignore
205
+ .cursorindexingignore
206
+
207
+ # Marimo
208
+ marimo/_static/
209
+ marimo/_lsp/
210
+ __marimo__/
211
+
212
+ scratch/
213
+ **/*.csv
214
+ **/*.stats
215
+
216
+ **/*.decrypted.*
217
+
218
+ # Cryptographic keys and certificates for testing that are not meant to be committed
219
+ helmchart/**/*.crt
220
+ helmchart/**/*.key
221
+ helmchart/**/*.csr
222
+ helmchart/**/*.srl
223
+ helmchart/**/server.conf
224
+ helmchart/**/client_ext.conf
225
+
226
+ # ggshield cache
227
+ .cache_ggshield
228
+
229
+ docker/Dockerfile.api.bak
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: fairagro-middleware-shared
3
+ Version: 8.6.2
4
+ Summary: The FAIRagro advanced middleware shared components
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: opentelemetry-api>=1.26.0
7
+ Requires-Dist: opentelemetry-exporter-otlp>=1.26.0
8
+ Requires-Dist: opentelemetry-instrumentation-logging>=0.47b0
9
+ Requires-Dist: opentelemetry-sdk>=1.26.0
10
+ Requires-Dist: pydantic>=2.12.5
11
+ Requires-Dist: pyyaml>=6.0.3
12
+ Description-Content-Type: text/markdown
13
+
14
+ # FAIRagro Advanced Middleware - Shared Components
15
+
16
+ This package contains shared utilities and components used across the FAIRagro Advanced Middleware system.
17
+
18
+ ## Overview
19
+
20
+ The `shared` package provides:
21
+
22
+ - **Configuration Management**: Base classes and utilities for configuration handling
23
+ - **Common Models**: Pydantic models used across multiple middleware components
24
+ - **Utilities**: Helper functions and classes for common operations
25
+
26
+ ## Components
27
+
28
+ ### Configuration (`middleware.shared.config`)
29
+
30
+ Configuration utilities including:
31
+
32
+ - `ConfigWrapper`: Base class for configuration management
33
+ - Environment variable handling
34
+ - Configuration validation with Pydantic
35
+
36
+ ### Models
37
+
38
+ Shared Pydantic models for data validation and serialization across the middleware.
39
+
40
+ ## Usage
41
+
42
+ This package is used as a dependency by other middleware components:
43
+
44
+ - `api`: The main REST API
45
+ - `api_client`: Client library for API interaction
46
+ - `inspire_to_arc`: INSPIRE metadata to ARC conversion
47
+
48
+ ## Dependencies
49
+
50
+ - `pydantic>=2.12.4`: Data validation and settings management
51
+
52
+ ## Development
53
+
54
+ Install in development mode:
55
+
56
+ ```bash
57
+ uv sync --package shared
58
+ ```
59
+
60
+ Run tests:
61
+
62
+ ```bash
63
+ uv run pytest middleware/shared/tests
64
+ ```
@@ -0,0 +1,51 @@
1
+ # FAIRagro Advanced Middleware - Shared Components
2
+
3
+ This package contains shared utilities and components used across the FAIRagro Advanced Middleware system.
4
+
5
+ ## Overview
6
+
7
+ The `shared` package provides:
8
+
9
+ - **Configuration Management**: Base classes and utilities for configuration handling
10
+ - **Common Models**: Pydantic models used across multiple middleware components
11
+ - **Utilities**: Helper functions and classes for common operations
12
+
13
+ ## Components
14
+
15
+ ### Configuration (`middleware.shared.config`)
16
+
17
+ Configuration utilities including:
18
+
19
+ - `ConfigWrapper`: Base class for configuration management
20
+ - Environment variable handling
21
+ - Configuration validation with Pydantic
22
+
23
+ ### Models
24
+
25
+ Shared Pydantic models for data validation and serialization across the middleware.
26
+
27
+ ## Usage
28
+
29
+ This package is used as a dependency by other middleware components:
30
+
31
+ - `api`: The main REST API
32
+ - `api_client`: Client library for API interaction
33
+ - `inspire_to_arc`: INSPIRE metadata to ARC conversion
34
+
35
+ ## Dependencies
36
+
37
+ - `pydantic>=2.12.4`: Data validation and settings management
38
+
39
+ ## Development
40
+
41
+ Install in development mode:
42
+
43
+ ```bash
44
+ uv sync --package shared
45
+ ```
46
+
47
+ Run tests:
48
+
49
+ ```bash
50
+ uv run pytest middleware/shared/tests
51
+ ```
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "fairagro-middleware-shared"
3
+ dynamic = ["version"]
4
+ description = "The FAIRagro advanced middleware shared components"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "pydantic>=2.12.5",
9
+ "pyyaml>=6.0.3",
10
+ "opentelemetry-api>=1.26.0",
11
+ "opentelemetry-sdk>=1.26.0",
12
+ "opentelemetry-exporter-otlp>=1.26.0",
13
+ "opentelemetry-instrumentation-logging>=0.47b0",
14
+ ]
15
+
16
+ [tool.hatch.build.targets.wheel]
17
+ packages = ["src/middleware"]
18
+
19
+ [tool.ruff]
20
+ extend = "../../pyproject.toml"
21
+
22
+ [tool.hatch.version]
23
+ source = "vcs"
24
+ raw-options = { root = "../..", fallback_version = "0.0.0", tag_regex = "^(?:v|.*-(?:chart|docker)-v)(?P<version>\\d+\\.\\d+\\.\\d+)(?:$|[-+].*)" }
25
+
26
+ [build-system]
27
+ requires = ["hatchling", "hatch-vcs"]
28
+ build-backend = "hatchling.build"
29
+
30
+ [dependency-groups]
31
+ dev = [
32
+ "types-pyyaml>=6.0.12.20250915",
33
+ ]
@@ -0,0 +1 @@
1
+ """Contains same generic utility functions."""
@@ -0,0 +1,30 @@
1
+ """FAIRagro Middleware API Models package.
2
+
3
+ Backward compatibility layer for refactored shared models.
4
+ """
5
+
6
+ from .common import models as common
7
+ from .v1 import models as v1
8
+ from .v2 import models as v2
9
+
10
+ # Common / Shared
11
+ ArcStatus = common.ArcStatus
12
+ TaskStatus = common.TaskStatus
13
+ ApiResponse = common.ApiResponse
14
+ ArcResponse = common.ArcResponse # V1/V2 common
15
+
16
+ # V1 Models
17
+ LivenessResponse = v1.LivenessResponse
18
+ HealthResponse = v1.HealthResponse
19
+ CreateOrUpdateArcsRequest = v1.CreateOrUpdateArcsRequest
20
+ CreateOrUpdateArcsResponse = v1.CreateOrUpdateArcsResponse
21
+ GetTaskStatusResponse = v1.GetTaskStatusResponse
22
+ WhoamiResponse = v1.WhoamiResponse
23
+ ArcTaskTicket = v1.ArcTaskTicket
24
+
25
+ # V2 Models
26
+ HealthResponseV2 = v2.HealthResponse
27
+ CreateOrUpdateArcRequest = v2.CreateOrUpdateArcRequest
28
+ CreateOrUpdateArcResponse = v2.CreateOrUpdateArcResponse
29
+ ArcOperationResult = v2.ArcOperationResult
30
+ GetTaskStatusResponseV2 = v2.GetTaskStatusResponse
@@ -0,0 +1,104 @@
1
+ """Common models and enums shared across API versions."""
2
+
3
+ from enum import StrEnum
4
+ from typing import Annotated
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+
9
+ class ArcStatus(StrEnum):
10
+ """Enumeration of possible ARC status values."""
11
+
12
+ CREATED = "created"
13
+ UPDATED = "updated"
14
+ DELETED = "deleted"
15
+ REQUESTED = "requested"
16
+
17
+
18
+ class TaskStatus(StrEnum):
19
+ """Enumeration of possible task states.
20
+
21
+ Values match Celery task states.
22
+ """
23
+
24
+ PENDING = "PENDING"
25
+ STARTED = "STARTED"
26
+ SUCCESS = "SUCCESS"
27
+ FAILURE = "FAILURE"
28
+ RETRY = "RETRY"
29
+ REVOKED = "REVOKED"
30
+
31
+
32
+ class ArcLifecycleStatus(StrEnum):
33
+ """ARC lifecycle status in the system."""
34
+
35
+ ACTIVE = "ACTIVE" # Normal active state
36
+ PROCESSING = "PROCESSING" # Git workflow in progress
37
+ MISSING = "MISSING" # Not seen in recent harvest
38
+ DELETED = "DELETED" # Soft-deleted (not physically removed)
39
+ INVALID = "INVALID" # Validation failed
40
+
41
+
42
+ class ArcEventType(StrEnum):
43
+ """Types of events in the ARC event log."""
44
+
45
+ # Lifecycle events
46
+ ARC_CREATED = "ARC_CREATED"
47
+ ARC_UPDATED = "ARC_UPDATED"
48
+ ARC_NOT_SEEN = "ARC_NOT_SEEN"
49
+ ARC_MARKED_MISSING = "ARC_MARKED_MISSING"
50
+ ARC_MARKED_DELETED = "ARC_MARKED_DELETED"
51
+ ARC_RESTORED = "ARC_RESTORED" # Reappeared after being marked missing/deleted
52
+ ARC_NOT_CHANGED = "ARC_NOT_CHANGED" # Explicitly tracking no-change events (if needed)
53
+
54
+ # Git workflow events
55
+ GIT_QUEUED = "GIT_QUEUED"
56
+ GIT_PROCESSING = "GIT_PROCESSING"
57
+ GIT_PUSH_SUCCESS = "GIT_PUSH_SUCCESS"
58
+ GIT_PUSH_FAILED = "GIT_PUSH_FAILED"
59
+
60
+ # Validation events
61
+ VALIDATION_WARNING = "VALIDATION_WARNING"
62
+ VALIDATION_ERROR = "VALIDATION_ERROR"
63
+ VALIDATION_SUCCESS = "VALIDATION_SUCCESS"
64
+
65
+ # Operator actions
66
+ OPERATOR_NOTE = "OPERATOR_NOTE"
67
+ MANUAL_DELETION = "MANUAL_DELETION"
68
+
69
+
70
+ class HarvestStatus(StrEnum):
71
+ """Harvest run status."""
72
+
73
+ RUNNING = "RUNNING"
74
+ COMPLETED = "COMPLETED"
75
+ FAILED = "FAILED"
76
+ CANCELLED = "CANCELLED"
77
+
78
+
79
+ class ApiResponse(BaseModel):
80
+ """Base response model for business logic operations."""
81
+
82
+ client_id: Annotated[
83
+ str | None,
84
+ Field(
85
+ description="Client identifier which is the CN from the client certificate, "
86
+ "or 'unknown' if client certificates are not required",
87
+ ),
88
+ ] = None
89
+ message: Annotated[str, Field(description="Response message")] = ""
90
+
91
+
92
+ class ArcResponse(BaseModel):
93
+ """Response model for individual ARC operations."""
94
+
95
+ id: Annotated[str, Field(description="ARC identifier, as hashed value of the original identifier and RDI")]
96
+ status: Annotated[ArcStatus, Field(description="Status of the ARC operation")]
97
+ timestamp: Annotated[str, Field(description="Timestamp of the ARC operation in ISO 8601 format")]
98
+
99
+
100
+ class ArcOperationResult(ApiResponse):
101
+ """Response model for the actual result of a single ARC operation."""
102
+
103
+ rdi: Annotated[str, Field(description="Research Data Infrastructure identifier the ARC belongs to")]
104
+ arc: Annotated[ArcResponse, Field(description="ARC response for the operation")]
@@ -0,0 +1,74 @@
1
+ """V1 API Models."""
2
+
3
+ from typing import Annotated
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from ..common.models import ApiResponse, ArcResponse
8
+
9
+
10
+ class LivenessResponse(BaseModel):
11
+ """Response model for liveness check."""
12
+
13
+ message: Annotated[str, Field(description="Liveness message")] = "ok"
14
+
15
+
16
+ class HealthResponse(BaseModel):
17
+ """Response model for health check including backend status."""
18
+
19
+ status: Annotated[str, Field(description="Overall service status (ok/error)")] = "ok"
20
+ redis_reachable: Annotated[
21
+ bool,
22
+ Field(
23
+ description="[DEPRECATED] Kept for backward compatibility. Always True as Redis is no longer used.",
24
+ deprecated=True,
25
+ ),
26
+ ] = True
27
+ rabbitmq_reachable: Annotated[bool, Field(description="True if RabbitMQ is reachable")]
28
+
29
+
30
+ class WhoamiResponse(ApiResponse):
31
+ """Response model for whoami operation."""
32
+
33
+ accessible_rdis: Annotated[
34
+ list[str], Field(description="List of Research Data Infrastructures the client is authorized for")
35
+ ]
36
+
37
+
38
+ class ArcTaskTicket(ApiResponse):
39
+ """Response model for a newly created async task ticket."""
40
+
41
+ rdi: Annotated[str, Field(description="Research Data Infrastructure identifier the ARC belongs to")]
42
+ task_id: Annotated[str, Field(description="Async task ID")]
43
+
44
+
45
+ class CreateOrUpdateArcsRequest(BaseModel):
46
+ """Request model for creating or updating ARCs."""
47
+
48
+ rdi: Annotated[str, Field(description="Research Data Infrastructure identifier")]
49
+ arcs: Annotated[list[dict], Field(description="List of ARC definitions in RO-Crate JSON format")]
50
+
51
+
52
+ class CreateOrUpdateArcsResponse(ApiResponse):
53
+ """Response model for create or update ARC operations (Task Ticket or Result)."""
54
+
55
+ rdi: Annotated[str | None, Field(description="Research Data Infrastructure identifier the ARCs belong to")] = None
56
+ arcs: Annotated[list[ArcResponse], Field(description="List of ARC responses for the operation")] = Field(
57
+ default_factory=list
58
+ )
59
+
60
+ # Async task fields
61
+ task_id: Annotated[str | None, Field(description="The ID of the background task processing the ARC")] = None
62
+ status: Annotated[str | None, Field(description="The status of the task submission")] = None
63
+
64
+
65
+ class GetTaskStatusResponse(BaseModel):
66
+ """Response model for task status."""
67
+
68
+ task_id: Annotated[str, Field(description="The ID of the background task")]
69
+ status: Annotated[str, Field(description="The status of the task")]
70
+ result: Annotated[
71
+ CreateOrUpdateArcsResponse | None,
72
+ Field(description="The result of the task if completed"),
73
+ ] = None
74
+ error: Annotated[str | None, Field(description="Error message if task failed")] = None
@@ -0,0 +1,38 @@
1
+ """V2 API Models."""
2
+
3
+ from typing import Annotated
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from ..common.models import ApiResponse, ArcOperationResult, TaskStatus
8
+
9
+
10
+ class HealthResponse(BaseModel):
11
+ """Response model for health check v2."""
12
+
13
+ status: Annotated[str, Field(description="Overall service status (ok/error)")] = "ok"
14
+ services: Annotated[dict[str, bool], Field(description="Dictionary of service statuses")]
15
+
16
+
17
+ class CreateOrUpdateArcRequest(BaseModel):
18
+ """Request model for creating or updating a single ARC."""
19
+
20
+ rdi: Annotated[str, Field(description="Research Data Infrastructure identifier")]
21
+ arc: Annotated[dict, Field(description="ARC definition in RO-Crate JSON format")]
22
+
23
+
24
+ class CreateOrUpdateArcResponse(ApiResponse):
25
+ """Response model for create or update a single ARC operation ticket."""
26
+
27
+ task_id: Annotated[str, Field(description="The ID of the background task")]
28
+ status: Annotated[TaskStatus, Field(description="The status of the task")]
29
+
30
+
31
+ class GetTaskStatusResponse(ApiResponse):
32
+ """Response model for task status."""
33
+
34
+ status: Annotated[TaskStatus, Field(description="The status of the task")]
35
+ result: Annotated[
36
+ ArcOperationResult | None,
37
+ Field(description="The result of the task if completed"),
38
+ ] = None