|
41 | 41 | _INSTANCE_CONFIG = get_instance_config() |
42 | 42 |
|
43 | 43 |
|
| 44 | +@pytest.fixture |
| 45 | +def base_dandiset_metadata() -> dict[str, Any]: |
| 46 | + """ |
| 47 | + Fixture providing basic Dandiset metadata for constructing a `Dandiset` instance. |
| 48 | +
|
| 49 | + Returns: |
| 50 | + Dict[str, Any] |
| 51 | + A dictionary containing basic Dandiset metadata without `doi`, `datePublished`, |
| 52 | + and `publishedBy`, suitable for constructing a `Dandiset` instance but not a |
| 53 | + `PublishedDandiset` instance. |
| 54 | +
|
| 55 | + Note: |
| 56 | + This metadata is returned by a fixture to ensure that each test receives a fresh |
| 57 | + copy of the metadata dictionary. |
| 58 | + """ |
| 59 | + |
| 60 | + return { |
| 61 | + "identifier": f"{INSTANCE_NAME}:999999", |
| 62 | + "id": f"{INSTANCE_NAME}:999999/draft", |
| 63 | + "version": "1.0.0", |
| 64 | + "name": "testing dataset", |
| 65 | + "description": "testing", |
| 66 | + "contributor": [ |
| 67 | + { |
| 68 | + "name": "last name, first name", |
| 69 | + "email": "someone@dandiarchive.org", |
| 70 | + "roleName": [RoleType("dcite:ContactPerson")], |
| 71 | + "schemaKey": "Person", |
| 72 | + } |
| 73 | + ], |
| 74 | + "license": [LicenseType("spdx:CC-BY-4.0")], |
| 75 | + "citation": "Last, first (2021). Test citation.", |
| 76 | + "assetsSummary": { |
| 77 | + "numberOfBytes": 0, |
| 78 | + "numberOfFiles": 0, |
| 79 | + "dataStandard": [{"name": "NWB"}], |
| 80 | + "approach": [{"name": "electrophysiology"}], |
| 81 | + "measurementTechnique": [{"name": "two-photon microscopy technique"}], |
| 82 | + "species": [{"name": "Human"}], |
| 83 | + }, |
| 84 | + "manifestLocation": [ |
| 85 | + "https://api.dandiarchive.org/api/dandisets/999999/versions/draft/assets/" |
| 86 | + ], |
| 87 | + "url": "https://dandiarchive.org/dandiset/999999/draft", |
| 88 | + } |
| 89 | + |
| 90 | + |
44 | 91 | @pytest.mark.parametrize( |
45 | 92 | ("y_type", "anys_value"), |
46 | 93 | [ |
@@ -403,46 +450,15 @@ def test_autogenerated_titles() -> None: |
403 | 450 |
|
404 | 451 |
|
405 | 452 | @skipif_no_doi_prefix |
406 | | -def test_dandimeta_1() -> None: |
| 453 | +def test_dandimeta_1(base_dandiset_metadata: dict[str, Any]) -> None: |
407 | 454 | """checking basic metadata for publishing""" |
408 | 455 |
|
409 | 456 | assert DOI_PREFIX is not None |
410 | 457 |
|
411 | | - # metadata without doi, datePublished and publishedBy |
412 | | - meta_dict: Dict[str, Any] = { |
413 | | - "identifier": f"{INSTANCE_NAME}:999999", |
414 | | - "id": f"{INSTANCE_NAME}:999999/draft", |
415 | | - "version": "1.0.0", |
416 | | - "name": "testing dataset", |
417 | | - "description": "testing", |
418 | | - "contributor": [ |
419 | | - { |
420 | | - "name": "last name, first name", |
421 | | - "email": "someone@dandiarchive.org", |
422 | | - "roleName": [RoleType("dcite:ContactPerson")], |
423 | | - "schemaKey": "Person", |
424 | | - } |
425 | | - ], |
426 | | - "license": [LicenseType("spdx:CC-BY-4.0")], |
427 | | - "citation": "Last, first (2021). Test citation.", |
428 | | - "assetsSummary": { |
429 | | - "numberOfBytes": 0, |
430 | | - "numberOfFiles": 0, |
431 | | - "dataStandard": [{"name": "NWB"}], |
432 | | - "approach": [{"name": "electrophysiology"}], |
433 | | - "measurementTechnique": [{"name": "two-photon microscopy technique"}], |
434 | | - "species": [{"name": "Human"}], |
435 | | - }, |
436 | | - "manifestLocation": [ |
437 | | - "https://api.dandiarchive.org/api/dandisets/999999/versions/draft/assets/" |
438 | | - ], |
439 | | - "url": "https://dandiarchive.org/dandiset/999999/draft", |
440 | | - } |
441 | | - |
442 | 458 | # should work for Dandiset but PublishedDandiset should raise an error |
443 | | - Dandiset(**meta_dict) |
| 459 | + Dandiset(**base_dandiset_metadata) |
444 | 460 | with pytest.raises(ValidationError) as exc: |
445 | | - PublishedDandiset(**meta_dict) |
| 461 | + PublishedDandiset(**base_dandiset_metadata) |
446 | 462 |
|
447 | 463 | ErrDetail = namedtuple("ErrDetail", ["type", "msg"]) |
448 | 464 |
|
@@ -490,21 +506,23 @@ def test_dandimeta_1() -> None: |
490 | 506 |
|
491 | 507 | # after adding basic meta required to publish: doi, datePublished, publishedBy, assetsSummary, |
492 | 508 | # so PublishedDandiset should work |
493 | | - meta_dict["url"] = "https://dandiarchive.org/dandiset/999999/0.0.0" |
494 | | - meta_dict["id"] = f"{INSTANCE_NAME}:999999/0.0.0" |
495 | | - meta_dict["version"] = "0.0.0" |
496 | | - meta_dict.update( |
| 509 | + base_dandiset_metadata["url"] = "https://dandiarchive.org/dandiset/999999/0.0.0" |
| 510 | + base_dandiset_metadata["id"] = f"{INSTANCE_NAME}:999999/0.0.0" |
| 511 | + base_dandiset_metadata["version"] = "0.0.0" |
| 512 | + base_dandiset_metadata.update( |
497 | 513 | basic_publishmeta(INSTANCE_NAME, dandi_id="999999", prefix=DOI_PREFIX) |
498 | 514 | ) |
499 | | - meta_dict["assetsSummary"].update(**{"numberOfBytes": 1, "numberOfFiles": 1}) |
| 515 | + base_dandiset_metadata["assetsSummary"].update( |
| 516 | + **{"numberOfBytes": 1, "numberOfFiles": 1} |
| 517 | + ) |
500 | 518 |
|
501 | 519 | # Test that releaseNotes is optional (can be omitted) |
502 | | - dandiset_without_notes = PublishedDandiset(**meta_dict) |
| 520 | + dandiset_without_notes = PublishedDandiset(**base_dandiset_metadata) |
503 | 521 | assert dandiset_without_notes.releaseNotes is None |
504 | 522 |
|
505 | 523 | # Test that releaseNotes can be set to a string value |
506 | | - meta_dict["releaseNotes"] = "Releasing during testing" |
507 | | - dandiset_with_notes = PublishedDandiset(**meta_dict) |
| 524 | + base_dandiset_metadata["releaseNotes"] = "Releasing during testing" |
| 525 | + dandiset_with_notes = PublishedDandiset(**base_dandiset_metadata) |
508 | 526 | assert dandiset_with_notes.releaseNotes == "Releasing during testing" |
509 | 527 |
|
510 | 528 | # Test that releaseNotes appears in model_dump |
@@ -983,3 +1001,78 @@ class VendoredFieldModel(BaseModel): |
983 | 1001 | # Validate the invalid vendored fields against the vendored patterns |
984 | 1002 | with pytest.raises(ValidationError): |
985 | 1003 | VendoredFieldModel.model_validate(invalid_vendored_fields) |
| 1004 | + |
| 1005 | + |
| 1006 | +class TestDandisetSameAs: |
| 1007 | + def test_not_specified(self, base_dandiset_metadata: dict[str, Any]) -> None: |
| 1008 | + """ |
| 1009 | + Test the case that `sameAs` is not specified in instantiating a `Dandiset` |
| 1010 | + """ |
| 1011 | + dandiset = Dandiset.model_validate(base_dandiset_metadata) |
| 1012 | + assert dandiset.sameAs is None |
| 1013 | + |
| 1014 | + def test_empty_list(self, base_dandiset_metadata: dict[str, Any]) -> None: |
| 1015 | + """ |
| 1016 | + Test the case that `sameAs` in a `Dandiset` is initialized to an empty list |
| 1017 | + """ |
| 1018 | + base_dandiset_metadata["sameAs"] = [] |
| 1019 | + dandiset = Dandiset.model_validate(base_dandiset_metadata) |
| 1020 | + assert dandiset.sameAs == [] |
| 1021 | + |
| 1022 | + @pytest.mark.parametrize( |
| 1023 | + "dandi_urls", |
| 1024 | + [ |
| 1025 | + ["dandi://DANDI-SANDBOX/123456"], |
| 1026 | + ["dandi://DANDI-SANDBOX/123456@draft"], |
| 1027 | + ["dandi://DANDI-SANDBOX/123456@1.22.33"], |
| 1028 | + ["dandi://DANDI-SANDBOX/123456/path"], |
| 1029 | + ["dandi://DANDI-SANDBOX/123456@draft/path"], |
| 1030 | + ["dandi://DANDI-SANDBOX/123456@1.22.33/path"], |
| 1031 | + ["dandi://EMBER-DANDI/123456"], |
| 1032 | + ["dandi://DANDI-SANDBOX/123456", "dandi://EMBER-DANDI/123456"], |
| 1033 | + ["dandi://A/123456", "dandi://B/654321"], |
| 1034 | + ], |
| 1035 | + ) |
| 1036 | + def test_with_valid_dandi_urls( |
| 1037 | + self, dandi_urls: list[str], base_dandiset_metadata: dict[str, Any] |
| 1038 | + ) -> None: |
| 1039 | + """ |
| 1040 | + Test the case that `sameAs` is initialized to a list of valid DANDI URLs |
| 1041 | + """ |
| 1042 | + base_dandiset_metadata["sameAs"] = dandi_urls |
| 1043 | + dandiset = Dandiset.model_validate(base_dandiset_metadata) |
| 1044 | + assert dandiset.sameAs == dandi_urls |
| 1045 | + |
| 1046 | + @pytest.mark.parametrize( |
| 1047 | + "dandi_urls", |
| 1048 | + [ |
| 1049 | + # List of invalid DANDI URLs |
| 1050 | + ["dandi://DANDI-SANDBOX/123456@abc"], |
| 1051 | + ["dandi://DANDI-SANDBOX/123456@1.22.33.44"], |
| 1052 | + ["dandi://DANDI-SANDBOX/123456/"], |
| 1053 | + ["dandi://DANDI-SANDBOX/123456@draft/"], |
| 1054 | + ["dandi://DANDI-SANDBOX/123456@1.22.33/"], |
| 1055 | + ["http://DANDI-SANDBOX/123456"], # Not dandi:// scheme |
| 1056 | + ["dandi://DANDI- SANDBOX/123456"], # Containing a space |
| 1057 | + ["dandi://"], # Missing instance name and dandiset id |
| 1058 | + ["dandi://DANDI-SANDBOX"], # Missing dandiset id |
| 1059 | + ["dandi://DANDI-SANDBOX/12345"], # Dandiset id too short |
| 1060 | + ["dandi://-DANDI/123456"], # Invalid instance name |
| 1061 | + ["dandi://EMBER3DANDI/123456"], # Invalid instance name |
| 1062 | + ["dandi://DANDI-SANDBOX/123456", "dandi://DANDI- SANDBOX/123456"], |
| 1063 | + [42], |
| 1064 | + # Value that is not a list |
| 1065 | + "DANDI-SANDBOX:123456", |
| 1066 | + 42, |
| 1067 | + ], |
| 1068 | + ) |
| 1069 | + def test_with_invalid_dandi_urls( |
| 1070 | + self, dandi_urls: Any, base_dandiset_metadata: dict[str, Any] |
| 1071 | + ) -> None: |
| 1072 | + """ |
| 1073 | + Test the case that `sameAs` is initialized to an invalid list of DANDI URLs |
| 1074 | + or a value that is not a list |
| 1075 | + """ |
| 1076 | + base_dandiset_metadata["sameAs"] = dandi_urls |
| 1077 | + with pytest.raises(ValidationError): |
| 1078 | + Dandiset.model_validate(base_dandiset_metadata) |
0 commit comments