Skip to content

Commit

Permalink
Fix editable installs with extension modules (#633)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Wardrop <mpwardrop@gmail.com>
  • Loading branch information
robbotorigami and matthewwardrop authored Sep 1, 2023
1 parent 43a2db9 commit 73b2f71
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/poetry/core/masonry/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ def _build(self, wheel: zipfile.ZipFile) -> None:
finally:
os.chdir(current_path)

if self._editable:
# For an editable install, the extension modules will be built
# in-place - so there's no need to copy them into the zip
return

build_dir = self._path / "build"
libs: list[Path] = list(build_dir.glob("lib.*"))
if not libs:
Expand Down Expand Up @@ -216,6 +221,15 @@ def _copy_file_scripts(self, wheel: zipfile.ZipFile) -> None:
)

def _run_build_command(self, setup: Path) -> None:
if self._editable:
subprocess.check_call(
[
self.executable.as_posix(),
str(setup),
"build_ext",
"--inplace",
]
)
subprocess.check_call(
[
self.executable.as_posix(),
Expand Down
44 changes: 44 additions & 0 deletions tests/masonry/builders/test_wheel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import importlib.machinery
import os
import re
import shutil
Expand Down Expand Up @@ -28,13 +29,18 @@
WHEEL_TAG_REGEX = "[cp]p[23]_?\\d+-(?:cp[23]_?\\d+m?u?|pypy[23]_?\\d+_pp\\d+)-.+"


shared_lib_extensions = importlib.machinery.EXTENSION_SUFFIXES


@pytest.fixture(autouse=True)
def setup() -> Iterator[None]:
clear_samples_dist()
clear_samples_build()

yield

clear_samples_dist()
clear_samples_build()


def clear_samples_dist() -> None:
Expand All @@ -43,6 +49,15 @@ def clear_samples_dist() -> None:
shutil.rmtree(str(dist))


def clear_samples_build() -> None:
for build in fixtures_dir.glob("**/build"):
if build.is_dir():
shutil.rmtree(str(build))
for suffix in shared_lib_extensions:
for shared_lib in fixtures_dir.glob(f"**/*{suffix}"):
shared_lib.unlink()


def test_wheel_module() -> None:
module_path = fixtures_dir / "module1"
WheelBuilder.make(Factory().create_poetry(module_path))
Expand Down Expand Up @@ -373,3 +388,32 @@ def test_tag(in_venv_build: bool, mocker: MockerFixture) -> None:
get_sys_tags_spy.assert_not_called()
else:
get_sys_tags_spy.assert_called()


def test_extended_editable_wheel_build() -> None:
"""Tests that an editable wheel made from a project with extensions includes
the .pth, but does not include the built package itself.
"""
root = fixtures_dir / "extended"
WheelBuilder.make_in(Factory().create_poetry(root), editable=True)

whl = next((root / "dist").glob("extended-0.1-*.whl"))

assert whl.exists()
with zipfile.ZipFile(str(whl)) as z:
assert "extended.pth" in z.namelist()
# Ensure the directory "extended/" does not exist in the whl
assert all(not n.startswith("extended/") for n in z.namelist())


def test_extended_editable_build_inplace() -> None:
"""Tests that a project with extensions builds the extension modules in-place
when ran for an editable install.
"""
root = fixtures_dir / "extended"
WheelBuilder.make_in(Factory().create_poetry(root), editable=True)

# Check that an extension with any of the allowed extensions was built in-place
assert any(
(root / "extended" / f"extended{ext}").exists() for ext in shared_lib_extensions
)

0 comments on commit 73b2f71

Please sign in to comment.