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
52 changes: 46 additions & 6 deletions pipeline/src/additional_methods/by_name.py.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,52 @@
return [value for value in cls.__dict__.values() if isinstance(value, cls)]

@classmethod
def by_name(cls, name):
def by_name(
cls,
name: str,
match: str = "equals",
all: bool = False,
):
"""
Search for instances in the openMINDS instance library based on their name.

This includes properties "name", "lookup_label", "family_name", "full_name", "short_name", "abbreviation", and "synonyms".

Note that not all metadata classes have a name.

Args:
name (str): a string to search for.
match (str, optional): either "equals" (exact match - default) or "contains".
all (bool, optional): Whether to return all objects that match the name, or only the first. Defaults to False.
"""
namelike_properties = ("name", "lookup_label", "family_name", "full_name", "short_name", "abbreviation")
if cls._instance_lookup is None:
cls._instance_lookup = {}
for instance in cls.instances():
cls._instance_lookup[instance.name] = instance
if instance.synonyms:
for synonym in instance.synonyms:
cls._instance_lookup[synonym] = instance
return cls._instance_lookup[name]
keys = []
for prop_name in namelike_properties:
if hasattr(instance, prop_name):
keys.append(getattr(instance, prop_name))
if hasattr(instance, "synonyms"):
for synonym in instance.synonyms or []:
keys.append(synonym)
for key in keys:
if key in cls._instance_lookup:
cls._instance_lookup[key].append(instance)
else:
cls._instance_lookup[key] = [instance]
if match == "equals":
matches = cls._instance_lookup.get(name, None)
elif match == "contains":
matches = []
for key, instances in cls._instance_lookup.items():
if name in key:
matches.extend(instances)
else:
raise ValueError("'match' must be either 'equals' or 'contains'")
if all:
return matches
elif len(matches) > 0:
return matches[0]
else:
return None
31 changes: 31 additions & 0 deletions pipeline/tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,34 @@ def test_issue0073b(om):
ds1.is_variant_of = ds2

failures = ds1.validate()


@pytest.mark.parametrize("om", [openminds.latest])
def test_issue0069(om):
# https://github.com/openMetadataInitiative/openMINDS_Python/issues/69
# The License class has a classmethod "by_name()" which assumes License is a controlled term
# (i.e., it has properties "name" and "synonyms").
# However License does not have these properties, it has "short_name" and "full_name".

# Test with default arguments (single result, exact match)
result = om.core.License.by_name("CC-BY-4.0")
assert result.short_name == "CC-BY-4.0"

result = om.sands.ParcellationEntity.by_name("NODa,b")
assert result.abbreviation == "NODa,b"

result = om.sands.CommonCoordinateSpace.by_name("MEBRAINS population-based monkey brain template")
assert result.full_name == "MEBRAINS population-based monkey brain template"

assert om.controlled_terms.BiologicalOrder.by_name("rodents") == om.controlled_terms.BiologicalOrder.by_name("Rodentia") != None

# Test with "all=True"
results = om.sands.BrainAtlasVersion.by_name("Julich-Brain Atlas", all=True)
assert len(results) == 30
assert all(r.short_name == "Julich-Brain Atlas" for r in results)
assert len(set(r.id for r in results)) == len(results)

# Test with "match='contains'"
results = om.core.License.by_name("Creative Commons", all=True, match="contains")
assert len(results) == 7
assert all("CC" in r.short_name for r in results)