From 9123897ad8d85e48bd3c435ffabcf9a36a0ed355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Mon, 15 Jan 2024 17:32:20 +0100 Subject: [PATCH] feat: Support meson-python editable modules --- src/griffe/finder.py | 9 +++++++++ tests/test_finder.py | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/griffe/finder.py b/src/griffe/finder.py index 936a4a46..03e24317 100644 --- a/src/griffe/finder.py +++ b/src/griffe/finder.py @@ -36,6 +36,7 @@ _editable_editables_patterns = [re.compile(pat) for pat in (r"^__editables_\w+\.py$", "^_editable_impl_\\w+\\.py$")] _editable_setuptools_patterns = [re.compile(pat) for pat in ("^__editable__\\w+\\.py$",)] _editable_scikit_build_core_patterns = [re.compile(pat) for pat in (r"^_\w+_editable.py$",)] +_editable_meson_python_patterns = [re.compile(pat) for pat in (r"^_\w+_editable_loader.py$",)] def _match_pattern(string: str, patterns: Sequence[Pattern]) -> bool: @@ -421,6 +422,14 @@ def _handle_editable_module(path: Path) -> list[Path]: and node.targets[0].id == "MAPPING" ) and isinstance(node.value, ast.Dict): return [Path(cst.value).parent for cst in node.value.values if isinstance(cst, ast.Constant)] + if _match_pattern(path.name, _editable_meson_python_patterns): + # Support for how 'meson-python' writes these files: + # example line: `install({'package', 'module1'}, '/media/data/dev/griffe/build/cp311', ["path"], False)`. + # Compiled modules then found in the cp311 folder, under src/package. + parsed_module = ast.parse(path.read_text()) + for node in parsed_module.body: + if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call) and node.value.func.id == "install": + return [Path(node.value.args[1].value, "src")] raise UnhandledEditableModuleError(path) diff --git a/tests/test_finder.py b/tests/test_finder.py index 758a374d..59f320a4 100644 --- a/tests/test_finder.py +++ b/tests/test_finder.py @@ -166,6 +166,19 @@ def test_scikit_build_core_file_handling(tmp_path: Path) -> None: assert _handle_editable_module(pth_file) == [Path("/path/to/whatever")] +def test_meson_python_file_handling(tmp_path: Path) -> None: + """Assert editable modules by `meson-python` are handled. + + Parameters: + tmp_path: Pytest fixture. + """ + pth_file = tmp_path / "_whatever_editable_loader.py" + pth_file.write_text( + "hello=1\ninstall({'whatever', 'hello'}, '/path/to/build', ['/tmp/ninja'], False)", + ) + assert _handle_editable_module(pth_file) == [Path("/path/to/build/src")] + + @pytest.mark.parametrize( ("first", "second", "find_stubs", "expect"), [