Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions brainglobe_atlasapi/atlas_generation/validate_atlases.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,45 @@ def validate_annotation_symmetry(atlas: BrainGlobeAtlas):
return True


def validate_unique_acronyms(atlas: BrainGlobeAtlas):
"""Validate that all structure acronyms in the atlas are unique.

Duplicate acronyms are incompatible with the current implementation
of brainglobe-atlasapi as the acronym is used as a primary key to
fetch details for a region.

Parameters
----------
atlas : BrainGlobeAtlas
The BrainGlobeAtlas object to validate.

Returns
-------
bool
True if all acronyms are unique.

Raises
------
AssertionError
If any duplicate acronyms are found in the atlas structures.
"""
seen = set()
duplicates = []

for structure in atlas.structures:
acronym = atlas.structures[structure]["acronym"]
if acronym in seen:
name = atlas.structures[structure]["name"]
duplicates.append((acronym, name))
else:
seen.add(acronym)

assert (
len(duplicates) == 0
), f"Duplicate acronyms found in atlas structures: {sorted(duplicates)}"
return True


def validate_atlas_name(atlas: BrainGlobeAtlas):
"""Validate the naming convention of the atlas.

Expand Down Expand Up @@ -523,6 +562,7 @@ def get_all_validation_functions():
catch_missing_structures,
validate_reference_image_pixels,
validate_annotation_symmetry,
validate_unique_acronyms,
validate_atlas_name,
]

Expand Down Expand Up @@ -588,6 +628,7 @@ def validate_atlas(atlas_name, version, validation_functions):
catch_missing_structures,
validate_reference_image_pixels,
validate_annotation_symmetry,
validate_unique_acronyms,
validate_atlas_name,
]

Expand Down
29 changes: 29 additions & 0 deletions tests/atlasgen/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
validate_mesh_matches_image_extents,
validate_metadata,
validate_reference_image_pixels,
validate_unique_acronyms,
)
from brainglobe_atlasapi.config import get_brainglobe_dir
from brainglobe_atlasapi.core import AdditionalRefDict
Expand Down Expand Up @@ -457,3 +458,31 @@ def test_validate_metadata(atlas, metadata, expected_output, error_message):
validate_metadata(atlas)
else:
assert validate_metadata(atlas) == expected_output


def test_validate_unique_acronyms_fail(mocker, atlas):
"""Check that an atlas with duplicate acronyms fails validation.

Parameters
----------
mocker : pytest_mock.MockerFixture
Mocker fixture for patching.
atlas : BrainGlobeAtlas
A BrainGlobeAtlas instance.
"""
# Create structures with duplicate acronyms
structures_with_duplicates = {
1: {"acronym": "root", "name": "Root"},
2: {"acronym": "brain", "name": "Brain"},
3: {"acronym": "brain", "name": "Brain Duplicate"}, # Duplicate!
4: {"acronym": "cortex", "name": "Cortex"},
}
mocker.patch.object(atlas, "structures", structures_with_duplicates)

with pytest.raises(AssertionError) as exc_info:
validate_unique_acronyms(atlas)

# Verify error contains the duplicate acronym and its name
error_message = str(exc_info.value)
assert "brain" in error_message
assert "Brain Duplicate" in error_message
Loading