-
Notifications
You must be signed in to change notification settings - Fork 5
feat: build examples dict for cli commands #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 25 commits
54974ba
c9cf238
f9a14c3
71423d5
a1ee907
b16c90b
15c8111
db2ac9a
9fcef71
c70ca27
d32201a
fbbf88c
a458c5e
736b519
0bd26fc
4be38f6
280390c
99c4951
aa65d02
4aa15b0
cfb2273
fdf09b2
53ac9a2
ce1efa7
c39dfae
c2e8076
d1038b7
85bb747
0d08dbe
fcbb1a2
52aa4e7
e8c8ee5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ | |
|
|
||
|
|
||
| # Examples | ||
| def _get_examples_dir() -> Path: | ||
| def _get_examples_dir(root_path=None) -> Path: | ||
| """Return the absolute path to the installed examples directory. | ||
|
|
||
| Returns | ||
|
|
@@ -72,6 +72,43 @@ def map_pack_to_examples() -> dict[str, List[str]]: | |
| return examples_by_pack | ||
|
|
||
|
|
||
| def copy_examples( | ||
| examples: List[str], | ||
sbillinge marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| target_dir: Optional[Path] = None, | ||
| ) -> List[Path]: | ||
| """Copy one or more examples to a target directory. | ||
|
||
|
|
||
| Parameters | ||
| ---------- | ||
| examples : list of str | ||
| Example name(s): ['example1'], ['pack1'] | ||
| target_dir : Path, optional | ||
| Target directory where examples should be copied. | ||
| Defaults to current working directory if not specified. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of Path | ||
|
||
| List of destination paths created. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
|
||
| If example name is ambiguous (exists in multiple packs). | ||
| FileNotFoundError | ||
| If example does not exist. | ||
| FileExistsError | ||
| If destination exists and overwrite=False. | ||
| """ | ||
| return | ||
|
|
||
|
|
||
| def print_info(pack_examples_dict): | ||
| """Pretty print available and installed packs and examples to | ||
| console.""" | ||
| return | ||
|
|
||
|
|
||
| def copy_example(pack_example: str) -> Path: | ||
| """Copy an example into the current working directory. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ | |
| __all__ = ["PacksManager"] | ||
|
|
||
|
|
||
| def _installed_packs_dir() -> Path: | ||
| def _installed_packs_dir(root_path=None) -> Path: | ||
| """Locate requirements/packs/ for the installed package.""" | ||
| with get_package_dir() as pkgdir: | ||
| pkg = Path(pkgdir).resolve() | ||
|
|
@@ -51,10 +51,34 @@ class PacksManager: | |
| packs_dir : pathlib.Path | ||
| Absolute path to the installed packs directory. | ||
| Defaults to `requirements/packs` under the installed package. | ||
| examples_dir : pathlib.Path | ||
| Absolute path to the installed examples directory. | ||
| Defaults to `docs/examples` under the installed package. | ||
| """ | ||
|
|
||
| def __init__(self) -> None: | ||
| self.packs_dir = _installed_packs_dir() | ||
| def __init__(self, root_path=None) -> None: | ||
| if root_path is None: | ||
| self.packs_dir = _installed_packs_dir(root_path) | ||
| self.examples_dir = self._get_examples_dir() | ||
| # root_path option provided for testing | ||
| else: | ||
| self.packs_dir = Path(root_path).resolve() | ||
| self.examples_dir = Path(root_path).resolve() | ||
|
||
|
|
||
| def _get_examples_dir(self) -> Path: | ||
| """Return the absolute path to the installed examples directory. | ||
|
|
||
| Returns | ||
| ------- | ||
| pathlib.Path | ||
| Directory containing shipped examples. | ||
|
|
||
| Raises | ||
| ------ | ||
| FileNotFoundError | ||
| If the examples directory cannot be located in the installation. | ||
| """ | ||
| return (self.packs_dir / ".." / ".." / "docs" / "examples").resolve() | ||
|
|
||
| def available_packs(self) -> List[str]: | ||
| """List all available packs. | ||
|
|
@@ -68,6 +92,37 @@ def available_packs(self) -> List[str]: | |
| p.stem for p in self.packs_dir.glob("*.txt") if p.is_file() | ||
| ) | ||
|
|
||
| def available_examples(self) -> dict[str, List[tuple[str, Path]]]: | ||
| """Finds all examples for each pack and builds a dict. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| root_path : Path | ||
| Root path to the examples directory. | ||
| Returns | ||
cadenmyers13 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ------- | ||
| dict | ||
| A dictionary mapping pack names to lists of example names. | ||
sbillinge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Raises | ||
| ------ | ||
| FileNotFoundError | ||
| If the provided root_path does not exist or is not a directory. | ||
| """ | ||
| example_dir = self.examples_dir | ||
| examples_dict = {} | ||
| for pack_path in sorted(example_dir.iterdir()): | ||
| if pack_path.is_dir(): | ||
| pack_name = pack_path.stem | ||
| examples_dict[pack_name] = [] | ||
| for example_path in sorted(pack_path.iterdir()): | ||
| if example_path.is_dir(): | ||
| example_name = example_path.stem | ||
| examples_dict[pack_name].append( | ||
| (example_name, example_path) | ||
| ) | ||
| return examples_dict | ||
|
|
||
| def _resolve_pack_file(self, identifier: Union[str, Path]) -> Path: | ||
| """Resolve a pack identifier to an absolute .txt path. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,78 @@ def tmp_examples(tmp_path_factory): | |
| yield tmp_examples | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def example_cases(tmp_path_factory): | ||
| """Copy the entire examples/ tree into a temp directory once per | ||
| test session. | ||
|
|
||
| Returns the path to that copy. | ||
| """ | ||
| examples_dir = tmp_path_factory.mktemp("examples") | ||
|
|
||
| # case 1: pack with no examples | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the tree structure here: #53 (comment). This is what the temp dir looks like. let me know if this looks okay. I believe everything is being correctly and there is no magic |
||
| # case1_dict = {"case1": {"empty_pack": []}} | ||
| # _build_examples_tree_helper(examples_dir, case1_dict) | ||
| case1 = examples_dir / "case1" / "empty_pack" | ||
| case1.mkdir(parents=True, exist_ok=True) | ||
|
|
||
| # Case 2: pack with multiple examples | ||
| case2a = ( | ||
| examples_dir | ||
| / "case2" | ||
| / "full_pack" | ||
| / "example1" | ||
| / "solution" | ||
| / "diffpy-cmi" | ||
| ) # full_pack, example1 | ||
| case2a.mkdir(parents=True, exist_ok=True) | ||
| (case2a / "script1.py").touch() | ||
| case2b = ( | ||
| examples_dir / "case2" / "full_pack" / "example2" / "random" / "path" | ||
| ) # full_pack, example2 | ||
| case2b.mkdir(parents=True, exist_ok=True) | ||
| (case2b / "script1.py").touch() | ||
| (case2b / "script2.py").touch() | ||
|
|
||
| # # Case 3: multiple packs with multiple examples | ||
| case3a = examples_dir / "case3" / "packA" / "my_ex1" # packA, ex1 | ||
| case3a.mkdir(parents=True, exist_ok=True) | ||
| (case3a / "script1.py").touch() | ||
| case3b = ( | ||
| examples_dir / "case3" / "packA" / "my_ex2" / "solutions" | ||
| ) # packA, ex2 | ||
| case3b.mkdir(parents=True, exist_ok=True) | ||
| (case3b / "script2.py").touch() | ||
| case3c = ( | ||
| examples_dir / "case3" / "packB" / "ex1" / "more" / "random" / "path" | ||
| ) # packB, ex1 | ||
| case3c.mkdir(parents=True, exist_ok=True) | ||
| (case3c / "script3.py").touch() | ||
| (case3c / "script4.py").touch() | ||
|
|
||
| # # Case 4: no pack found (empty directory) | ||
| case4 = examples_dir / "case4" | ||
| case4.mkdir(parents=True, exist_ok=True) | ||
|
|
||
| # Case 5: multiple packs with the same example names | ||
| case5a = examples_dir / "case5" / "packA" / "example" / "path1" | ||
| case5a.mkdir(parents=True, exist_ok=True) | ||
| (case5a / "script1.py").touch() | ||
| case5b = examples_dir / "case5" / "packB" / "example" / "path2" | ||
| case5b.mkdir(parents=True, exist_ok=True) | ||
| (case5b / "script2.py").touch() | ||
|
|
||
| yield examples_dir | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def copy_target_dir(tmp_path_factory): | ||
| """Create a temporary directory to serve as the target for copying | ||
| examples.""" | ||
| target_dir = tmp_path_factory.mktemp("copy_target") | ||
| yield target_dir | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session", autouse=True) | ||
| def use_headless_matplotlib(): | ||
| """Force matplotlib to use a headless backend during tests.""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # from diffpy.cmi import get_package_dir | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("root_path", [None, str(Path(__file__).parent)]) | ||
sbillinge marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| def test_get_package_dir(root_path): | ||
| """Test that get_package_dir returns a valid path context | ||
sbillinge marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| manager.""" | ||
| assert False | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,24 @@ | |
| import pytest | ||
|
|
||
| from diffpy.cmi import cli | ||
| from diffpy.cmi.packsmanager import PacksManager | ||
|
|
||
|
|
||
| def test_print_info(temp_path, capsys): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. heads up, I am, not reviewing these till we have the dict building done. |
||
| pkmg = PacksManager() | ||
| actual = pkmg.available_examples(temp_path) | ||
| # pretty print the actual dict | ||
| pkmg.print_info(actual) | ||
| captured = capsys.readouterr() | ||
| output = captured.out.strip() | ||
| # check that output contains expected headers | ||
| assert "Available packs" in output or "Installed packs" in output | ||
|
|
||
|
|
||
| @pytest.mark.parametrize() | ||
| def test_copy_examples(dict, tmp_path): | ||
| cli.copy_examples(examples=dict, target_dir=tmp_path) | ||
| assert False | ||
|
|
||
|
|
||
| def test_map_pack_to_examples_structure(): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| import pytest | ||
|
|
||
| from diffpy.cmi.packsmanager import PacksManager | ||
|
|
||
| example_params = [ | ||
| # 1) pack with no examples. Expect {'empty_pack': []} | ||
| # 2) pack with multiple examples. | ||
| # Expect {'full_pack': [('example1`, path_to_1'), 'example2', path_to_2)] | ||
| # 3) multiple packs. Expect dict with multiple pack:tuple pairs | ||
| # 4) no pack found. Expect {} | ||
sbillinge marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we leave these here, we need to add case 5 here also.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| # case 1: pack with no examples. Expect {'empty_pack': []} | ||
| ( | ||
| "case1", | ||
| {"empty_pack": []}, | ||
| ), | ||
| # case 2: pack with multiple examples. | ||
| # Expect {'full_pack': [('example1', path_to_1), | ||
| # ('example2', path_to_2)]} | ||
| ( | ||
| "case2", | ||
| { | ||
| "full_pack": [ | ||
| ("example1", "case2/full_pack/example1"), | ||
| ("example2", "case2/full_pack/example2"), | ||
| ] | ||
| }, | ||
| ), | ||
| # case 3: multiple packs. Expect dict with multiple pack:tuple pairs | ||
| ( | ||
| "case3", | ||
| { | ||
| "packA": [ | ||
| ("my_ex1", "case3/packA/my_ex1"), | ||
|
||
| ("my_ex2", "case3/packA/my_ex2"), | ||
| ], | ||
| "packB": [("ex1", "case3/packB/ex1")], | ||
| }, | ||
| ), | ||
| ( # case 4: no pack found. Expect {} | ||
| "case4", | ||
| {}, | ||
| ), | ||
| ( # case 5: multiple packs with the same example names | ||
|
||
| # Expect dict with multiple pack:tuple pairs | ||
| "case5", | ||
| { | ||
| "packA": [ | ||
| ("example", "case5/packA/example"), | ||
| ], | ||
| "packB": [ | ||
| ("example", "case5/packB/example"), | ||
| ], | ||
| }, | ||
| ), | ||
| ] | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("input,expected", example_params) | ||
| def test_available_examples(input, expected, example_cases): | ||
| tmp_ex_dir = example_cases / input | ||
|
||
| pkmg = PacksManager(tmp_ex_dir) | ||
| # Ensure the example directory is correctly set | ||
| assert pkmg.examples_dir == tmp_ex_dir | ||
|
||
| actual = pkmg.available_examples() | ||
| # Verify that the keys (pack names) are correct | ||
|
||
| assert set(actual.keys()) == set(expected.keys()) | ||
| # Verify that each expected example exists in actual | ||
|
||
| for expected_pack, expected_list in expected.items(): | ||
|
||
| actual_list = actual[expected_pack] | ||
| for (expected_exname, expected_path), ( | ||
| actual_exname, | ||
| actual_path, | ||
| ) in zip(expected_list, actual_list): | ||
| # Checks example name and path | ||
| assert expected_exname == actual_exname | ||
| assert expected_path == str(actual_path.relative_to(example_cases)) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("input,expected", example_params) | ||
| def test_tmp_(input, expected, example_cases): | ||
|
||
| example_path = example_cases / input | ||
| for path in example_path.rglob("*"): | ||
| if path.suffix: | ||
| # Checks temp files are files and not dirs | ||
|
||
| assert path.is_file() | ||
| else: | ||
| assert path.is_dir() | ||
Uh oh!
There was an error while loading. Please reload this page.