Skip to content

Commit 87b2040

Browse files
yarikopticclaude
andcommitted
Fix downgrade migrations: correct version, add sameAs, handle empty strings
- SIMPLE_DOWNGRADES: "0.6.11" -> "0.7.0" (no 0.6.11 was ever released) - Add sameAs to downgrade fields (added on master via PR #364) - Include str in empty-value check so releaseNotes="" is treated as empty - Rewrite test to use DANDI_SCHEMA_VERSION and minimal metadata dict (0.6.11 was not in ALLOWED_INPUT_SCHEMAS, basic_publishmeta needed instance_name positional arg) - Add test coverage for sameAs downgrade (empty list, non-empty list) Co-Authored-By: Claude Code 2.1.63 / Claude Opus 4.6 <noreply@anthropic.com>
1 parent 427310a commit 87b2040

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

dandischema/metadata.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,11 +451,12 @@ def migrate(
451451
# Downgrades
452452

453453
# Simple downgrades that just require removing fields, which is totally fine
454-
# if they are empty, as they are None or empty containers (list, tuple, etc).
454+
# if they are empty, as they are None or empty containers (list, tuple, etc)
455+
# or empty strings.
455456
# List only those for which such notion of "empty" applies.
456457
SIMPLE_DOWNGRADES = [
457458
# version added, fields to remove
458-
("0.6.11", ["releaseNotes"]),
459+
("0.7.0", ["sameAs", "releaseNotes"]),
459460
]
460461
for ver_added, fields in SIMPLE_DOWNGRADES:
461462
# additional guards are via ALLOWED_TARGET_SCHEMAS
@@ -465,7 +466,7 @@ def migrate(
465466
value = obj_migrated.get(field)
466467
# Explicit check for "empty" value per above description.
467468
if value is None or (
468-
not value and isinstance(value, (list, tuple, dict, set))
469+
not value and isinstance(value, (list, tuple, dict, set, str))
469470
):
470471
del obj_migrated[field]
471472
else:

dandischema/tests/test_metadata.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
DOI_PREFIX,
1818
INSTANCE_NAME,
1919
METADATA_DIR,
20-
basic_publishmeta,
2120
skipif_instance_name_not_dandi,
2221
skipif_no_network,
2322
skipif_no_test_dandiset_metadata_dir,
@@ -497,35 +496,59 @@ def test_migrate_schemaversion_update() -> None:
497496

498497

499498
@pytest.mark.ai_generated
500-
def test_migrate_downgrade_releasenotes() -> None:
501-
"""Test downgrade from 0.6.11 to 0.6.10 handling releaseNotes field"""
499+
def test_migrate_downgrade() -> None:
500+
"""Test downgrade from 0.7.0 to 0.6.10 handling releaseNotes and sameAs fields"""
502501

503-
# Create a basic PublishedDandiset metadata in 0.6.11 format
504-
meta_dict = {
505-
"schemaVersion": "0.6.11",
502+
# Minimal metadata at current (0.7.0) version
503+
meta_dict: dict = {
504+
"schemaKey": "Dandiset",
505+
"schemaVersion": DANDI_SCHEMA_VERSION,
506+
"identifier": "DANDI:000000",
506507
}
507-
meta_dict.update(basic_publishmeta(dandi_id="999999"))
508508

509-
# Test 1: Downgrade without releaseNotes (should succeed)
509+
# Test 1: Downgrade without new fields (should succeed)
510510
downgraded = migrate(meta_dict, to_version="0.6.10", skip_validation=True)
511511
assert downgraded["schemaVersion"] == "0.6.10"
512512
assert "releaseNotes" not in downgraded
513+
assert "sameAs" not in downgraded
513514

514515
# Test 2: Downgrade with empty releaseNotes (should succeed)
515516
meta_dict["releaseNotes"] = ""
516517
downgraded = migrate(meta_dict, to_version="0.6.10", skip_validation=True)
517518
assert downgraded["schemaVersion"] == "0.6.10"
518519
assert "releaseNotes" not in downgraded
519520

520-
# Test 3: Downgrade with non-empty releaseNotes (should fail)
521+
# Test 3: Downgrade with None releaseNotes (should succeed)
522+
meta_dict["releaseNotes"] = None
523+
downgraded = migrate(meta_dict, to_version="0.6.10", skip_validation=True)
524+
assert downgraded["schemaVersion"] == "0.6.10"
525+
assert "releaseNotes" not in downgraded
526+
527+
# Test 4: Downgrade with empty sameAs list (should succeed)
528+
meta_dict.pop("releaseNotes")
529+
meta_dict["sameAs"] = []
530+
downgraded = migrate(meta_dict, to_version="0.6.10", skip_validation=True)
531+
assert downgraded["schemaVersion"] == "0.6.10"
532+
assert "sameAs" not in downgraded
533+
534+
# Test 5: Downgrade with non-empty releaseNotes (should fail)
535+
meta_dict.pop("sameAs")
521536
meta_dict["releaseNotes"] = "Releasing during testing"
522537
with pytest.raises(ValueError, match="Cannot downgrade to 0.6.10 from"):
523538
migrate(meta_dict, to_version="0.6.10", skip_validation=True)
524539

525-
# Test 4: No-op migration (already at target version)
526-
meta_dict_0610 = meta_dict.copy()
527-
meta_dict_0610["schemaVersion"] = "0.6.10"
528-
meta_dict_0610.pop("releaseNotes")
540+
# Test 6: Downgrade with non-empty sameAs (should fail)
541+
meta_dict.pop("releaseNotes")
542+
meta_dict["sameAs"] = ["dandi://DANDI-SANDBOX/123456"]
543+
with pytest.raises(ValueError, match="Cannot downgrade to 0.6.10 from"):
544+
migrate(meta_dict, to_version="0.6.10", skip_validation=True)
545+
546+
# Test 7: No-op migration (already at target version)
547+
meta_dict_0610 = {
548+
"schemaKey": "Dandiset",
549+
"schemaVersion": "0.6.10",
550+
"identifier": "DANDI:000000",
551+
}
529552
migrated = migrate(meta_dict_0610, to_version="0.6.10", skip_validation=True)
530553
assert migrated == meta_dict_0610
531554
assert migrated is not meta_dict_0610 # but we do create a copy

0 commit comments

Comments
 (0)