Skip to content

Commit 3333005

Browse files
dnicolodirgommers
authored andcommitted
ENH: implement editable loader with PEP 829 .start files
on Python 3.15 and later. Editable wheels are Python version specific, thus there is no need to write both a .pth and a .start file for Python versions that support the latter. Editable wheels implemented with .pth files just imported the implementation module and relied on the execution of the module body on import for the installation of the module loader. PEP 829 .start files need to specify a callable that takes no arguments. To keep the difference between .pth and .start file implementations to a minimum, define such callable in the implementation module and switch the .pth file to explicitly call it. Fixes #846
1 parent 6b9c6d9 commit 3333005

3 files changed

Lines changed: 38 additions & 18 deletions

File tree

mesonpy/__init__.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -553,18 +553,28 @@ def build(self, directory: Path, source_dir: pathlib.Path, build_dir: pathlib.Pa
553553
whl.writestr(
554554
f'{loader_module_name}.py',
555555
importlib.resources.files('mesonpy').joinpath('_editable.py').read_bytes() + textwrap.dedent(f'''
556-
install(
557-
{self._metadata.name!r},
558-
{self._top_level_modules!r},
559-
{os.fspath(build_dir)!r},
560-
{build_command!r},
561-
{verbose!r},
562-
)''').encode('utf-8'))
563-
564-
# install .pth file
565-
whl.writestr(
566-
f'{self._metadata.canonical_name}-editable.pth',
567-
f'import {loader_module_name}'.encode('utf-8'))
556+
def init():
557+
finder = MesonpyMetaFinder(
558+
{self._metadata.name!r},
559+
{self._top_level_modules!r},
560+
{os.fspath(build_dir)!r},
561+
{build_command!r},
562+
{verbose!r},
563+
)
564+
sys.meta_path.insert(0, finder)
565+
sys.path_hooks.insert(0, finder._path_hook)
566+
''').encode('utf-8'))
567+
568+
if sys.version_info >= (3, 15):
569+
# install .start file
570+
whl.writestr(
571+
f'{self._metadata.canonical_name}-editable.start',
572+
f'{loader_module_name}:init'.encode('utf-8'))
573+
else:
574+
# install .pth file
575+
whl.writestr(
576+
f'{self._metadata.canonical_name}-editable.pth',
577+
f'import {loader_module_name}; {loader_module_name}.init()'.encode('utf-8'))
568578

569579
return wheel_file
570580

mesonpy/_editable.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,3 @@ def iter_modules(self, prefix: str) -> Iterator[Tuple[str, bool]]:
410410
elif modname and '.' not in modname:
411411
yielded.add(modname)
412412
yield prefix + modname, False
413-
414-
415-
def install(package: str, names: Set[str], path: str, cmd: List[str], verbose: bool) -> None:
416-
finder = MesonpyMetaFinder(package, names, path, cmd, verbose)
417-
sys.meta_path.insert(0, finder)
418-
sys.path_hooks.insert(0, finder._path_hook)

tests/test_editable.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from contextlib import redirect_stdout
1414

1515
import pytest
16+
import wheel.wheelfile
1617

1718
import mesonpy
1819

@@ -190,6 +191,21 @@ def test_editable_install(venv, editable_simple):
190191
assert venv.python('-c', 'import simple; print(simple.data())').strip() == 'ABC'
191192

192193

194+
def test_editable_contents(editable_simple):
195+
artifact = wheel.wheelfile.WheelFile(editable_simple)
196+
197+
impl = 'start' if sys.version_info >= (3, 15) else 'pth'
198+
expecting = {
199+
'simple-1.0.0.dist-info/METADATA',
200+
'simple-1.0.0.dist-info/RECORD',
201+
'simple-1.0.0.dist-info/WHEEL',
202+
'_simple_editable_loader.py',
203+
f'simple-editable.{impl}',
204+
}
205+
206+
assert set(artifact.namelist()) == expecting
207+
208+
193209
def test_editble_reentrant(venv, editable_imports_itself_during_build):
194210
venv.pip('install', os.fspath(editable_imports_itself_during_build))
195211
assert venv.python('-c', 'import plat; print(plat.data())').strip() == 'ABC'

0 commit comments

Comments
 (0)