Skip to content

Commit 06c0ee3

Browse files
authored
Merge pull request #245 from dandi/pydantic-discriminated-unions
Use discriminated unions to provide more helpful error messages
2 parents e135307 + abccf00 commit 06c0ee3

File tree

5 files changed

+49
-8
lines changed

5 files changed

+49
-8
lines changed

dandischema/consts.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
DANDI_SCHEMA_VERSION = "0.6.7"
1+
DANDI_SCHEMA_VERSION = "0.6.8"
22
ALLOWED_INPUT_SCHEMAS = [
33
"0.4.4",
44
"0.5.1",
@@ -10,6 +10,7 @@
1010
"0.6.4",
1111
"0.6.5",
1212
"0.6.6",
13+
"0.6.7",
1314
]
1415

1516
# ATM we allow only for a single target version which is current

dandischema/models.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
)
2323
from pydantic.json_schema import JsonSchemaValue
2424
from pydantic_core import CoreSchema
25+
from typing_extensions import (
26+
Annotated, # TODO: import from `typing` when Python 3.8 support is dropped
27+
)
2528
from zarr_checksum.checksum import InvalidZarrChecksum, ZarrDirectoryDigest
2629

2730
from .consts import DANDI_SCHEMA_VERSION
@@ -1188,9 +1191,14 @@ class Activity(DandiBaseModel):
11881191

11891192
# isPartOf: Optional["Activity"] = Field(None, json_schema_extra={"nskey": "schema"})
11901193
# hasPart: Optional["Activity"] = Field(None, json_schema_extra={"nskey": "schema"})
1191-
wasAssociatedWith: Optional[List[Union[Person, Organization, Software, Agent]]] = (
1192-
Field(None, json_schema_extra={"nskey": "prov"})
1193-
)
1194+
wasAssociatedWith: Optional[
1195+
List[
1196+
Annotated[
1197+
Union[Person, Organization, Software, Agent],
1198+
Field(discriminator="schemaKey"),
1199+
]
1200+
]
1201+
] = Field(None, json_schema_extra={"nskey": "prov"})
11941202
used: Optional[List[Equipment]] = Field(
11951203
None,
11961204
description="A listing of equipment used for the activity.",
@@ -1467,13 +1475,21 @@ class CommonModel(DandiBaseModel):
14671475
description="A description of the item.",
14681476
json_schema_extra={"nskey": "schema"},
14691477
)
1470-
contributor: Optional[List[Union[Person, Organization]]] = Field(
1478+
contributor: Optional[
1479+
List[Annotated[Union[Person, Organization], Field(discriminator="schemaKey")]]
1480+
] = Field(
14711481
None,
14721482
title="Contributors",
14731483
description="Contributors to this item: persons or organizations.",
14741484
json_schema_extra={"nskey": "schema"},
14751485
)
1476-
about: Optional[List[Union[Disorder, Anatomy, GenericType]]] = Field(
1486+
about: Optional[
1487+
List[
1488+
Annotated[
1489+
Union[Disorder, Anatomy, GenericType], Field(discriminator="schemaKey")
1490+
]
1491+
]
1492+
] = Field(
14771493
None,
14781494
title="Subject matter of the dataset",
14791495
description="The subject matter of the content, such as disorders, brain anatomy.",
@@ -1586,7 +1602,9 @@ def contributor_musthave_contact(
15861602
max_length=3000,
15871603
json_schema_extra={"nskey": "schema"},
15881604
)
1589-
contributor: List[Union[Person, Organization]] = Field(
1605+
contributor: List[
1606+
Annotated[Union[Person, Organization], Field(discriminator="schemaKey")]
1607+
] = Field(
15901608
title="Dandiset contributors",
15911609
description="People or Organizations that have contributed to this Dandiset.",
15921610
json_schema_extra={"nskey": "schema"},

dandischema/tests/data/metadata/meta_000008.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
{
99
"schemaKey": "Person",
1010
"name": "Scala, Federico",
11+
"email": "fscala@example.com",
1112
"roleName": [
1213
"dcite:DataCollector",
1314
"dcite:Author",
@@ -150,6 +151,7 @@
150151
"schemaKey": "Person",
151152
"identifier": "0000-0002-4305-6376",
152153
"name": "Tolias, Andreas Savas",
154+
"email": "atolias@example.com",
153155
"roleName": [
154156
"dcite:Author",
155157
"dcite:ContactPerson"

dandischema/tests/test_datacite.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def metadata_basic() -> Dict[str, Any]:
7272
"name": "A_last, A_first",
7373
"email": "nemo@example.com",
7474
"roleName": [RoleType("dcite:ContactPerson")],
75+
"schemaKey": "Person",
7576
}
7677
],
7778
"license": [LicenseType("spdx:CC-BY-4.0")],
@@ -195,12 +196,18 @@ def test_datacite(dandi_id: str, schema: Any) -> None:
195196
{
196197
"name": "A_last, A_first",
197198
"roleName": [RoleType("dcite:ContactPerson")],
199+
"email": "nemo@example.com",
200+
"schemaKey": "Person",
198201
},
199202
{
200203
"name": "B_last, B_first",
201204
"roleName": [RoleType("dcite:Author")],
205+
"schemaKey": "Person",
206+
},
207+
{
208+
"name": "C_last, C_first",
209+
"schemaKey": "Person",
202210
},
203-
{"name": "C_last, C_first"},
204211
],
205212
},
206213
{
@@ -218,10 +225,13 @@ def test_datacite(dandi_id: str, schema: Any) -> None:
218225
{
219226
"name": "A_last, A_first",
220227
"roleName": [RoleType("dcite:ContactPerson")],
228+
"email": "nemo@example.com",
229+
"schemaKey": "Person",
221230
},
222231
{
223232
"name": "B_last, B_first",
224233
"roleName": [RoleType("dcite:Sponsor")],
234+
"schemaKey": "Person",
225235
},
226236
],
227237
},
@@ -237,11 +247,14 @@ def test_datacite(dandi_id: str, schema: Any) -> None:
237247
{
238248
"name": "A_last, A_first",
239249
"roleName": [RoleType("dcite:ContactPerson")],
250+
"email": "nemo@example.com",
251+
"schemaKey": "Person",
240252
},
241253
{
242254
"name": "B_last, B_first",
243255
"identifier": "0000-0001-0000-0000",
244256
"roleName": [RoleType("dcite:Sponsor")],
257+
"schemaKey": "Person",
245258
},
246259
],
247260
},
@@ -264,11 +277,14 @@ def test_datacite(dandi_id: str, schema: Any) -> None:
264277
{
265278
"name": "A_last, A_first",
266279
"roleName": [RoleType("dcite:ContactPerson")],
280+
"email": "nemo@example.com",
281+
"schemaKey": "Person",
267282
},
268283
{
269284
"name": "B_last, B_first",
270285
"identifier": "0000-0001-0000-0000",
271286
"roleName": [RoleType("dcite:Funder")],
287+
"schemaKey": "Person",
272288
},
273289
],
274290
},
@@ -297,10 +313,13 @@ def test_datacite(dandi_id: str, schema: Any) -> None:
297313
RoleType("dcite:Software"),
298314
],
299315
"identifier": "0000-0001-0000-0000",
316+
"schemaKey": "Person",
300317
},
301318
{
302319
"name": "B_last, B_first",
303320
"roleName": [RoleType("dcite:ContactPerson")],
321+
"email": "nemo@example.com",
322+
"schemaKey": "Person",
304323
},
305324
],
306325
},

dandischema/tests/test_models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ def test_dantimeta_1() -> None:
381381
"name": "last name, first name",
382382
"email": "someone@dandiarchive.org",
383383
"roleName": [RoleType("dcite:ContactPerson")],
384+
"schemaKey": "Person",
384385
}
385386
],
386387
"license": [LicenseType("spdx:CC-BY-4.0")],

0 commit comments

Comments
 (0)