destiny_sdk 0.1.0__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.
- destiny_sdk/__init__.py +23 -0
- destiny_sdk/auth.py +204 -0
- destiny_sdk/client.py +113 -0
- destiny_sdk/core.py +35 -0
- destiny_sdk/enhancements.py +363 -0
- destiny_sdk/identifiers.py +107 -0
- destiny_sdk/imports.py +253 -0
- destiny_sdk/py.typed +0 -0
- destiny_sdk/references.py +45 -0
- destiny_sdk/robots.py +337 -0
- destiny_sdk/visibility.py +24 -0
- destiny_sdk-0.1.0.dist-info/LICENSE +51 -0
- destiny_sdk-0.1.0.dist-info/METADATA +92 -0
- destiny_sdk-0.1.0.dist-info/RECORD +15 -0
- destiny_sdk-0.1.0.dist-info/WHEEL +4 -0
destiny_sdk/imports.py
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Import process classes for the Destiny SDK."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from enum import StrEnum, auto
|
|
5
|
+
|
|
6
|
+
from pydantic import (
|
|
7
|
+
UUID4,
|
|
8
|
+
BaseModel,
|
|
9
|
+
Field,
|
|
10
|
+
HttpUrl,
|
|
11
|
+
PastDatetime,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ImportRecordStatus(StrEnum):
|
|
16
|
+
"""
|
|
17
|
+
Describes the status of an import record.
|
|
18
|
+
|
|
19
|
+
- `created`: Created, but no processing has started.
|
|
20
|
+
- `started`: Processing has started on the batch.
|
|
21
|
+
- `completed`: Processing has been completed.
|
|
22
|
+
- `cancelled`: Processing was cancelled by calling the API.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
CREATED = auto()
|
|
26
|
+
STARTED = auto()
|
|
27
|
+
COMPLETED = auto()
|
|
28
|
+
CANCELLED = auto()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ImportBatchStatus(StrEnum):
|
|
32
|
+
"""
|
|
33
|
+
Describes the status of an import batch.
|
|
34
|
+
|
|
35
|
+
- `created`: Created, but no processing has started.
|
|
36
|
+
- `started`: Processing has started on the batch.
|
|
37
|
+
- `completed`: Processing has been completed.
|
|
38
|
+
- `cancelled`: Processing was cancelled by calling the API.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
CREATED = auto()
|
|
42
|
+
STARTED = auto()
|
|
43
|
+
FAILED = auto()
|
|
44
|
+
COMPLETED = auto()
|
|
45
|
+
CANCELLED = auto()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CollisionStrategy(StrEnum):
|
|
49
|
+
"""
|
|
50
|
+
The strategy to use when an identifier collision is detected.
|
|
51
|
+
|
|
52
|
+
Identifier collisions are detected on ``identifier_type`` and ``identifier``
|
|
53
|
+
(and ``other_identifier_name`` where relevant) already present in the database.
|
|
54
|
+
|
|
55
|
+
Enhancement collisions are detected on an entry with matching ``enhancement_type``
|
|
56
|
+
and ``source`` already being present on the collided reference.
|
|
57
|
+
|
|
58
|
+
- `discard`: Do nothing with the incoming reference.
|
|
59
|
+
- `fail`: Do nothing with the incoming reference and mark it as failed. This
|
|
60
|
+
allows the importing process to "follow up" on the failure.
|
|
61
|
+
- `merge_aggressive`: Prioritize the incoming reference's identifiers and
|
|
62
|
+
enhancements in the merge.
|
|
63
|
+
- `merge_defensive`: Prioritize the existing reference's identifiers and
|
|
64
|
+
enhancements in the merge.
|
|
65
|
+
- `append`: Performs an aggressive merge of identifiers, and an append of
|
|
66
|
+
enhancements.
|
|
67
|
+
- `overwrite`: Performs an aggressive merge of identifiers, and an overwrite of
|
|
68
|
+
enhancements (deleting existing and recreating what is imported). This should
|
|
69
|
+
be used sparingly and carefully.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
DISCARD = auto()
|
|
73
|
+
FAIL = auto()
|
|
74
|
+
MERGE_AGGRESSIVE = auto()
|
|
75
|
+
MERGE_DEFENSIVE = auto()
|
|
76
|
+
APPEND = auto()
|
|
77
|
+
OVERWRITE = auto()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class ImportResultStatus(StrEnum):
|
|
81
|
+
"""
|
|
82
|
+
Describes the status of an import result.
|
|
83
|
+
|
|
84
|
+
- `created`: Created, but no processing has started.
|
|
85
|
+
- `started`: The reference is currently being processed.
|
|
86
|
+
- `completed`: The reference has been created.
|
|
87
|
+
- `partially_failed`: The reference was created but one or more enhancements or
|
|
88
|
+
identifiers failed to be added. See the result's `failure_details` field for
|
|
89
|
+
more information.
|
|
90
|
+
- `failed`: The reference failed to be created. See the result's `failure_details`
|
|
91
|
+
field for more information.
|
|
92
|
+
- `cancelled`: Processing was cancelled by calling the API.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
CREATED = auto()
|
|
96
|
+
STARTED = auto()
|
|
97
|
+
COMPLETED = auto()
|
|
98
|
+
CANCELLED = auto()
|
|
99
|
+
PARTIALLY_FAILED = auto()
|
|
100
|
+
FAILED = auto()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class _ImportRecordBase(BaseModel):
|
|
104
|
+
"""Base import record class."""
|
|
105
|
+
|
|
106
|
+
search_string: str | None = Field(
|
|
107
|
+
default=None,
|
|
108
|
+
description="The search string used to produce this import",
|
|
109
|
+
)
|
|
110
|
+
searched_at: PastDatetime = Field(
|
|
111
|
+
default_factory=lambda: datetime.datetime.now(tz=datetime.UTC),
|
|
112
|
+
description="""
|
|
113
|
+
The timestamp (including timezone) at which the search which produced
|
|
114
|
+
this import was conducted. If no timezone is included, the timestamp
|
|
115
|
+
is assumed to be in UTC.
|
|
116
|
+
""",
|
|
117
|
+
)
|
|
118
|
+
processor_name: str = Field(
|
|
119
|
+
description="The name of the processor that is importing the data."
|
|
120
|
+
)
|
|
121
|
+
processor_version: str = Field(
|
|
122
|
+
description="The version of the processor that is importing the data."
|
|
123
|
+
)
|
|
124
|
+
notes: str | None = Field(
|
|
125
|
+
default=None,
|
|
126
|
+
description="""
|
|
127
|
+
Any additional notes regarding the import (eg. reason for importing, known
|
|
128
|
+
issues).
|
|
129
|
+
""",
|
|
130
|
+
)
|
|
131
|
+
expected_reference_count: int = Field(
|
|
132
|
+
description="""
|
|
133
|
+
The number of references expected to be included in this import.
|
|
134
|
+
-1 is accepted if the number is unknown.
|
|
135
|
+
""",
|
|
136
|
+
ge=-1,
|
|
137
|
+
)
|
|
138
|
+
source_name: str = Field(
|
|
139
|
+
description="The source of the reference being imported (eg. Open Alex)"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ImportRecordIn(_ImportRecordBase):
|
|
144
|
+
"""Input for creating an import record."""
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ImportRecordRead(_ImportRecordBase):
|
|
148
|
+
"""Core import record class."""
|
|
149
|
+
|
|
150
|
+
id: UUID4 = Field(
|
|
151
|
+
description="The ID of the import record",
|
|
152
|
+
)
|
|
153
|
+
status: ImportRecordStatus = Field(
|
|
154
|
+
ImportRecordStatus.CREATED,
|
|
155
|
+
description="The status of the import record",
|
|
156
|
+
)
|
|
157
|
+
batches: list["ImportBatchRead"] | None = Field(
|
|
158
|
+
default=None,
|
|
159
|
+
description="A list of batches for the import record",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class _ImportBatchBase(BaseModel):
|
|
164
|
+
"""The base class for import batches."""
|
|
165
|
+
|
|
166
|
+
collision_strategy: CollisionStrategy = Field(
|
|
167
|
+
default=CollisionStrategy.FAIL,
|
|
168
|
+
description="""
|
|
169
|
+
The strategy to use for each reference when an identifier collision occurs.
|
|
170
|
+
Default is `fail`, which allows the importing process to "follow up" on the collision.
|
|
171
|
+
""",
|
|
172
|
+
)
|
|
173
|
+
storage_url: HttpUrl = Field(
|
|
174
|
+
description="""
|
|
175
|
+
The URL at which the set of references for this batch are stored. The file is a jsonl
|
|
176
|
+
with each line formatted according to
|
|
177
|
+
:class:`ReferenceFileInput <libs.sdk.src.destiny_sdk.references.ReferenceFileInput>`.
|
|
178
|
+
""",
|
|
179
|
+
)
|
|
180
|
+
callback_url: HttpUrl | None = Field(
|
|
181
|
+
default=None,
|
|
182
|
+
description="""
|
|
183
|
+
The URL to which the processor should send a callback when the batch has been processed.
|
|
184
|
+
""",
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class ImportBatchIn(_ImportBatchBase):
|
|
189
|
+
"""Input for creating an import batch."""
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class ImportBatchRead(_ImportBatchBase):
|
|
193
|
+
"""Core import batch class."""
|
|
194
|
+
|
|
195
|
+
id: UUID4 = Field(
|
|
196
|
+
description="The ID of the import batch",
|
|
197
|
+
)
|
|
198
|
+
status: ImportBatchStatus = Field(
|
|
199
|
+
default=ImportBatchStatus.CREATED, description="The status of the batch."
|
|
200
|
+
)
|
|
201
|
+
import_record_id: UUID4 = Field(
|
|
202
|
+
description="The ID of the import record this batch is associated with"
|
|
203
|
+
)
|
|
204
|
+
import_record: ImportRecordRead | None = Field(
|
|
205
|
+
default=None, description="The parent import record."
|
|
206
|
+
)
|
|
207
|
+
import_results: list["ImportResultRead"] | None = Field(
|
|
208
|
+
default=None, description="The results from processing the batch."
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ImportBatchSummary(_ImportBatchBase):
|
|
213
|
+
"""A view for an import batch that includes a summary of its results."""
|
|
214
|
+
|
|
215
|
+
id: UUID4 = Field(
|
|
216
|
+
description="""
|
|
217
|
+
The identifier of the batch.
|
|
218
|
+
""",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
import_batch_id: UUID4 = Field(description="The ID of the batch being summarised")
|
|
222
|
+
|
|
223
|
+
import_batch_status: ImportBatchStatus = Field(
|
|
224
|
+
description="The status of the batch being summarised"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
results: dict[ImportResultStatus, int] = Field(
|
|
228
|
+
description="A count of references by their current import status."
|
|
229
|
+
)
|
|
230
|
+
failure_details: list[str] | None = Field(
|
|
231
|
+
description="""
|
|
232
|
+
The details of the failures that occurred.
|
|
233
|
+
Each failure will start with `"Entry x"` where x is the line number of the
|
|
234
|
+
jsonl object attempted to be imported.
|
|
235
|
+
""",
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class ImportResultRead(BaseModel):
|
|
240
|
+
"""Core import result class."""
|
|
241
|
+
|
|
242
|
+
id: UUID4 = Field(description="The ID of the import result.")
|
|
243
|
+
reference_id: UUID4 | None = Field(
|
|
244
|
+
default=None,
|
|
245
|
+
description="The ID of the reference created by this import result.",
|
|
246
|
+
)
|
|
247
|
+
failure_details: str | None = Field(
|
|
248
|
+
default=None,
|
|
249
|
+
description="The details of the failure, if the import result failed.",
|
|
250
|
+
)
|
|
251
|
+
import_batch: ImportBatchRead | None = Field(
|
|
252
|
+
default=None, description="The parent import batch."
|
|
253
|
+
)
|
destiny_sdk/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Reference classes for the Destiny SDK."""
|
|
2
|
+
|
|
3
|
+
from pydantic import UUID4, BaseModel, Field
|
|
4
|
+
|
|
5
|
+
from destiny_sdk.core import _JsonlFileInputMixIn
|
|
6
|
+
from destiny_sdk.enhancements import Enhancement, EnhancementFileInput
|
|
7
|
+
from destiny_sdk.identifiers import ExternalIdentifier
|
|
8
|
+
from destiny_sdk.visibility import Visibility
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Reference(_JsonlFileInputMixIn, BaseModel):
|
|
12
|
+
"""Core reference class."""
|
|
13
|
+
|
|
14
|
+
visibility: Visibility = Field(
|
|
15
|
+
default=Visibility.PUBLIC,
|
|
16
|
+
description="The level of visibility of the reference",
|
|
17
|
+
)
|
|
18
|
+
id: UUID4 = Field(
|
|
19
|
+
description="The ID of the reference",
|
|
20
|
+
)
|
|
21
|
+
identifiers: list[ExternalIdentifier] | None = Field(
|
|
22
|
+
default=None,
|
|
23
|
+
description="A list of `ExternalIdentifiers` for the Reference",
|
|
24
|
+
)
|
|
25
|
+
enhancements: list[Enhancement] | None = Field(
|
|
26
|
+
default=None,
|
|
27
|
+
description="A list of enhancements for the reference",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ReferenceFileInput(_JsonlFileInputMixIn, BaseModel):
|
|
32
|
+
"""Enhancement model used to marshall a file input."""
|
|
33
|
+
|
|
34
|
+
visibility: Visibility = Field(
|
|
35
|
+
default=Visibility.PUBLIC,
|
|
36
|
+
description="The level of visibility of the reference",
|
|
37
|
+
)
|
|
38
|
+
identifiers: list[ExternalIdentifier] | None = Field(
|
|
39
|
+
default=None,
|
|
40
|
+
description="A list of `ExternalIdentifiers` for the Reference",
|
|
41
|
+
)
|
|
42
|
+
enhancements: list[EnhancementFileInput] | None = Field(
|
|
43
|
+
default=None,
|
|
44
|
+
description="A list of enhancements for the reference",
|
|
45
|
+
)
|
destiny_sdk/robots.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""Schemas that define inputs/outputs for robots."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum, auto
|
|
4
|
+
from typing import Annotated, Self
|
|
5
|
+
|
|
6
|
+
from pydantic import UUID4, BaseModel, ConfigDict, Field, HttpUrl, model_validator
|
|
7
|
+
|
|
8
|
+
from destiny_sdk.core import _JsonlFileInputMixIn
|
|
9
|
+
from destiny_sdk.enhancements import Enhancement
|
|
10
|
+
from destiny_sdk.references import Reference
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RobotError(BaseModel):
|
|
14
|
+
"""A record of something going wrong with the robot."""
|
|
15
|
+
|
|
16
|
+
message: Annotated[
|
|
17
|
+
str,
|
|
18
|
+
Field(
|
|
19
|
+
description=(
|
|
20
|
+
"Message which describes the error encountered during processing"
|
|
21
|
+
)
|
|
22
|
+
),
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LinkedRobotError(_JsonlFileInputMixIn, RobotError):
|
|
27
|
+
"""
|
|
28
|
+
A record of something going wrong when processing an individual reference.
|
|
29
|
+
|
|
30
|
+
Used in results for batch requests - in single requests, the reference
|
|
31
|
+
id is derived from the request id.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
reference_id: UUID4 = Field(
|
|
35
|
+
description="The ID of the reference which caused the error."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class RobotResult(BaseModel):
|
|
40
|
+
"""The result of a robot request which is returned to the repo."""
|
|
41
|
+
|
|
42
|
+
request_id: UUID4
|
|
43
|
+
error: RobotError | None = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
description="Error the robot encountered while creating enhancement.",
|
|
46
|
+
)
|
|
47
|
+
enhancement: Enhancement | None = Field(
|
|
48
|
+
default=None, description="An enhancement to create"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@model_validator(mode="after")
|
|
52
|
+
def validate_error_or_enhancement_set(self) -> Self:
|
|
53
|
+
"""Validate that a robot result has either an error or an enhancement set."""
|
|
54
|
+
if (self.error is None) == (self.enhancement is None):
|
|
55
|
+
msg = """
|
|
56
|
+
exactly one of 'error' or 'enhancement' must be provided
|
|
57
|
+
"""
|
|
58
|
+
raise ValueError(msg)
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class BatchRobotResult(BaseModel):
|
|
63
|
+
"""Used to indicate to the repository that the robot has finished processing."""
|
|
64
|
+
|
|
65
|
+
request_id: UUID4
|
|
66
|
+
error: RobotError | None = Field(
|
|
67
|
+
default=None,
|
|
68
|
+
description="""
|
|
69
|
+
Error the robot encountered while creating enhancements. If this field is populated,
|
|
70
|
+
we assume the entire batch or request failed, rather than an individual reference.
|
|
71
|
+
If there was an error with processing an individual reference, it should be passed in
|
|
72
|
+
the result file and this field should be left as None. Vice-versa, if this field is
|
|
73
|
+
None, the repository will assume that the result file is ready for processing.
|
|
74
|
+
""",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class BatchRobotResultValidationEntry(_JsonlFileInputMixIn, BaseModel):
|
|
79
|
+
"""A single entry in the validation result file for a batch enhancement request."""
|
|
80
|
+
|
|
81
|
+
reference_id: UUID4 | None = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description=(
|
|
84
|
+
"The ID of the reference which was enhanced. "
|
|
85
|
+
"If this is empty, the BatchEnhancementResultEntry could not be parsed."
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
error: str | None = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
description=(
|
|
91
|
+
"Error encountered during the enhancement process for this reference. "
|
|
92
|
+
"If this is empty, the enhancement was successfully created."
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class RobotRequest(BaseModel):
|
|
98
|
+
"""An enhancement request from the repo to a robot."""
|
|
99
|
+
|
|
100
|
+
id: UUID4
|
|
101
|
+
reference: Reference # Reference with selected enhancements
|
|
102
|
+
extra_fields: (
|
|
103
|
+
dict | None
|
|
104
|
+
) # We need something to pass through the signed url for uploads
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
#: The result for a single reference when processed by a batch enhancement request.
|
|
108
|
+
#: This is a single entry in the result file.
|
|
109
|
+
BatchEnhancementResultEntry = Annotated[
|
|
110
|
+
Enhancement | LinkedRobotError,
|
|
111
|
+
Field(),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class BatchRobotRequest(BaseModel):
|
|
116
|
+
"""A batch enhancement request from the repo to a robot."""
|
|
117
|
+
|
|
118
|
+
id: UUID4
|
|
119
|
+
reference_storage_url: HttpUrl = Field(
|
|
120
|
+
description="""
|
|
121
|
+
The URL at which the set of references are stored. The file is a jsonl
|
|
122
|
+
with each line formatted according to
|
|
123
|
+
:class:`Reference <libs.sdk.src.destiny_sdk.references.Reference>`, one
|
|
124
|
+
reference per line.
|
|
125
|
+
Each reference may have identifiers or enhancements attached, as
|
|
126
|
+
required by the robot.
|
|
127
|
+
If the URL expires, a new one can be generated using
|
|
128
|
+
``GET /references/enhancement/batch/<batch_request_id>``.
|
|
129
|
+
"""
|
|
130
|
+
)
|
|
131
|
+
result_storage_url: HttpUrl = Field(
|
|
132
|
+
description="""
|
|
133
|
+
The URL at which the set of enhancements are to be stored. The file is to be a jsonl
|
|
134
|
+
with each line formatted according to
|
|
135
|
+
:class:`BatchEnhancementResultEntry <libs.sdk.src.destiny_sdk.robots.BatchEnhancementResultEntry>`.
|
|
136
|
+
If the URL expires, a new one can be generated using
|
|
137
|
+
``GET /references/enhancement/batch/<batch_request_id>``.
|
|
138
|
+
""" # noqa: E501
|
|
139
|
+
)
|
|
140
|
+
extra_fields: dict | None = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="Extra fields to pass to the robot. TBC.",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class EnhancementRequestStatus(StrEnum):
|
|
147
|
+
"""
|
|
148
|
+
The status of an enhancement request.
|
|
149
|
+
|
|
150
|
+
**Allowed values**:
|
|
151
|
+
- `received`: Enhancement request has been received.
|
|
152
|
+
- `accepted`: Enhancement request has been accepted.
|
|
153
|
+
- `rejected`: Enhancement request has been rejected.
|
|
154
|
+
- `failed`: Enhancement failed to create.
|
|
155
|
+
- `completed`: Enhancement has been created.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
RECEIVED = auto()
|
|
159
|
+
ACCEPTED = auto()
|
|
160
|
+
REJECTED = auto()
|
|
161
|
+
FAILED = auto()
|
|
162
|
+
COMPLETED = auto()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class _EnhancementRequestBase(BaseModel):
|
|
166
|
+
"""
|
|
167
|
+
Base enhancement request class.
|
|
168
|
+
|
|
169
|
+
An enhancement request is a request to create an enhancement on a reference.
|
|
170
|
+
It contains the reference and the robot to be used to create the enhancement.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
reference_id: UUID4 = Field(description="The ID of the reference to be enhanced.")
|
|
174
|
+
robot_id: UUID4 = Field(
|
|
175
|
+
description="The robot to be used to create the enhancement."
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
enhancement_parameters: dict | None = Field(
|
|
179
|
+
default=None, description="Information needed to create the enhancement. TBC."
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class EnhancementRequestIn(_EnhancementRequestBase):
|
|
184
|
+
"""The model for requesting an enhancement on specific reference."""
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class EnhancementRequestRead(_EnhancementRequestBase):
|
|
188
|
+
"""Core enhancement request class."""
|
|
189
|
+
|
|
190
|
+
id: UUID4
|
|
191
|
+
request_status: EnhancementRequestStatus = Field(
|
|
192
|
+
description="The status of the request to create an enhancement",
|
|
193
|
+
)
|
|
194
|
+
error: str | None = Field(
|
|
195
|
+
default=None,
|
|
196
|
+
description="Error encountered during the enhancement process",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class BatchEnhancementRequestStatus(StrEnum):
|
|
201
|
+
"""
|
|
202
|
+
The status of an enhancement request.
|
|
203
|
+
|
|
204
|
+
**Allowed values**:
|
|
205
|
+
- `received`: Enhancement request has been received by the repo.
|
|
206
|
+
- `accepted`: Enhancement request has been accepted by the robot.
|
|
207
|
+
- `rejected`: Enhancement request has been rejected by the robot.
|
|
208
|
+
- `partial_failed`: Some enhancements failed to create.
|
|
209
|
+
- `failed`: All enhancements failed to create.
|
|
210
|
+
- `importing`: Enhancements have been received by the repo and are being imported.
|
|
211
|
+
- `completed`: All enhancements have been created.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
RECEIVED = auto()
|
|
215
|
+
ACCEPTED = auto()
|
|
216
|
+
REJECTED = auto()
|
|
217
|
+
PARTIAL_FAILED = auto()
|
|
218
|
+
FAILED = auto()
|
|
219
|
+
IMPORTING = auto()
|
|
220
|
+
COMPLETED = auto()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class _BatchEnhancementRequestBase(BaseModel):
|
|
224
|
+
"""
|
|
225
|
+
Base batch enhancement request class.
|
|
226
|
+
|
|
227
|
+
A batch enhancement request is a request to create multiple enhancements.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
robot_id: UUID4 = Field(
|
|
231
|
+
description="The robot to be used to create the enhancements."
|
|
232
|
+
)
|
|
233
|
+
reference_ids: list[UUID4] = Field(
|
|
234
|
+
description="The IDs of the references to be enhanced."
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class BatchEnhancementRequestIn(_BatchEnhancementRequestBase):
|
|
239
|
+
"""The model for requesting multiple enhancements on specific references."""
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class BatchEnhancementRequestRead(_BatchEnhancementRequestBase):
|
|
243
|
+
"""Core batch enhancement request class."""
|
|
244
|
+
|
|
245
|
+
id: UUID4
|
|
246
|
+
request_status: BatchEnhancementRequestStatus = Field(
|
|
247
|
+
description="The status of the request to create enhancements",
|
|
248
|
+
)
|
|
249
|
+
reference_data_url: HttpUrl | None = Field(
|
|
250
|
+
default=None,
|
|
251
|
+
description="""
|
|
252
|
+
The URL at which the set of references are stored. The file is a jsonl with each line
|
|
253
|
+
formatted according to
|
|
254
|
+
:class:`Reference <libs.sdk.src.destiny_sdk.references.Reference>`.
|
|
255
|
+
, one reference per line.
|
|
256
|
+
Each reference may have identifiers or enhancements attached, as
|
|
257
|
+
required by the robot.
|
|
258
|
+
If the URL expires, a new one can be generated using
|
|
259
|
+
``GET /references/enhancement/batch/<batch_request_id>``.
|
|
260
|
+
""",
|
|
261
|
+
)
|
|
262
|
+
result_storage_url: HttpUrl | None = Field(
|
|
263
|
+
default=None,
|
|
264
|
+
description="""
|
|
265
|
+
The URL at which the set of enhancements are stored. The file is to be a jsonl
|
|
266
|
+
with each line formatted according to
|
|
267
|
+
:class:`BatchEnhancementResultEntry <libs.sdk.src.destiny_sdk.robots.BatchEnhancementResultEntry>`.
|
|
268
|
+
This field is only relevant to robots.
|
|
269
|
+
If the URL expires, a new one can be generated using
|
|
270
|
+
``GET /references/enhancement/batch/<batch_request_id>``.
|
|
271
|
+
""", # noqa: E501
|
|
272
|
+
)
|
|
273
|
+
validation_result_url: HttpUrl | None = Field(
|
|
274
|
+
default=None,
|
|
275
|
+
description="""
|
|
276
|
+
The URL at which the result of the batch enhancement request is stored.
|
|
277
|
+
This file is a txt file, one line per reference, with either an error
|
|
278
|
+
or a success message.
|
|
279
|
+
If the URL expires, a new one can be generated using
|
|
280
|
+
``GET /references/enhancement/batch/<batch_request_id>``.
|
|
281
|
+
""",
|
|
282
|
+
)
|
|
283
|
+
error: str | None = Field(
|
|
284
|
+
default=None,
|
|
285
|
+
description="Error encountered during the enhancement process. This "
|
|
286
|
+
"is only used if the entire batch enhancement request failed, rather than an "
|
|
287
|
+
"individual reference. If there was an error with processing an individual "
|
|
288
|
+
"reference, it is passed in the validation result file.",
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class _RobotBase(BaseModel):
|
|
293
|
+
"""
|
|
294
|
+
Base Robot class.
|
|
295
|
+
|
|
296
|
+
A Robot is a provider of enhancements to destiny repository
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
model_config = ConfigDict(extra="forbid") # Forbid extra fields on robot models
|
|
300
|
+
|
|
301
|
+
name: str = Field(description="The name of the robot, must be unique.")
|
|
302
|
+
base_url: HttpUrl = Field(
|
|
303
|
+
description="The base url of the robot. The robot must implement endpoints "
|
|
304
|
+
"base_url/single for the enhancement of single references and "
|
|
305
|
+
"base_url/batch for batch enhancements of references.",
|
|
306
|
+
)
|
|
307
|
+
description: str = Field(
|
|
308
|
+
description="Description of the enhancement the robot provides."
|
|
309
|
+
)
|
|
310
|
+
owner: str = Field(description="The owner/publisher of the robot.")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class RobotIn(_RobotBase):
|
|
314
|
+
"""The model for registering a new robot."""
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class Robot(_RobotBase):
|
|
318
|
+
"""Then model for a registered robot."""
|
|
319
|
+
|
|
320
|
+
id: UUID4 = Field(
|
|
321
|
+
description="The id of the robot provided by destiny repository. "
|
|
322
|
+
"Used as the client_id when sending HMAC authenticated requests."
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class ProvisionedRobot(Robot):
|
|
327
|
+
"""
|
|
328
|
+
The model for a provisioned robot.
|
|
329
|
+
|
|
330
|
+
Used only when a robot is initially created,
|
|
331
|
+
or when cycling a robot's client_secret.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
client_secret: str = Field(
|
|
335
|
+
description="The client secret of the robot, used as the secret key "
|
|
336
|
+
"when sending HMAC authenticated requests."
|
|
337
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Visibility enum for repository data."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum, auto
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Visibility(StrEnum):
|
|
7
|
+
"""
|
|
8
|
+
The visibility of a data element in the repository.
|
|
9
|
+
|
|
10
|
+
This is used to manage whether information should be publicly available or
|
|
11
|
+
restricted (generally due to copyright constraints from publishers).
|
|
12
|
+
|
|
13
|
+
TODO: Implement data governance layer to manage this.
|
|
14
|
+
|
|
15
|
+
**Allowed values**:
|
|
16
|
+
|
|
17
|
+
- `public`: Visible to the general public without authentication.
|
|
18
|
+
- `restricted`: Requires authentication to be visible.
|
|
19
|
+
- `hidden`: Is not visible, but may be passed to data mining processes.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
PUBLIC = auto()
|
|
23
|
+
RESTRICTED = auto()
|
|
24
|
+
HIDDEN = auto()
|