diff --git a/pipeline/src/additional_methods/by_name.py.txt b/pipeline/src/additional_methods/by_name.py.txt index 5bbfef33..ed875fe0 100644 --- a/pipeline/src/additional_methods/by_name.py.txt +++ b/pipeline/src/additional_methods/by_name.py.txt @@ -10,6 +10,7 @@ all: bool = False, case_sensitive: bool = True, ignore_accents: bool = False, + ignore_separators: bool = False, ): """ Search for instances in the openMINDS instance library based on their name. @@ -29,6 +30,9 @@ other diacritical marks (cedilla, tilde, ring, etc.) when matching. Also treat special letters (ß, œ, æ, ø, ł, etc.) as their closest plain-letter equivalents (e.g. "ß" as "ss"). Defaults to False. + ignore_separators (bool, optional): Whether to ignore hyphens ("-"), underscores + ("_"), slashes ("/"), and repeated whitespace when matching, by collapsing + them all to a single space. Defaults to False. """ namelike_properties = ("name", "lookup_label", "family_name", "full_name", "short_name", "abbreviation") if cls._instance_lookup is None: @@ -72,25 +76,31 @@ s = s.casefold() if ignore_accents: s = remove_accents(s) + if ignore_separators: + s = s.replace("-", " ").replace("_", " ").replace("/", " ") + s = " ".join(s.split()) return s if match == "equals": - if case_sensitive and not ignore_accents: + if case_sensitive and not ignore_accents and not ignore_separators: matches = cls._instance_lookup.get(name, []) else: + normalized_name = normalize(name) matches = [] for key, instances in cls._instance_lookup.items(): - if normalize(key) == normalize(name): + if normalize(key) == normalized_name: matches.extend(instances) elif match == "contains": + normalized_name = normalize(name) matches = [] for key, instances in cls._instance_lookup.items(): - if normalize(name) in normalize(key): + if normalized_name in normalize(key): matches.extend(instances) elif match == "within": + normalized_name = normalize(name) matches = [] for key, instances in cls._instance_lookup.items(): - if normalize(key) in normalize(name): + if normalize(key) in normalized_name: matches.extend(instances) else: raise ValueError("'match' must be either 'equals', 'contains', or 'within'") diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index b0481cf2..421c5742 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -763,3 +763,32 @@ def test_pr0103_by_name_ignore_accents(om): for query, ignore_accents, expected_name in special_letter_cases: match = SovereignState.by_name(query, ignore_accents=ignore_accents) assert (match.name if match else None) == expected_name + + +@pytest.mark.parametrize("om", [openminds.latest]) +def test_pr0105_by_name_ignore_separators(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/pull/105 + # by_name(..., ignore_separators=True) treats hyphens and underscores as spaces, + # and collapses repeated/mixed whitespace, before matching + Technique = om.controlled_terms.Technique + + # (query, ignore_separators, expected match name or None) + cases = [ + ("two-photon fluorescence microscopy", False, "two-photon fluorescence microscopy"), # exact + ("two photon fluorescence microscopy", True, "two-photon fluorescence microscopy"), + ("two_photon_fluorescence_microscopy", True, "two-photon fluorescence microscopy"), + ("two photon fluorescence-microscopy", True, "two-photon fluorescence microscopy"), + ("two photon fluorescence microscopy", False, None), # defaults: hyphen still matters + ("CLARITY/TDE", False, "CLARITY/TDE"), # exact + ("CLARITY TDE", True, "CLARITY/TDE"), + ("CLARITY-TDE", True, "CLARITY/TDE"), + ("CLARITY TDE", False, None), # defaults: slash still matters + ] + for query, ignore_separators, expected_name in cases: + match = Technique.by_name(query, ignore_separators=ignore_separators) + assert (match.name if match else None) == expected_name + + # ignore_separators also applies to match="within" + assert Technique.by_name("CLARITY-TDE method", match="within") is None + match = Technique.by_name("CLARITY-TDE method", match="within", ignore_separators=True) + assert match.name == "CLARITY/TDE"