dyff-schema 0.35.4__py3-none-any.whl → 0.36.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.
Potentially problematic release.
This version of dyff-schema might be problematic. Click here for more details.
- dyff/schema/_version.py +2 -2
- dyff/schema/v0/r1/commands.py +228 -1
- dyff/schema/v0/r1/oci.py +5 -7
- dyff/schema/v0/r1/platform.py +408 -6
- dyff/schema/v0/r1/requests.py +35 -13
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/METADATA +3 -1
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/RECORD +11 -11
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/WHEEL +0 -0
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/licenses/LICENSE +0 -0
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/licenses/NOTICE +0 -0
- {dyff_schema-0.35.4.dist-info → dyff_schema-0.36.0.dist-info}/top_level.txt +0 -0
dyff/schema/_version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = version = "0.
|
|
2
|
-
__version_tuple__ = version_tuple = (0,
|
|
1
|
+
__version__ = version = "0.36.0"
|
|
2
|
+
__version_tuple__ = version_tuple = (0, 36, 0)
|
dyff/schema/v0/r1/commands.py
CHANGED
|
@@ -7,6 +7,7 @@ These are used internally by the platform and users typically won't encounter th
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
from datetime import datetime, timedelta, timezone
|
|
10
11
|
from typing import Literal, Optional, Union
|
|
11
12
|
|
|
12
13
|
import pydantic
|
|
@@ -15,6 +16,9 @@ from typing_extensions import Annotated
|
|
|
15
16
|
|
|
16
17
|
from .base import DyffSchemaBaseModel, JsonMergePatchSemantics
|
|
17
18
|
from .platform import (
|
|
19
|
+
ChallengeTask,
|
|
20
|
+
ChallengeTaskExecutionEnvironment,
|
|
21
|
+
ChallengeTaskSchedule,
|
|
18
22
|
DyffEntityType,
|
|
19
23
|
EntityIdentifier,
|
|
20
24
|
FamilyMember,
|
|
@@ -24,6 +28,7 @@ from .platform import (
|
|
|
24
28
|
SchemaVersion,
|
|
25
29
|
Status,
|
|
26
30
|
TagNameType,
|
|
31
|
+
body_maxlen,
|
|
27
32
|
summary_maxlen,
|
|
28
33
|
title_maxlen,
|
|
29
34
|
)
|
|
@@ -42,7 +47,10 @@ class Command(SchemaVersion, DyffSchemaBaseModel):
|
|
|
42
47
|
"""
|
|
43
48
|
|
|
44
49
|
command: Literal[
|
|
50
|
+
"CreateChallengeTask",
|
|
45
51
|
"CreateEntity",
|
|
52
|
+
"EditChallengeContent",
|
|
53
|
+
"EditChallengeTaskRules",
|
|
46
54
|
"EditEntityDocumentation",
|
|
47
55
|
"EditEntityLabels",
|
|
48
56
|
"EditFamilyMembers",
|
|
@@ -68,11 +76,220 @@ class CreateEntity(Command):
|
|
|
68
76
|
# ----------------------------------------------------------------------------
|
|
69
77
|
|
|
70
78
|
|
|
79
|
+
class CreateChallengeTaskAttributes(DyffSchemaBaseModel):
|
|
80
|
+
"""Attributes for the CreateChallengeTask command."""
|
|
81
|
+
|
|
82
|
+
task: ChallengeTask = pydantic.Field(description="The task to create.")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class CreateChallengeTaskData(EntityIdentifier):
|
|
86
|
+
"""Payload data for the CreateChallengeTask command."""
|
|
87
|
+
|
|
88
|
+
attributes: CreateChallengeTaskAttributes = pydantic.Field(
|
|
89
|
+
description="The command attributes"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class CreateChallengeTask(Command):
|
|
94
|
+
"""Create a new challenge task within an existing challenge."""
|
|
95
|
+
|
|
96
|
+
command: Literal["CreateChallengeTask"] = "CreateChallengeTask"
|
|
97
|
+
|
|
98
|
+
data: CreateChallengeTaskData = pydantic.Field(description="The command data.")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ----------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class EditChallengeContentPagePatch(JsonMergePatchSemantics):
|
|
105
|
+
"""Same properties as ChallengeContentPage.
|
|
106
|
+
|
|
107
|
+
Fields that are not assigned explicitly remain unchanged.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
title: Annotated[str, StringConstraints(max_length=title_maxlen())] = ( # type: ignore
|
|
111
|
+
pydantic.Field(
|
|
112
|
+
default="",
|
|
113
|
+
description='A short plain string suitable as a title or "headline".',
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
summary: Annotated[str, StringConstraints(max_length=summary_maxlen())] = ( # type: ignore
|
|
118
|
+
pydantic.Field(
|
|
119
|
+
default="",
|
|
120
|
+
description="A brief summary, suitable for display in"
|
|
121
|
+
" small UI elements.",
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
body: Annotated[str, StringConstraints(max_length=body_maxlen())] = pydantic.Field( # type: ignore
|
|
126
|
+
default="",
|
|
127
|
+
description="Long-form documentation. Interpreted as"
|
|
128
|
+
" Markdown. There are no length constraints, but be reasonable.",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class EditChallengeContentPatch(DyffSchemaBaseModel):
|
|
133
|
+
page: EditChallengeContentPagePatch
|
|
134
|
+
|
|
135
|
+
@field_serializer("page")
|
|
136
|
+
def _serialize_page(self, page: EditChallengeContentPagePatch, _info):
|
|
137
|
+
return page.model_dump(mode=_info.mode)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class EditChallengeContentAttributes(DyffSchemaBaseModel):
|
|
141
|
+
"""Attributes for the EditChallengePageContent command."""
|
|
142
|
+
|
|
143
|
+
challenge: Optional[EditChallengeContentPatch] = pydantic.Field(
|
|
144
|
+
default=None,
|
|
145
|
+
description="Edits to make to the content of the main challenge page.",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
tasks: Optional[dict[str, EditChallengeContentPatch]] = pydantic.Field(
|
|
149
|
+
default=None, description="Edits to make to the content of the challenge tasks."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class EditChallengeContentData(EntityIdentifier):
|
|
154
|
+
"""Payload data for the EditChallengePageContent command."""
|
|
155
|
+
|
|
156
|
+
attributes: EditChallengeContentAttributes = pydantic.Field(
|
|
157
|
+
description="The command attributes"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class EditChallengeContent(Command):
|
|
162
|
+
"""Edit the page content associated with a challenge-related entity.
|
|
163
|
+
|
|
164
|
+
Setting a documentation field to null/None deletes the corresponding value. To
|
|
165
|
+
preserve the existing value, leave the field *unset*.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
command: Literal["EditChallengeContent"] = "EditChallengeContent"
|
|
169
|
+
|
|
170
|
+
data: EditChallengeContentData = pydantic.Field(description="The edit data.")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ----------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class EditChallengeTaskRulesExecutionEnvironmentChoices(JsonMergePatchSemantics):
|
|
177
|
+
"""Same properties as ChallengeTaskExecutionEnvironmentChocies, but assigning None
|
|
178
|
+
to a field is interpreted as a command to delete that field.
|
|
179
|
+
|
|
180
|
+
Fields that are not assigned explicitly remain unchanged.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
choices: dict[str, Optional[ChallengeTaskExecutionEnvironment]] = pydantic.Field(
|
|
184
|
+
default_factory=dict, description="Execution environment choices."
|
|
185
|
+
)
|
|
186
|
+
default: Optional[str] = pydantic.Field(
|
|
187
|
+
default=None, description="The default execution environment."
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class EditChallengeTaskRulesSchedule(JsonMergePatchSemantics):
|
|
192
|
+
"""Same properties as ChallengeTaskSchedule, but assigning None to a field is
|
|
193
|
+
interpreted as a command to delete that field.
|
|
194
|
+
|
|
195
|
+
Fields that are not assigned explicitly remain unchanged.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
openingTime: Optional[datetime] = pydantic.Field(
|
|
199
|
+
default=None, description="The announced opening time for task submissions."
|
|
200
|
+
)
|
|
201
|
+
closingTime: Optional[datetime] = pydantic.Field(
|
|
202
|
+
default=None, description="The announced closing time for task submissions."
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
submissionCycleDuration: timedelta = pydantic.Field(
|
|
206
|
+
default=timedelta(days=1),
|
|
207
|
+
description="The duration of a submission cycle."
|
|
208
|
+
" Teams are limited to a maximum number of submissions per cycle.",
|
|
209
|
+
)
|
|
210
|
+
submissionCycleEpoch: datetime = pydantic.Field(
|
|
211
|
+
default=datetime.fromtimestamp(0, timezone.utc),
|
|
212
|
+
description="The epoch of a submission cycle."
|
|
213
|
+
" For example, any given cycle lasts from"
|
|
214
|
+
" [epoch + N*duration, epoch + (N+1)*duration)."
|
|
215
|
+
" Teams are limited to a maximum number of submissions per cycle.",
|
|
216
|
+
)
|
|
217
|
+
submissionLimitPerCycle: int = pydantic.Field(
|
|
218
|
+
default=1,
|
|
219
|
+
ge=1,
|
|
220
|
+
description="Teams are limited to this many submissions per cycle.",
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class EditChallengeTaskRulesPatch(DyffSchemaBaseModel):
|
|
225
|
+
"""Same properties as ChallengeTaskRules, but assigning None to a field is
|
|
226
|
+
interpreted as a command to delete that field.
|
|
227
|
+
|
|
228
|
+
Fields that are not assigned explicitly remain unchanged.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
executionEnvironment: Optional[
|
|
232
|
+
EditChallengeTaskRulesExecutionEnvironmentChoices
|
|
233
|
+
] = pydantic.Field(
|
|
234
|
+
default=None, description="Patch for the .rules.executionEnvironments field."
|
|
235
|
+
)
|
|
236
|
+
schedule: Optional[EditChallengeTaskRulesSchedule] = pydantic.Field(
|
|
237
|
+
default=None, description="Patch for the .rules.schedule field."
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
@field_serializer("executionEnvironment")
|
|
241
|
+
def _serialize_executionEnvironment(
|
|
242
|
+
self,
|
|
243
|
+
executionEnvironment: EditChallengeTaskRulesExecutionEnvironmentChoices,
|
|
244
|
+
_info,
|
|
245
|
+
):
|
|
246
|
+
return executionEnvironment.model_dump(mode=_info.mode)
|
|
247
|
+
|
|
248
|
+
@field_serializer("schedule")
|
|
249
|
+
def _serialize_schedule(
|
|
250
|
+
self,
|
|
251
|
+
schedule: EditChallengeTaskRulesSchedule,
|
|
252
|
+
_info,
|
|
253
|
+
):
|
|
254
|
+
return schedule.model_dump(mode=_info.mode)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class EditChallengeTaskRulesAttributes(DyffSchemaBaseModel):
|
|
258
|
+
"""Attributes for the EditChallengeTaskRules command."""
|
|
259
|
+
|
|
260
|
+
rules: EditChallengeTaskRulesPatch = pydantic.Field(
|
|
261
|
+
description="Edits to make to the task rules."
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class EditChallengeTaskRulesData(EntityIdentifier):
|
|
266
|
+
"""Payload data for the EditChallengeTaskRules command."""
|
|
267
|
+
|
|
268
|
+
attributes: EditChallengeTaskRulesAttributes = pydantic.Field(
|
|
269
|
+
description="The command attributes"
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class EditChallengeTaskRules(Command):
|
|
274
|
+
"""Edit the rules of a challenge task.
|
|
275
|
+
|
|
276
|
+
Setting a field to null/None deletes the corresponding value. To preserve the
|
|
277
|
+
existing value, leave the field *unset*.
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
command: Literal["EditChallengeTaskRules"] = "EditChallengeTaskRules"
|
|
281
|
+
|
|
282
|
+
data: EditChallengeTaskRulesData = pydantic.Field(description="The edit data.")
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# ----------------------------------------------------------------------------
|
|
286
|
+
|
|
287
|
+
|
|
71
288
|
class EditEntityDocumentationPatch(JsonMergePatchSemantics):
|
|
72
289
|
"""Same properties as DocumentationBase, but assigning None to a field is
|
|
73
290
|
interpreted as a command to delete that field.
|
|
74
291
|
|
|
75
|
-
Fields that are assigned explicitly remain unchanged.
|
|
292
|
+
Fields that are not assigned explicitly remain unchanged.
|
|
76
293
|
"""
|
|
77
294
|
|
|
78
295
|
title: Optional[Annotated[str, StringConstraints(max_length=title_maxlen())]] = ( # type: ignore
|
|
@@ -292,7 +509,9 @@ class UpdateEntityStatus(Command):
|
|
|
292
509
|
|
|
293
510
|
|
|
294
511
|
DyffCommandType = Union[
|
|
512
|
+
CreateChallengeTask,
|
|
295
513
|
CreateEntity,
|
|
514
|
+
EditChallengeContent,
|
|
296
515
|
EditEntityDocumentation,
|
|
297
516
|
EditEntityLabels,
|
|
298
517
|
EditFamilyMembers,
|
|
@@ -304,8 +523,16 @@ DyffCommandType = Union[
|
|
|
304
523
|
|
|
305
524
|
__all__ = [
|
|
306
525
|
"Command",
|
|
526
|
+
"CreateChallengeTask",
|
|
527
|
+
"CreateChallengeTaskAttributes",
|
|
528
|
+
"CreateChallengeTaskData",
|
|
307
529
|
"CreateEntity",
|
|
308
530
|
"DyffCommandType",
|
|
531
|
+
"EditChallengeContent",
|
|
532
|
+
"EditChallengeContentAttributes",
|
|
533
|
+
"EditChallengeContentData",
|
|
534
|
+
"EditChallengeContentPagePatch",
|
|
535
|
+
"EditChallengeContentPatch",
|
|
309
536
|
"EditEntityDocumentation",
|
|
310
537
|
"EditEntityDocumentationAttributes",
|
|
311
538
|
"EditEntityDocumentationData",
|
dyff/schema/v0/r1/oci.py
CHANGED
|
@@ -53,18 +53,16 @@ class _OCISchemaBaseModel(pydantic.BaseModel):
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
@pydantic.model_validator(mode="after")
|
|
56
|
-
def _ensure_datetime_timezone_utc(
|
|
57
|
-
for field_name, field_value in
|
|
56
|
+
def _ensure_datetime_timezone_utc(self):
|
|
57
|
+
for field_name, field_value in self.__dict__.items():
|
|
58
58
|
if isinstance(field_value, datetime):
|
|
59
59
|
if field_value.tzinfo is None:
|
|
60
60
|
# Set UTC timezone for naive datetime
|
|
61
|
-
setattr(
|
|
62
|
-
values, field_name, field_value.replace(tzinfo=timezone.utc)
|
|
63
|
-
)
|
|
61
|
+
setattr(self, field_name, field_value.replace(tzinfo=timezone.utc))
|
|
64
62
|
elif field_value.tzinfo != timezone.utc:
|
|
65
63
|
# Convert to UTC timezone
|
|
66
|
-
setattr(
|
|
67
|
-
return
|
|
64
|
+
setattr(self, field_name, field_value.astimezone(timezone.utc))
|
|
65
|
+
return self
|
|
68
66
|
|
|
69
67
|
|
|
70
68
|
class _DigestMixin(pydantic.BaseModel):
|
dyff/schema/v0/r1/platform.py
CHANGED
|
@@ -22,11 +22,12 @@ We use the following naming convention:
|
|
|
22
22
|
import abc
|
|
23
23
|
import enum
|
|
24
24
|
import urllib.parse
|
|
25
|
-
from datetime import datetime
|
|
25
|
+
from datetime import datetime, timedelta, timezone
|
|
26
26
|
from enum import Enum
|
|
27
27
|
from pathlib import Path
|
|
28
28
|
from typing import Any, Literal, NamedTuple, Optional, Type, Union
|
|
29
29
|
|
|
30
|
+
import i18naddress
|
|
30
31
|
import pyarrow
|
|
31
32
|
import pydantic
|
|
32
33
|
from pydantic import StringConstraints
|
|
@@ -182,6 +183,10 @@ def summary_maxlen() -> int:
|
|
|
182
183
|
return 280
|
|
183
184
|
|
|
184
185
|
|
|
186
|
+
def body_maxlen() -> int:
|
|
187
|
+
return 1_000_000
|
|
188
|
+
|
|
189
|
+
|
|
185
190
|
def entity_id_regex() -> str:
|
|
186
191
|
"""An entity ID is a 32-character HEX string.
|
|
187
192
|
|
|
@@ -199,6 +204,7 @@ class Entities(str, enum.Enum):
|
|
|
199
204
|
Artifact = "OCIArtifact"
|
|
200
205
|
Audit = "Audit"
|
|
201
206
|
AuditProcedure = "AuditProcedure"
|
|
207
|
+
Challenge = "Challenge"
|
|
202
208
|
Concern = "Concern"
|
|
203
209
|
DataSource = "DataSource"
|
|
204
210
|
Dataset = "Dataset"
|
|
@@ -217,6 +223,8 @@ class Entities(str, enum.Enum):
|
|
|
217
223
|
Revision = "Revision"
|
|
218
224
|
SafetyCase = "SafetyCase"
|
|
219
225
|
Score = "Score"
|
|
226
|
+
Submission = "Submission"
|
|
227
|
+
Team = "Team"
|
|
220
228
|
UseCase = "UseCase"
|
|
221
229
|
|
|
222
230
|
|
|
@@ -227,6 +235,7 @@ class Resources(str, enum.Enum):
|
|
|
227
235
|
Artifact = "artifacts"
|
|
228
236
|
Audit = "audits"
|
|
229
237
|
AuditProcedure = "auditprocedures"
|
|
238
|
+
Challenge = "challenges"
|
|
230
239
|
Concern = "concerns"
|
|
231
240
|
Dataset = "datasets"
|
|
232
241
|
DataSource = "datasources"
|
|
@@ -246,6 +255,8 @@ class Resources(str, enum.Enum):
|
|
|
246
255
|
Revision = "revisions"
|
|
247
256
|
SafetyCase = "safetycases"
|
|
248
257
|
Score = "scores"
|
|
258
|
+
Submission = "submissions"
|
|
259
|
+
Team = "teams"
|
|
249
260
|
UseCase = "usecases"
|
|
250
261
|
|
|
251
262
|
Task = "tasks"
|
|
@@ -276,6 +287,7 @@ EntityKindLiteral = Literal[
|
|
|
276
287
|
"Analysis",
|
|
277
288
|
"Audit",
|
|
278
289
|
"AuditProcedure",
|
|
290
|
+
"Challenge",
|
|
279
291
|
"DataSource",
|
|
280
292
|
"Dataset",
|
|
281
293
|
"Evaluation",
|
|
@@ -293,6 +305,8 @@ EntityKindLiteral = Literal[
|
|
|
293
305
|
"Report",
|
|
294
306
|
"Revision",
|
|
295
307
|
"SafetyCase",
|
|
308
|
+
"Submission",
|
|
309
|
+
"Team",
|
|
296
310
|
"UseCase",
|
|
297
311
|
]
|
|
298
312
|
|
|
@@ -503,6 +517,7 @@ class DyffEntity(Status, Labeled, SchemaVersion, DyffModelWithID):
|
|
|
503
517
|
"Analysis",
|
|
504
518
|
"Audit",
|
|
505
519
|
"AuditProcedure",
|
|
520
|
+
"Challenge",
|
|
506
521
|
"DataSource",
|
|
507
522
|
"Dataset",
|
|
508
523
|
"Evaluation",
|
|
@@ -520,6 +535,8 @@ class DyffEntity(Status, Labeled, SchemaVersion, DyffModelWithID):
|
|
|
520
535
|
"Report",
|
|
521
536
|
"Revision",
|
|
522
537
|
"SafetyCase",
|
|
538
|
+
"Submission",
|
|
539
|
+
"Team",
|
|
523
540
|
"UseCase",
|
|
524
541
|
]
|
|
525
542
|
|
|
@@ -730,7 +747,9 @@ class FamilyMemberBase(DyffSchemaBaseModel):
|
|
|
730
747
|
description="ID of the resource this member references.",
|
|
731
748
|
)
|
|
732
749
|
|
|
733
|
-
description: Optional[
|
|
750
|
+
description: Optional[
|
|
751
|
+
Annotated[str, StringConstraints(max_length=summary_maxlen())]
|
|
752
|
+
] = pydantic.Field( # type: ignore
|
|
734
753
|
default=None,
|
|
735
754
|
description="A short description of the member."
|
|
736
755
|
" This should describe how this version of the resource"
|
|
@@ -2003,12 +2022,12 @@ class ScoreSpec(DyffSchemaBaseModel):
|
|
|
2003
2022
|
return self.format_quantity(self.format, quantity, unit=self.unit)
|
|
2004
2023
|
|
|
2005
2024
|
@pydantic.model_validator(mode="after")
|
|
2006
|
-
def _validate_minimum_maximum(
|
|
2007
|
-
minimum =
|
|
2008
|
-
maximum =
|
|
2025
|
+
def _validate_minimum_maximum(self):
|
|
2026
|
+
minimum = self.minimum
|
|
2027
|
+
maximum = self.maximum
|
|
2009
2028
|
if minimum is not None and maximum is not None and minimum > maximum:
|
|
2010
2029
|
raise ValueError(f"minimum {minimum} is greater than maximum {maximum}")
|
|
2011
|
-
return
|
|
2030
|
+
return self
|
|
2012
2031
|
|
|
2013
2032
|
@pydantic.field_validator("format")
|
|
2014
2033
|
def _validate_format(cls, v):
|
|
@@ -2292,6 +2311,372 @@ class OCIArtifact(DyffEntity):
|
|
|
2292
2311
|
return None
|
|
2293
2312
|
|
|
2294
2313
|
|
|
2314
|
+
# ----------------------------------------------------------------------------
|
|
2315
|
+
# Challenges
|
|
2316
|
+
|
|
2317
|
+
|
|
2318
|
+
class ChallengeContentPage(DyffSchemaBaseModel):
|
|
2319
|
+
"""The content for the Web page corresponding to a challenge or challenge-related
|
|
2320
|
+
object."""
|
|
2321
|
+
|
|
2322
|
+
title: str = pydantic.Field(
|
|
2323
|
+
default="Untitled Challenge",
|
|
2324
|
+
description='A short plain string suitable as a title or "headline".',
|
|
2325
|
+
max_length=title_maxlen(),
|
|
2326
|
+
)
|
|
2327
|
+
|
|
2328
|
+
summary: str = pydantic.Field(
|
|
2329
|
+
default="",
|
|
2330
|
+
description="A brief summary, suitable for display in small UI elements.",
|
|
2331
|
+
max_length=summary_maxlen(),
|
|
2332
|
+
)
|
|
2333
|
+
|
|
2334
|
+
body: str = pydantic.Field(
|
|
2335
|
+
default="",
|
|
2336
|
+
description="Long-form documentation. Interpreted as"
|
|
2337
|
+
" Markdown and rendered as a single page. There are no length"
|
|
2338
|
+
" constraints, but be reasonable.",
|
|
2339
|
+
max_length=body_maxlen(),
|
|
2340
|
+
)
|
|
2341
|
+
|
|
2342
|
+
|
|
2343
|
+
class ChallengeNewsItem(DyffSchemaBaseModel):
|
|
2344
|
+
"""A news item to display in the challenge news feed."""
|
|
2345
|
+
|
|
2346
|
+
id: str = pydantic.Field(description="Unique ID of the news item.")
|
|
2347
|
+
title: str = pydantic.Field(
|
|
2348
|
+
description='A short plain string suitable as a title or "headline".',
|
|
2349
|
+
max_length=title_maxlen(),
|
|
2350
|
+
)
|
|
2351
|
+
summary: str = pydantic.Field(
|
|
2352
|
+
description="A brief summary, suitable for display in small UI elements.",
|
|
2353
|
+
max_length=summary_maxlen(),
|
|
2354
|
+
)
|
|
2355
|
+
postingTime: datetime = pydantic.Field(
|
|
2356
|
+
description="The timestamp when the news item was posted."
|
|
2357
|
+
)
|
|
2358
|
+
|
|
2359
|
+
|
|
2360
|
+
class TeamMember(DyffSchemaBaseModel):
|
|
2361
|
+
"""A member of a team."""
|
|
2362
|
+
|
|
2363
|
+
name: str = pydantic.Field(
|
|
2364
|
+
description="The member's full name as it will be displayed in the UI."
|
|
2365
|
+
" Include all desired titles and honorifics.",
|
|
2366
|
+
max_length=title_maxlen(),
|
|
2367
|
+
)
|
|
2368
|
+
isCorrespondingMember: bool = pydantic.Field(
|
|
2369
|
+
description="Indicates that this member will receive and respond to"
|
|
2370
|
+
" correspondence pertaining to the team's participation in the challenge."
|
|
2371
|
+
" At least one member must be a corresponding member."
|
|
2372
|
+
)
|
|
2373
|
+
email: Optional[pydantic.EmailStr] = pydantic.Field(
|
|
2374
|
+
default=None, description="The member's email address."
|
|
2375
|
+
)
|
|
2376
|
+
orcid: Optional[str] = pydantic.Field(
|
|
2377
|
+
default=None, description="The member's ORCID."
|
|
2378
|
+
)
|
|
2379
|
+
url: Optional[pydantic.HttpUrl] = pydantic.Field(
|
|
2380
|
+
default=None,
|
|
2381
|
+
description="The URL of the member's personal Web page or similar.",
|
|
2382
|
+
)
|
|
2383
|
+
note: Optional[str] = pydantic.Field(
|
|
2384
|
+
default=None,
|
|
2385
|
+
description="A brief note giving additional information about the member.",
|
|
2386
|
+
max_length=summary_maxlen(),
|
|
2387
|
+
)
|
|
2388
|
+
affiliations: Optional[list[str]] = pydantic.Field(
|
|
2389
|
+
default=None,
|
|
2390
|
+
description="The member's affiliations, specified as keys in the"
|
|
2391
|
+
" .affiliations dict in the corresonding Team object.",
|
|
2392
|
+
)
|
|
2393
|
+
|
|
2394
|
+
|
|
2395
|
+
class GoogleI18nMailingAddress(DyffSchemaBaseModel):
|
|
2396
|
+
"""An international mailing address, in the schema used by Google's
|
|
2397
|
+
i18n address metadata repository
|
|
2398
|
+
(https://chromium-i18n.appspot.com/ssl-address) and as interpreted by the
|
|
2399
|
+
Python ``google-i18n-address`` package.
|
|
2400
|
+
|
|
2401
|
+
The field names depart from our camelCase convention to match the
|
|
2402
|
+
existing google-i18n-address format. We also use the empty string rather
|
|
2403
|
+
than
|
|
2404
|
+
"""
|
|
2405
|
+
|
|
2406
|
+
street_address: str = pydantic.Field(
|
|
2407
|
+
description="The (possibly multiline) street address.",
|
|
2408
|
+
)
|
|
2409
|
+
country_code: str = pydantic.Field(
|
|
2410
|
+
description="Two-letter ISO 3166-1 country code.",
|
|
2411
|
+
)
|
|
2412
|
+
city: Optional[str] = pydantic.Field(
|
|
2413
|
+
default=None,
|
|
2414
|
+
description="A city or town name.",
|
|
2415
|
+
)
|
|
2416
|
+
country_area: Optional[str] = pydantic.Field(
|
|
2417
|
+
default=None,
|
|
2418
|
+
description="A designation of a region, province, or state.",
|
|
2419
|
+
)
|
|
2420
|
+
postal_code: Optional[str] = pydantic.Field(
|
|
2421
|
+
default=None,
|
|
2422
|
+
description="A postal code or zip code.",
|
|
2423
|
+
)
|
|
2424
|
+
sorting_code: Optional[str] = pydantic.Field(
|
|
2425
|
+
default=None,
|
|
2426
|
+
description="A sorting code.",
|
|
2427
|
+
)
|
|
2428
|
+
name: Optional[str] = pydantic.Field(
|
|
2429
|
+
default=None,
|
|
2430
|
+
description="A person's name.",
|
|
2431
|
+
)
|
|
2432
|
+
company_name: Optional[str] = pydantic.Field(
|
|
2433
|
+
default=None,
|
|
2434
|
+
description="A name of a company or organization.",
|
|
2435
|
+
)
|
|
2436
|
+
|
|
2437
|
+
formatted: str = pydantic.Field(
|
|
2438
|
+
default="",
|
|
2439
|
+
description="The address formatted as a multi-line string (auto-generated).",
|
|
2440
|
+
)
|
|
2441
|
+
|
|
2442
|
+
@pydantic.model_validator(mode="after")
|
|
2443
|
+
def normalize_address(self):
|
|
2444
|
+
"""Normalizes the address and populates .formatted."""
|
|
2445
|
+
unnormalized = self.model_dump()
|
|
2446
|
+
normalized = i18naddress.normalize_address(unnormalized)
|
|
2447
|
+
for k, v in normalized.items():
|
|
2448
|
+
if v != "":
|
|
2449
|
+
setattr(self, k, v)
|
|
2450
|
+
self.formatted = i18naddress.format_address(normalized, latin=True)
|
|
2451
|
+
return self
|
|
2452
|
+
|
|
2453
|
+
|
|
2454
|
+
class TeamAffiliation(DyffSchemaBaseModel):
|
|
2455
|
+
"""An organization with which one or more team members are affiliated, such as a
|
|
2456
|
+
university or company."""
|
|
2457
|
+
|
|
2458
|
+
name: str = pydantic.Field(
|
|
2459
|
+
description="The name of the organization as it will be displayed in the UI.",
|
|
2460
|
+
max_length=title_maxlen(),
|
|
2461
|
+
)
|
|
2462
|
+
department: Optional[str] = pydantic.Field(
|
|
2463
|
+
default=None,
|
|
2464
|
+
description="A department within the organization.",
|
|
2465
|
+
max_length=title_maxlen(),
|
|
2466
|
+
)
|
|
2467
|
+
group: Optional[str] = pydantic.Field(
|
|
2468
|
+
default=None,
|
|
2469
|
+
description="A group within the organization or department.",
|
|
2470
|
+
max_length=title_maxlen(),
|
|
2471
|
+
)
|
|
2472
|
+
|
|
2473
|
+
address: Optional[GoogleI18nMailingAddress] = pydantic.Field(
|
|
2474
|
+
default=None,
|
|
2475
|
+
description="The mailing address of the organization.",
|
|
2476
|
+
)
|
|
2477
|
+
|
|
2478
|
+
url: Optional[pydantic.HttpUrl] = pydantic.Field(
|
|
2479
|
+
default=None, description="The organization's Web page or similar."
|
|
2480
|
+
)
|
|
2481
|
+
|
|
2482
|
+
|
|
2483
|
+
class Team(DyffEntity):
|
|
2484
|
+
"""The members and affiliations of a team that has entered a challenge."""
|
|
2485
|
+
|
|
2486
|
+
kind: Literal["Team"] = Entities.Team.value
|
|
2487
|
+
|
|
2488
|
+
challenge: str = pydantic.Field(
|
|
2489
|
+
description="ID of the Challenge that this Team is participating in"
|
|
2490
|
+
)
|
|
2491
|
+
members: dict[str, TeamMember] = pydantic.Field(
|
|
2492
|
+
description="The members of this team"
|
|
2493
|
+
)
|
|
2494
|
+
affiliations: dict[str, TeamAffiliation] = pydantic.Field(
|
|
2495
|
+
description="The affiliations of the team. Team members state their"
|
|
2496
|
+
" affiliations by referencing these entries by their keys."
|
|
2497
|
+
)
|
|
2498
|
+
|
|
2499
|
+
def dependencies(self) -> list[str]:
|
|
2500
|
+
return []
|
|
2501
|
+
|
|
2502
|
+
def resource_allocation(self) -> Optional[ResourceAllocation]:
|
|
2503
|
+
return None
|
|
2504
|
+
|
|
2505
|
+
|
|
2506
|
+
class ChallengeTaskExecutionEnvironment(DyffSchemaBaseModel):
|
|
2507
|
+
"""Description of an execution environment that is available to run challenge
|
|
2508
|
+
entries.
|
|
2509
|
+
|
|
2510
|
+
The specified computational resources are maximums; entries are free to request and
|
|
2511
|
+
use fewer resources.
|
|
2512
|
+
"""
|
|
2513
|
+
|
|
2514
|
+
cpu: Quantity
|
|
2515
|
+
memory: Quantity
|
|
2516
|
+
accelerators: dict[str, int]
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
class ChallengeTaskExecutionEnvironmentChoices(DyffSchemaBaseModel):
|
|
2520
|
+
"""The execution environment(s) available to run challenge entries.
|
|
2521
|
+
|
|
2522
|
+
For an InferenceService to be a valid submission for a Challenge, there must be at
|
|
2523
|
+
least one execution environment defined for the challenge such that all of the
|
|
2524
|
+
resource requests of the service are less than or equal to the corresponding limits
|
|
2525
|
+
defined in the execution environment.
|
|
2526
|
+
"""
|
|
2527
|
+
|
|
2528
|
+
choices: dict[str, ChallengeTaskExecutionEnvironment]
|
|
2529
|
+
default: str
|
|
2530
|
+
|
|
2531
|
+
|
|
2532
|
+
class ChallengeTaskSchedule(DyffSchemaBaseModel):
|
|
2533
|
+
"""The schedule of a challenge task."""
|
|
2534
|
+
|
|
2535
|
+
openingTime: Optional[datetime] = pydantic.Field(
|
|
2536
|
+
default=None, description="The announced opening time for task submissions."
|
|
2537
|
+
)
|
|
2538
|
+
closingTime: Optional[datetime] = pydantic.Field(
|
|
2539
|
+
default=None, description="The announced closing time for task submissions."
|
|
2540
|
+
)
|
|
2541
|
+
submissionCycleDuration: timedelta = pydantic.Field(
|
|
2542
|
+
default=timedelta(days=1),
|
|
2543
|
+
description="The duration of a submission cycle."
|
|
2544
|
+
" Teams are limited to a maximum number of submissions per cycle.",
|
|
2545
|
+
)
|
|
2546
|
+
submissionCycleEpoch: datetime = pydantic.Field(
|
|
2547
|
+
default=datetime.fromtimestamp(0, timezone.utc),
|
|
2548
|
+
description="The epoch of a submission cycle."
|
|
2549
|
+
" For example, any given cycle lasts from"
|
|
2550
|
+
" [epoch + N*duration, epoch + (N+1)*duration)."
|
|
2551
|
+
" Teams are limited to a maximum number of submissions per cycle.",
|
|
2552
|
+
)
|
|
2553
|
+
submissionLimitPerCycle: int = pydantic.Field(
|
|
2554
|
+
default=1,
|
|
2555
|
+
ge=1,
|
|
2556
|
+
description="Teams are limited to this many submissions per cycle.",
|
|
2557
|
+
)
|
|
2558
|
+
|
|
2559
|
+
|
|
2560
|
+
class ChallengeTaskRules(DyffSchemaBaseModel):
|
|
2561
|
+
"""The rules of the challenge."""
|
|
2562
|
+
|
|
2563
|
+
executionEnvironment: ChallengeTaskExecutionEnvironmentChoices = pydantic.Field(
|
|
2564
|
+
description="The available choices for the execution environment."
|
|
2565
|
+
)
|
|
2566
|
+
schedule: ChallengeTaskSchedule = pydantic.Field(
|
|
2567
|
+
description="The challenge schedule."
|
|
2568
|
+
)
|
|
2569
|
+
|
|
2570
|
+
|
|
2571
|
+
class ChallengeTaskContent(DyffSchemaBaseModel):
|
|
2572
|
+
"""The content of a ChallengeTask UI view."."""
|
|
2573
|
+
|
|
2574
|
+
page: ChallengeContentPage = pydantic.Field(
|
|
2575
|
+
description="The content of the challenge task Web page."
|
|
2576
|
+
)
|
|
2577
|
+
|
|
2578
|
+
|
|
2579
|
+
class ChallengeTaskBase(DyffSchemaBaseModel):
|
|
2580
|
+
"""The part of the ChallengeTask spec that is not system-populated."""
|
|
2581
|
+
|
|
2582
|
+
challenge: str = pydantic.Field(
|
|
2583
|
+
description="The ID of the Challenge of which this task is a member."
|
|
2584
|
+
)
|
|
2585
|
+
name: str = pydantic.Field(
|
|
2586
|
+
description="Unique name for the task in the context of the challenge."
|
|
2587
|
+
" This may appear in URLs and must follow naming restrictions.",
|
|
2588
|
+
max_length=title_maxlen(),
|
|
2589
|
+
pattern=r"[a-z0-9-]*",
|
|
2590
|
+
)
|
|
2591
|
+
assessment: str = pydantic.Field(
|
|
2592
|
+
description="ID of the Assessment that the task runs."
|
|
2593
|
+
)
|
|
2594
|
+
rules: ChallengeTaskRules = pydantic.Field(description="The rules for submissions.")
|
|
2595
|
+
content: ChallengeTaskContent = pydantic.Field(
|
|
2596
|
+
description="Content of the task view in the Dyff App."
|
|
2597
|
+
)
|
|
2598
|
+
|
|
2599
|
+
|
|
2600
|
+
class ChallengeTask(Status, ChallengeTaskBase, DyffModelWithID):
|
|
2601
|
+
"""A task that is part of a challenge.
|
|
2602
|
+
|
|
2603
|
+
Teams make submissions to individual tasks, rather than the overall challenge. A
|
|
2604
|
+
task combines an assessment pipeline that actually implements the computations along
|
|
2605
|
+
with rules for submissions and descriptive content for the Web app.
|
|
2606
|
+
"""
|
|
2607
|
+
|
|
2608
|
+
creationTime: datetime = pydantic.Field(
|
|
2609
|
+
description="Resource creation time (assigned by system)"
|
|
2610
|
+
)
|
|
2611
|
+
|
|
2612
|
+
lastTransitionTime: Optional[datetime] = pydantic.Field(
|
|
2613
|
+
default=None, description="Time of last (status, reason) change."
|
|
2614
|
+
)
|
|
2615
|
+
|
|
2616
|
+
|
|
2617
|
+
class ChallengeContent(DyffSchemaBaseModel):
|
|
2618
|
+
"""The content of a Challenge UI view."."""
|
|
2619
|
+
|
|
2620
|
+
page: ChallengeContentPage = pydantic.Field(
|
|
2621
|
+
default_factory=ChallengeContentPage,
|
|
2622
|
+
description="The content of the challenge Web page.",
|
|
2623
|
+
)
|
|
2624
|
+
news: dict[str, ChallengeNewsItem] = pydantic.Field(
|
|
2625
|
+
default_factory=dict,
|
|
2626
|
+
description="News items to display in the challenge news feed.",
|
|
2627
|
+
)
|
|
2628
|
+
|
|
2629
|
+
|
|
2630
|
+
class Challenge(DyffEntity):
|
|
2631
|
+
"""A Challenge is a collection of assessments on which participating teams compete
|
|
2632
|
+
to achieve the best performance."""
|
|
2633
|
+
|
|
2634
|
+
kind: Literal["Challenge"] = Entities.Challenge.value
|
|
2635
|
+
|
|
2636
|
+
content: ChallengeContent = pydantic.Field(
|
|
2637
|
+
description="Content of the challenge view in the Dyff App."
|
|
2638
|
+
)
|
|
2639
|
+
|
|
2640
|
+
tasks: dict[str, ChallengeTask] = pydantic.Field(
|
|
2641
|
+
default_factory=dict, description="The assessments that comprise the challenge."
|
|
2642
|
+
)
|
|
2643
|
+
|
|
2644
|
+
def dependencies(self) -> list[str]:
|
|
2645
|
+
return []
|
|
2646
|
+
|
|
2647
|
+
def resource_allocation(self) -> Optional[ResourceAllocation]:
|
|
2648
|
+
return None
|
|
2649
|
+
|
|
2650
|
+
|
|
2651
|
+
class ChallengeSubmission(DyffEntity):
|
|
2652
|
+
"""A submission of an inference system to a challenge by a team.
|
|
2653
|
+
|
|
2654
|
+
All of the constituent resources must already exist. Creating a Submission simply
|
|
2655
|
+
indicates that the participating team wishes to submit the inference service as an
|
|
2656
|
+
official entry. Most challenges will limit the number of submissions that can be
|
|
2657
|
+
made in a given time interval.
|
|
2658
|
+
"""
|
|
2659
|
+
|
|
2660
|
+
kind: Literal["Submission"] = Entities.Submission.value
|
|
2661
|
+
|
|
2662
|
+
challenge: str = pydantic.Field(
|
|
2663
|
+
description="The ID of the challenge being submitted to."
|
|
2664
|
+
)
|
|
2665
|
+
task: str = pydantic.Field(
|
|
2666
|
+
description="The key of the task within the challenge being submitted to."
|
|
2667
|
+
)
|
|
2668
|
+
team: str = pydantic.Field(description="The ID of the team making the submission.")
|
|
2669
|
+
inferenceService: str = pydantic.Field(
|
|
2670
|
+
description="The ID of the inference service being submitted."
|
|
2671
|
+
)
|
|
2672
|
+
|
|
2673
|
+
def dependencies(self) -> list[str]:
|
|
2674
|
+
return []
|
|
2675
|
+
|
|
2676
|
+
def resource_allocation(self) -> Optional[ResourceAllocation]:
|
|
2677
|
+
return None
|
|
2678
|
+
|
|
2679
|
+
|
|
2295
2680
|
# ---------------------------------------------------------------------------
|
|
2296
2681
|
# Status enumerations
|
|
2297
2682
|
|
|
@@ -2537,9 +2922,12 @@ _ENTITY_CLASS = {
|
|
|
2537
2922
|
Entities.Artifact: OCIArtifact,
|
|
2538
2923
|
Entities.Audit: Audit,
|
|
2539
2924
|
Entities.AuditProcedure: AuditProcedure,
|
|
2925
|
+
Entities.Challenge: Challenge,
|
|
2540
2926
|
Entities.Dataset: Dataset,
|
|
2541
2927
|
Entities.DataSource: DataSource,
|
|
2542
2928
|
Entities.Evaluation: Evaluation,
|
|
2929
|
+
Entities.Family: Family,
|
|
2930
|
+
Entities.Hazard: Hazard,
|
|
2543
2931
|
Entities.InferenceService: InferenceService,
|
|
2544
2932
|
Entities.InferenceSession: InferenceSession,
|
|
2545
2933
|
Entities.Measurement: Measurement,
|
|
@@ -2548,6 +2936,8 @@ _ENTITY_CLASS = {
|
|
|
2548
2936
|
Entities.Module: Module,
|
|
2549
2937
|
Entities.Report: Report,
|
|
2550
2938
|
Entities.SafetyCase: SafetyCase,
|
|
2939
|
+
Entities.Team: Team,
|
|
2940
|
+
Entities.UseCase: UseCase,
|
|
2551
2941
|
}
|
|
2552
2942
|
|
|
2553
2943
|
|
|
@@ -2558,6 +2948,7 @@ def entity_class(kind: Entities):
|
|
|
2558
2948
|
_DyffEntityTypeRevisable = Union[
|
|
2559
2949
|
Audit,
|
|
2560
2950
|
AuditProcedure,
|
|
2951
|
+
Challenge,
|
|
2561
2952
|
DataSource,
|
|
2562
2953
|
Dataset,
|
|
2563
2954
|
Evaluation,
|
|
@@ -2572,6 +2963,7 @@ _DyffEntityTypeRevisable = Union[
|
|
|
2572
2963
|
OCIArtifact,
|
|
2573
2964
|
Report,
|
|
2574
2965
|
SafetyCase,
|
|
2966
|
+
Team,
|
|
2575
2967
|
UseCase,
|
|
2576
2968
|
]
|
|
2577
2969
|
|
|
@@ -2649,6 +3041,12 @@ __all__ = [
|
|
|
2649
3041
|
"Audit",
|
|
2650
3042
|
"AuditProcedure",
|
|
2651
3043
|
"AuditRequirement",
|
|
3044
|
+
"Challenge",
|
|
3045
|
+
"ChallengeContent",
|
|
3046
|
+
"ChallengeContentPage",
|
|
3047
|
+
"ChallengeSubmission",
|
|
3048
|
+
"ChallengeTask",
|
|
3049
|
+
"ChallengeTaskBase",
|
|
2652
3050
|
"Concern",
|
|
2653
3051
|
"ConcernBase",
|
|
2654
3052
|
"Container",
|
|
@@ -2769,6 +3167,9 @@ __all__ = [
|
|
|
2769
3167
|
"TagName",
|
|
2770
3168
|
"TagNameType",
|
|
2771
3169
|
"TaskSchema",
|
|
3170
|
+
"Team",
|
|
3171
|
+
"TeamMember",
|
|
3172
|
+
"TeamAffiliation",
|
|
2772
3173
|
"UseCase",
|
|
2773
3174
|
"Volume",
|
|
2774
3175
|
"VolumeMount",
|
|
@@ -2791,6 +3192,7 @@ __all__ = [
|
|
|
2791
3192
|
"ModelStatusReason",
|
|
2792
3193
|
"ReportStatus",
|
|
2793
3194
|
"ReportStatusReason",
|
|
3195
|
+
"body_maxlen",
|
|
2794
3196
|
"identifier_regex",
|
|
2795
3197
|
"identifier_maxlen",
|
|
2796
3198
|
"is_status_terminal",
|
dyff/schema/v0/r1/requests.py
CHANGED
|
@@ -26,6 +26,8 @@ from .base import DyffBaseModel, JsonMergePatchSemantics
|
|
|
26
26
|
from .platform import (
|
|
27
27
|
AnalysisBase,
|
|
28
28
|
AnalysisScope,
|
|
29
|
+
ChallengeContent,
|
|
30
|
+
ChallengeTaskBase,
|
|
29
31
|
ConcernBase,
|
|
30
32
|
DatasetBase,
|
|
31
33
|
DataView,
|
|
@@ -60,12 +62,14 @@ class DyffRequestDefaultValidators(DyffBaseModel):
|
|
|
60
62
|
"""
|
|
61
63
|
|
|
62
64
|
@pydantic.model_validator(mode="after")
|
|
63
|
-
def _require_datetime_timezone_aware(
|
|
64
|
-
for k, v in
|
|
65
|
+
def _require_datetime_timezone_aware(self):
|
|
66
|
+
for k, v in self.__dict__.items():
|
|
65
67
|
if isinstance(v, datetime):
|
|
66
68
|
if v.tzinfo is None:
|
|
67
|
-
raise ValueError(
|
|
68
|
-
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"{self.__class__.__qualname__}.{k}: timezone not set"
|
|
71
|
+
)
|
|
72
|
+
return self
|
|
69
73
|
|
|
70
74
|
|
|
71
75
|
class DyffRequestBase(SchemaVersion, DyffRequestDefaultValidators):
|
|
@@ -136,6 +140,17 @@ class ArtifactCreateRequest(DyffEntityCreateRequest):
|
|
|
136
140
|
pass
|
|
137
141
|
|
|
138
142
|
|
|
143
|
+
class ChallengeCreateRequest(DyffEntityCreateRequest):
|
|
144
|
+
content: ChallengeContent = pydantic.Field(
|
|
145
|
+
default_factory=ChallengeContent,
|
|
146
|
+
description="Content of the challenge view in the Dyff App.",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class ChallengeTaskCreateRequest(DyffEntityCreateRequest, ChallengeTaskBase):
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
|
|
139
154
|
class ConcernCreateRequest(DyffEntityCreateRequest, ConcernBase):
|
|
140
155
|
@pydantic.field_validator("documentation", check_fields=False)
|
|
141
156
|
def _validate_documentation(
|
|
@@ -171,14 +186,14 @@ class InferenceServiceCreateRequest(DyffEntityCreateRequest, InferenceServiceBas
|
|
|
171
186
|
)
|
|
172
187
|
|
|
173
188
|
@pydantic.model_validator(mode="after")
|
|
174
|
-
def check_runner_and_image_specified(
|
|
175
|
-
if
|
|
189
|
+
def check_runner_and_image_specified(self):
|
|
190
|
+
if self.runner is None:
|
|
176
191
|
raise ValueError("must specify .runner in new inference services")
|
|
177
|
-
image =
|
|
178
|
-
imageRef =
|
|
192
|
+
image = self.runner.image is not None
|
|
193
|
+
imageRef = self.runner.imageRef is not None
|
|
179
194
|
if sum([image, imageRef]) != 1:
|
|
180
195
|
raise ValueError("must specify exactly one of .runner.{image, imageRef}")
|
|
181
|
-
return
|
|
196
|
+
return self
|
|
182
197
|
|
|
183
198
|
|
|
184
199
|
class InferenceSessionCreateRequest(DyffEntityCreateRequest, InferenceSessionBase):
|
|
@@ -213,14 +228,14 @@ class EvaluationCreateRequest(DyffEntityCreateRequest, EvaluationBase):
|
|
|
213
228
|
)
|
|
214
229
|
|
|
215
230
|
@pydantic.model_validator(mode="after")
|
|
216
|
-
def check_session_exactly_one(
|
|
217
|
-
session =
|
|
218
|
-
session_ref =
|
|
231
|
+
def check_session_exactly_one(self):
|
|
232
|
+
session = self.inferenceSession is not None
|
|
233
|
+
session_ref = self.inferenceSessionReference is not None
|
|
219
234
|
if not (session ^ session_ref):
|
|
220
235
|
raise ValueError(
|
|
221
236
|
"must specify exactly one of {inferenceSession, inferenceSessionReference}"
|
|
222
237
|
)
|
|
223
|
-
return
|
|
238
|
+
return self
|
|
224
239
|
|
|
225
240
|
@staticmethod
|
|
226
241
|
def repeat_of(evaluation: Evaluation) -> EvaluationCreateRequest:
|
|
@@ -286,6 +301,10 @@ class ReportCreateRequest(DyffEntityCreateRequest, ReportBase):
|
|
|
286
301
|
# ----------------------------------------------------------------------------
|
|
287
302
|
|
|
288
303
|
|
|
304
|
+
class ChallengeContentEditRequest(DyffRequestBase, commands.EditChallengeContentPatch):
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
|
|
289
308
|
class DocumentationEditRequest(
|
|
290
309
|
DyffRequestBase, commands.EditEntityDocumentationAttributes
|
|
291
310
|
):
|
|
@@ -471,6 +490,9 @@ __all__ = [
|
|
|
471
490
|
"ArtifactCreateRequest",
|
|
472
491
|
"ArtifactQueryRequest",
|
|
473
492
|
"AuditQueryRequest",
|
|
493
|
+
"ChallengeContentEditRequest",
|
|
494
|
+
"ChallengeCreateRequest",
|
|
495
|
+
"ChallengeTaskCreateRequest",
|
|
474
496
|
"ConcernCreateRequest",
|
|
475
497
|
"DyffEntityCreateRequest",
|
|
476
498
|
"DyffEntityQueryRequest",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dyff-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.36.0
|
|
4
4
|
Summary: Data models for the Dyff AI auditing platform.
|
|
5
5
|
Author-email: Digital Safety Research Institute <contact@dsri.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -21,6 +21,8 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
License-File: NOTICE
|
|
23
23
|
Requires-Dist: canonicaljson==2.0.0
|
|
24
|
+
Requires-Dist: email-validator
|
|
25
|
+
Requires-Dist: google-i18n-address
|
|
24
26
|
Requires-Dist: hypothesis
|
|
25
27
|
Requires-Dist: hypothesis-jsonschema
|
|
26
28
|
Requires-Dist: jsonpath-ng
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
dyff/schema/__init__.py,sha256=w7OWDFuyGKd6xt_yllNtKzHahPgywrfU4Ue02psYaMA,2244
|
|
2
|
-
dyff/schema/_version.py,sha256=
|
|
2
|
+
dyff/schema/_version.py,sha256=WugzP-ohXoqseZsih5K8n5URp30AcEarRZlsq9obhyE,80
|
|
3
3
|
dyff/schema/adapters.py,sha256=YMTHv_2VlLGFp-Kqwa6H51hjffHmk8gXjZilHysIF5Q,123
|
|
4
4
|
dyff/schema/annotations.py,sha256=nE6Jk1PLqlShj8uqjE_EzZC9zYnTDW5AVtQcjysiK8M,10018
|
|
5
5
|
dyff/schema/base.py,sha256=jvaNtsSZyFfsdUZTcY_U-yfLY5_GyrMxSXhON2R9XR0,119
|
|
@@ -27,10 +27,10 @@ dyff/schema/v0/__init__.py,sha256=L5y8UhRnojerPYHumsxQJRcHCNz8Hj9NM8b47mewMNs,92
|
|
|
27
27
|
dyff/schema/v0/r1/__init__.py,sha256=L5y8UhRnojerPYHumsxQJRcHCNz8Hj9NM8b47mewMNs,92
|
|
28
28
|
dyff/schema/v0/r1/adapters.py,sha256=hpwCSW8lkMkUKCLe0zaMUDu-VS_caSxJvPsECEi_XRA,33069
|
|
29
29
|
dyff/schema/v0/r1/base.py,sha256=1VJXVLKldOq3aH2HdVgxXXk4DJTZEIiaTa4GzMKzziU,20228
|
|
30
|
-
dyff/schema/v0/r1/commands.py,sha256=
|
|
31
|
-
dyff/schema/v0/r1/oci.py,sha256=
|
|
32
|
-
dyff/schema/v0/r1/platform.py,sha256=
|
|
33
|
-
dyff/schema/v0/r1/requests.py,sha256=
|
|
30
|
+
dyff/schema/v0/r1/commands.py,sha256=mFKuPtRrk3Zr7Ce2snmqIG_vGIPCv-RTiXDo6BLILTU,17485
|
|
31
|
+
dyff/schema/v0/r1/oci.py,sha256=YjHDVBJ2IIxqijll70OK6pM-qT6pq8tvU7D3YB9vGM0,6700
|
|
32
|
+
dyff/schema/v0/r1/platform.py,sha256=UVDc4loKNQIw0J6PD_aDSGhxQLdorwz8lXwikhf-ORo,102071
|
|
33
|
+
dyff/schema/v0/r1/requests.py,sha256=v9t8wg6ZYGCPp05HFtOnw093nCD9ED_lLOK__4Z2d4s,18584
|
|
34
34
|
dyff/schema/v0/r1/responses.py,sha256=nxy7FPtfw2B_bljz5UGGuSE79HTkDQxKH56AJVmd4Qo,1287
|
|
35
35
|
dyff/schema/v0/r1/test.py,sha256=X6dUyVd5svcPCI-PBMOAqEfK9jv3bRDvkQTJzwS96c0,10720
|
|
36
36
|
dyff/schema/v0/r1/version.py,sha256=NONebgcv5Thsw_ymud6PacZdGjV6ndBrmLnap-obcpo,428
|
|
@@ -43,9 +43,9 @@ dyff/schema/v0/r1/dataset/text.py,sha256=MYG5seGODDryRSCy-g0Unh5dD0HCytmZ3FeElC-
|
|
|
43
43
|
dyff/schema/v0/r1/dataset/vision.py,sha256=tJFF4dkhHX0UXTj1sPW-G22xTSI40gbYO465FuvmvAU,443
|
|
44
44
|
dyff/schema/v0/r1/io/__init__.py,sha256=L5y8UhRnojerPYHumsxQJRcHCNz8Hj9NM8b47mewMNs,92
|
|
45
45
|
dyff/schema/v0/r1/io/vllm.py,sha256=vWyLg-susbg0JDfv6VExBpgFdU2GHP2a14ChOdbckvs,5321
|
|
46
|
-
dyff_schema-0.
|
|
47
|
-
dyff_schema-0.
|
|
48
|
-
dyff_schema-0.
|
|
49
|
-
dyff_schema-0.
|
|
50
|
-
dyff_schema-0.
|
|
51
|
-
dyff_schema-0.
|
|
46
|
+
dyff_schema-0.36.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
47
|
+
dyff_schema-0.36.0.dist-info/licenses/NOTICE,sha256=YONACu0s_Ui6jNi-wtEsVQbTU1JIkh8wvLH6d1-Ni_w,43
|
|
48
|
+
dyff_schema-0.36.0.dist-info/METADATA,sha256=kinDhGaP-46BDtS4QXZ6xFLgsCLhLjy66JnqDa3zdfk,3734
|
|
49
|
+
dyff_schema-0.36.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
50
|
+
dyff_schema-0.36.0.dist-info/top_level.txt,sha256=9e3VVdeX73t_sUJOPQPCcGtYO1JhoErhHIi3WoWGcFI,5
|
|
51
|
+
dyff_schema-0.36.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|