Skip to content

Commit 627cd79

Browse files
committed
ENH: do not run 'meson install' to produce a wheel
There is no need to have the files copied in the installation directory: they are read from the source and build trees. This removes the concept of a Project working directory containing the installation directory and the build directory (unless the user specifies one). A Project now only has a source directory and a build directory. Adapt the tests accordingly.
1 parent fbb9bb9 commit 627cd79

File tree

6 files changed

+32
-104
lines changed

6 files changed

+32
-104
lines changed

meson.build

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ py.install_sources(
1717
'mesonpy/_dylib.py',
1818
'mesonpy/_editable.py',
1919
'mesonpy/_elf.py',
20-
'mesonpy/_introspection.py',
2120
'mesonpy/_tags.py',
2221
'mesonpy/_util.py',
2322
'mesonpy/_wheelfile.py',

mesonpy/__init__.py

Lines changed: 17 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import mesonpy._compat
4949
import mesonpy._dylib
5050
import mesonpy._elf
51-
import mesonpy._introspection
5251
import mesonpy._tags
5352
import mesonpy._util
5453
import mesonpy._wheelfile
@@ -628,16 +627,13 @@ class Project():
628627
def __init__(
629628
self,
630629
source_dir: Path,
631-
working_dir: Path,
632-
build_dir: Optional[Path] = None,
630+
build_dir: Path,
633631
meson_args: Optional[MesonArgs] = None,
634632
editable_verbose: bool = False,
635633
) -> None:
636634
self._source_dir = pathlib.Path(source_dir).absolute()
637-
self._working_dir = pathlib.Path(working_dir).absolute()
638-
self._build_dir = pathlib.Path(build_dir).absolute() if build_dir else (self._working_dir / 'build')
635+
self._build_dir = pathlib.Path(build_dir).absolute()
639636
self._editable_verbose = editable_verbose
640-
self._install_dir = self._working_dir / 'install'
641637
self._meson_native_file = self._build_dir / 'meson-python-native-file.ini'
642638
self._meson_cross_file = self._build_dir / 'meson-python-cross-file.ini'
643639
self._meson_args: MesonArgs = collections.defaultdict(list)
@@ -692,7 +688,6 @@ def __init__(
692688

693689
# make sure the build dir exists
694690
self._build_dir.mkdir(exist_ok=True, parents=True)
695-
self._install_dir.mkdir(exist_ok=True, parents=True)
696691

697692
# write the native file
698693
native_file_data = textwrap.dedent(f'''
@@ -737,26 +732,15 @@ def _run(self, cmd: Sequence[str]) -> None:
737732

738733
def _configure(self, reconfigure: bool = False) -> None:
739734
"""Configure Meson project."""
740-
sys_paths = mesonpy._introspection.SYSCONFIG_PATHS
741735
setup_args = [
742-
f'--prefix={sys.base_prefix}',
743736
os.fspath(self._source_dir),
744737
os.fspath(self._build_dir),
745738
f'--native-file={os.fspath(self._meson_native_file)}',
746-
# TODO: Allow configuring these arguments
739+
# default arguments
747740
'-Ddebug=false',
748741
'-Db_ndebug=if-release',
749742
'-Doptimization=2',
750-
751-
# XXX: This should not be needed, but Meson is using the wrong paths
752-
# in some scenarios, like on macOS.
753-
# https://github.com/mesonbuild/meson-python/pull/87#discussion_r1047041306
754-
'--python.purelibdir',
755-
sys_paths['purelib'],
756-
'--python.platlibdir',
757-
sys_paths['platlib'],
758-
759-
# user args
743+
# user arguments
760744
*self._meson_args['setup'],
761745
]
762746
if reconfigure:
@@ -795,38 +779,11 @@ def _wheel_builder(self) -> _WheelBuilder:
795779
self._install_plan,
796780
)
797781

798-
def build_commands(self, install_dir: Optional[pathlib.Path] = None) -> Sequence[Sequence[str]]:
799-
assert self._ninja is not None # help mypy out
800-
return (
801-
(self._ninja, *self._meson_args['compile'],),
802-
(
803-
'meson',
804-
'install',
805-
'--only-changed',
806-
'--destdir',
807-
os.fspath(install_dir or self._install_dir),
808-
*self._meson_args['install'],
809-
),
810-
)
811-
812782
@functools.lru_cache(maxsize=None)
813783
def build(self) -> None:
814-
"""Trigger the Meson build."""
815-
for cmd in self.build_commands():
816-
self._run(cmd)
817-
818-
@classmethod
819-
@contextlib.contextmanager
820-
def with_temp_working_dir(
821-
cls,
822-
source_dir: Path = os.path.curdir,
823-
build_dir: Optional[Path] = None,
824-
meson_args: Optional[MesonArgs] = None,
825-
editable_verbose: bool = False,
826-
) -> Iterator[Project]:
827-
"""Creates a project instance pointing to a temporary working directory."""
828-
with tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=os.fspath(source_dir)) as tmpdir:
829-
yield cls(source_dir, tmpdir, build_dir, meson_args, editable_verbose)
784+
"""Build Meson project."""
785+
assert self._ninja is not None # help mypy
786+
self._run([self._ninja, *self._meson_args['compile']])
830787

831788
@functools.lru_cache()
832789
def _info(self, name: str) -> Dict[str, Any]:
@@ -975,18 +932,19 @@ def editable(self, directory: Path) -> pathlib.Path:
975932

976933

977934
@contextlib.contextmanager
978-
def _project(config_settings: Optional[Dict[Any, Any]]) -> Iterator[Project]:
935+
def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Project]:
979936
"""Create the project given the given config settings."""
980937

981938
settings = _validate_config_settings(config_settings or {})
982-
meson_args = {name: settings.get(f'{name}-args', []) for name in _MESON_ARGS_KEYS}
983-
984-
with Project.with_temp_working_dir(
985-
build_dir=settings.get('builddir'),
986-
meson_args=typing.cast(MesonArgs, meson_args),
987-
editable_verbose=bool(settings.get('editable-verbose'))
988-
) as project:
989-
yield project
939+
meson_args = typing.cast(MesonArgs, {name: settings.get(f'{name}-args', []) for name in _MESON_ARGS_KEYS})
940+
source_dir = os.path.curdir
941+
build_dir = settings.get('builddir')
942+
editable_verbose = bool(settings.get('editable-verbose'))
943+
944+
with contextlib.ExitStack() as ctx:
945+
if build_dir is None:
946+
build_dir = ctx.enter_context(tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=source_dir))
947+
yield Project(source_dir, build_dir, meson_args, editable_verbose)
990948

991949

992950
def _parse_version_string(string: str) -> Tuple[int, ...]:

mesonpy/_introspection.py

Lines changed: 0 additions & 27 deletions
This file was deleted.

tests/test_editable.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,12 @@ def test_collect(package_complex):
6161
def test_mesonpy_meta_finder(package_complex, tmp_build_path):
6262
# build a package in a temporary directory
6363
mesonpy.Project(package_complex, tmp_build_path)
64-
build_path = tmp_build_path / 'build'
6564

6665
# point the meta finder to the build directory
67-
finder = _editable.MesonpyMetaFinder({'complex'}, os.fspath(build_path), ['ninja'])
66+
finder = _editable.MesonpyMetaFinder({'complex'}, os.fspath(tmp_build_path), ['ninja'])
6867

6968
# check repr
70-
assert repr(finder) == f'MesonpyMetaFinder({str(build_path)!r})'
69+
assert repr(finder) == f'MesonpyMetaFinder({str(tmp_build_path)!r})'
7170

7271
# verify that we can look up a pure module in the source directory
7372
spec = finder.find_spec('complex')
@@ -79,7 +78,7 @@ def test_mesonpy_meta_finder(package_complex, tmp_build_path):
7978
spec = finder.find_spec('complex.test')
8079
assert spec.name == 'complex.test'
8180
assert isinstance(spec.loader, _editable.ExtensionFileLoader)
82-
assert spec.origin == os.fspath(build_path / f'test{EXT_SUFFIX}')
81+
assert spec.origin == os.fspath(tmp_build_path / f'test{EXT_SUFFIX}')
8382

8483
try:
8584
# install the finder in the meta path
@@ -89,7 +88,7 @@ def test_mesonpy_meta_finder(package_complex, tmp_build_path):
8988
assert complex.__spec__.origin == os.fspath(package_complex / 'complex/__init__.py')
9089
assert complex.__file__ == os.fspath(package_complex / 'complex/__init__.py')
9190
import complex.test
92-
assert complex.test.__spec__.origin == os.fspath(build_path / f'test{EXT_SUFFIX}')
91+
assert complex.test.__spec__.origin == os.fspath(tmp_build_path / f'test{EXT_SUFFIX}')
9392
assert complex.test.answer() == 42
9493
import complex.namespace.foo
9594
assert complex.namespace.foo.__spec__.origin == os.fspath(package_complex / 'complex/namespace/foo.py')
@@ -128,7 +127,7 @@ def test_resources(tmp_path):
128127
mesonpy.Project(package_path, tmp_path)
129128

130129
# point the meta finder to the build directory
131-
finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path / 'build'), ['ninja'])
130+
finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path), ['ninja'])
132131

133132
# verify that we can look up resources
134133
spec = finder.find_spec('simple')
@@ -147,7 +146,7 @@ def test_importlib_resources(tmp_path):
147146
mesonpy.Project(package_path, tmp_path)
148147

149148
# point the meta finder to the build directory
150-
finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path / 'build'), ['ninja'])
149+
finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path), ['ninja'])
151150

152151
try:
153152
# install the finder in the meta path

tests/test_project.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
]
2929
)
3030
def test_name(package):
31-
with chdir(package_dir / package), mesonpy.Project.with_temp_working_dir() as project:
31+
with chdir(package_dir / package), mesonpy._project() as project:
3232
assert project.name == package.replace('-', '_')
3333

3434

@@ -40,21 +40,21 @@ def test_name(package):
4040
]
4141
)
4242
def test_version(package):
43-
with chdir(package_dir / package), mesonpy.Project.with_temp_working_dir() as project:
43+
with chdir(package_dir / package), mesonpy._project() as project:
4444
assert project.version == '1.0.0'
4545

4646

4747
def test_unsupported_dynamic(package_unsupported_dynamic):
4848
with pytest.raises(mesonpy.MesonBuilderError, match='Unsupported dynamic fields: "dependencies"'):
49-
with mesonpy.Project.with_temp_working_dir():
49+
with mesonpy._project():
5050
pass
5151

5252

5353
def test_unsupported_python_version(package_unsupported_python_version):
5454
with pytest.raises(mesonpy.MesonBuilderError, match=(
5555
f'Unsupported Python version {platform.python_version()}, expected ==1.0.0'
5656
)):
57-
with mesonpy.Project.with_temp_working_dir():
57+
with mesonpy._project():
5858
pass
5959

6060

@@ -76,7 +76,7 @@ def last_two_meson_args():
7676
'dist-args': ('cli-dist',),
7777
'setup-args': ('cli-setup',),
7878
'compile-args': ('cli-compile',),
79-
'install-args': ('cli-install',),
79+
'install-args': ('cli-install',), # 'meson install' is not called thus we cannot test this
8080
}
8181

8282
mesonpy.build_sdist(tmp_path, config_settings)
@@ -86,10 +86,9 @@ def last_two_meson_args():
8686
# sdist: calls to 'meson setup' and 'meson dist'
8787
('config-setup', 'cli-setup'),
8888
('config-dist', 'cli-dist'),
89-
# wheel: calls to 'meson setup', 'meson compile', and 'meson install'
89+
# wheel: calls to 'meson setup' and 'ninja'
9090
('config-setup', 'cli-setup'),
9191
('config-compile', 'cli-compile'),
92-
('config-install', 'cli-install'),
9392
]
9493

9594

@@ -174,7 +173,7 @@ def test_invalid_build_dir(package_pure, tmp_path, mocker):
174173
meson.reset_mock()
175174

176175
# corrupting the build direcory setup is run again
177-
tmp_path.joinpath('build/meson-private/coredata.dat').unlink()
176+
tmp_path.joinpath('meson-private/coredata.dat').unlink()
178177
project = mesonpy.Project(package_pure, tmp_path)
179178
assert len(meson.call_args_list) == 1
180179
assert meson.call_args_list[0].args[1][1] == 'setup'
@@ -183,7 +182,7 @@ def test_invalid_build_dir(package_pure, tmp_path, mocker):
183182
meson.reset_mock()
184183

185184
# removing the build directory things should still work
186-
shutil.rmtree(tmp_path.joinpath('build'))
185+
shutil.rmtree(tmp_path)
187186
project = mesonpy.Project(package_pure, tmp_path)
188187
assert len(meson.call_args_list) == 1
189188
assert meson.call_args_list[0].args[1][1] == 'setup'

tests/test_wheel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def test_entrypoints(wheel_full_metadata):
232232

233233

234234
def test_top_level_modules(package_module_types):
235-
with mesonpy.Project.with_temp_working_dir() as project:
235+
with mesonpy._project() as project:
236236
assert set(project._wheel_builder.top_level_modules) == {
237237
'file',
238238
'package',

0 commit comments

Comments
 (0)