From f852cf9ec480a98eb2f60f67d77f4a9499c24d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Genevi=C3=A8ve=20Fleury?= <113036747+gefleury@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:14:14 +0200 Subject: [PATCH 1/3] Avoid recomputing normalize(name) in by_name loop --- pipeline/src/additional_methods/by_name.py.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pipeline/src/additional_methods/by_name.py.txt b/pipeline/src/additional_methods/by_name.py.txt index 5bbfef33..ecd4c7f6 100644 --- a/pipeline/src/additional_methods/by_name.py.txt +++ b/pipeline/src/additional_methods/by_name.py.txt @@ -78,19 +78,22 @@ if case_sensitive and not ignore_accents: 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'") From 699198cf4789775875b17ddd909605c28309ef0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Genevi=C3=A8ve=20Fleury?= <113036747+gefleury@users.noreply.github.com> Date: Wed, 9 Sep 2026 20:20:52 +0200 Subject: [PATCH 2/3] Add ignore_separators option to by_name() --- .../src/additional_methods/by_name.py.txt | 9 +++++- pipeline/tests/test_regressions.py | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/pipeline/src/additional_methods/by_name.py.txt b/pipeline/src/additional_methods/by_name.py.txt index ecd4c7f6..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,10 +76,13 @@ 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) diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index b0481cf2..2b2d7ab8 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_pr_XXX_by_name_ignore_separators(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/pull/XXX + # 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" From 176bee6a57795ae06003fffeca31a48859e49ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Genevi=C3=A8ve=20Fleury?= <113036747+gefleury@users.noreply.github.com> Date: Thu, 10 Sep 2026 09:31:36 +0200 Subject: [PATCH 3/3] Rename by_name() test to match the test_pr convention --- pipeline/tests/test_regressions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index 2b2d7ab8..421c5742 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -766,8 +766,8 @@ def test_pr0103_by_name_ignore_accents(om): @pytest.mark.parametrize("om", [openminds.latest]) -def test_pr_XXX_by_name_ignore_separators(om): - # https://github.com/openMetadataInitiative/openMINDS_Python/pull/XXX +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