diff --git a/bioptim/examples/__main__.py b/bioptim/examples/__main__.py index 4edfb5b6f..2219d0528 100644 --- a/bioptim/examples/__main__.py +++ b/bioptim/examples/__main__.py @@ -490,14 +490,14 @@ def applySearchHighlight(self, text): self.setFormat(start, length, style) -def unnestedDict(exDict): - """Converts a dict-of-dicts to a singly nested dict for non-recursive parsing""" +def unnestedDict(exDict, root_dir=""): + """Convert an example tree to a title-to-relative-path dictionary.""" out = {} for kk, vv in exDict.items(): if isinstance(vv, dict): - out.update(unnestedDict(vv)) + out.update(unnestedDict(vv, os.path.join(root_dir, kk))) else: - out[kk] = vv + out[kk] = os.path.join(root_dir, vv) return out @@ -575,19 +575,15 @@ def filterByContent(self, text=None): self.hl.setDocument(self.ui.codeView.document()) text = text.lower() titles = [] - for key, val in examples_.items(): - if isinstance(val, OrderedDict): - root_dir = key - checkDict = unnestedDict(val) - for kk, vv in checkDict.items(): - path = os.getcwd() + "/" + root_dir - filename = os.path.join(path, vv) - contents = self.getExampleContent(filename).lower() - if text in contents: - titles.append(kk) - else: - pass - self.showExamplesByTitle(titles) + for root_dir, examples in examples_.items(): + if not isinstance(examples, dict): + continue + for title, relative_filename in unnestedDict(examples, root_dir).items(): + filename = os.path.join(path, relative_filename) + contents = self.getExampleContent(filename).lower() + if text in contents: + titles.append(title) + self.showExamplesByTitle(titles) def getMatchingTitles(self, text, exDict=None, acceptAll=False): if exDict is None: diff --git a/tests/shard1/test__run_examples.py b/tests/shard1/test__run_examples.py index 6b4a9f917..46f206b49 100644 --- a/tests/shard1/test__run_examples.py +++ b/tests/shard1/test__run_examples.py @@ -2,9 +2,80 @@ Test for file IO """ +import os from sys import platform +def test_example_paths_are_preserved_when_flattening(monkeypatch): + if platform == "linux": + monkeypatch.setenv("QT_QPA_PLATFORM", "offscreen") + + from bioptim.examples.__main__ import examples_, path, unnestedDict + + example_paths = unnestedDict(examples_["toy_examples/acados"], "toy_examples/acados") + + assert os.path.normpath(example_paths["Static arm"]) == os.path.normpath("toy_examples/acados/static_arm.py") + for root_dir, examples in examples_.items(): + for relative_path in unnestedDict(examples, root_dir).values(): + assert os.path.isfile(os.path.join(path, relative_path)) + + +def test_filter_by_content_uses_example_package_path(monkeypatch, tmp_path): + if platform == "linux": + monkeypatch.setenv("QT_QPA_PLATFORM", "offscreen") + + import bioptim.examples.__main__ as examples_module + + example_directory = tmp_path / "nested" + example_directory.mkdir() + (example_directory / "matching.py").write_text("the content needle is here") + (example_directory / "other.py").write_text("unrelated content") + + monkeypatch.setattr( + examples_module, + "examples_", + { + "nested": { + "Matching example": "matching.py", + "Other example": "other.py", + }, + "metadata": "ignored", + }, + ) + monkeypatch.setattr(examples_module, "path", str(tmp_path)) + + class Highlighter: + searchText = None + + @staticmethod + def setDocument(_): + pass + + class CodeView: + @staticmethod + def document(): + return None + + class Loader: + hl = Highlighter() + ui = type("Ui", (), {"codeView": CodeView()})() + matching_titles = None + + @staticmethod + def getExampleContent(filename): + with open(filename) as example_file: + return example_file.read() + + def showExamplesByTitle(self, titles): + self.matching_titles = titles + + loader = Loader() + examples_module.ExampleLoader.filterByContent(loader, "NEEDLE") + + assert loader.hl.searchText == "NEEDLE" + assert loader.matching_titles == ["Matching example"] + + def test_run_examples(): if platform == "linux": # AppVeyor and GitHub action cannot work with graphic interface on Linux return