diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 928d8acb0..50db30b9b 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -146,7 +146,6 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]], exclude: List[str], include: List[str]) -> DefaultDict[str, List[_Entry]]: """Map files to the wheel, organized by wheel installation directory.""" wheel_files: DefaultDict[str, List[_Entry]] = collections.defaultdict(list) - packages: Dict[str, str] = {} excluded = _compile_patterns(exclude) included = _compile_patterns(include) @@ -165,18 +164,6 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]], if path is None: raise BuildError(f'Could not map installation path to an equivalent wheel directory: {str(destination)!r}') - if path == 'purelib' or path == 'platlib': - package = destination.parts[1] - other = packages.setdefault(package, path) - if other != path: - this = os.fspath(pathlib.Path(path, *destination.parts[1:])) - module = next(entry.dst for entry in wheel_files[other] if entry.dst.parts[0] == destination.parts[1]) - that = os.fspath(other / module) - raise BuildError( - f'The {package} package is split between {path} and {other}: ' - f'{this!r} and {that!r}, a "pure: false" argument may be missing in meson.build. ' - f'It is recommended to set it in "import(\'python\').find_installation()"') - if key == 'install_subdirs' or key == 'targets' and os.path.isdir(src): exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])} exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])} @@ -208,6 +195,17 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]], wheel_files[path].append(_Entry(dst, src, install_rpath, build_rpath)) + purelib = {entry.dst.parts[0]: entry.dst for entry in wheel_files.get('purelib', [])} + for entry in wheel_files.get('platlib', []): + package = entry.dst.parts[0] + if package in purelib: + this = os.fspath('platlib' / entry.dst) + that = os.fspath('purelib' / purelib[package]) + raise BuildError( + f'The {package} package is split between platlib and purelib: ' + f'{this!r} and {that!r}, a "pure: false" argument may be missing in meson.build. ' + f'It is recommended to set it in "import(\'python\').find_installation()"') + return wheel_files diff --git a/tests/packages/purelib-platlib-split/meson.build b/tests/packages/purelib-platlib-split/meson.build index 071d79d57..48529bc2b 100644 --- a/tests/packages/purelib-platlib-split/meson.build +++ b/tests/packages/purelib-platlib-split/meson.build @@ -6,13 +6,16 @@ project('purelib-platlib-split', version: '1.0.0') py = import('python').find_installation() -py.install_sources( - 'pure.py', - subdir: 'purelib-platlib-split', +install_subdir( + 'pure', + strip_directory: true, + exclude_files: get_option('empty') ? ['pure.py'] : [], + install_dir: py.get_install_dir() / 'purelib-platlib-split', ) -py.install_sources( - 'plat.py', - subdir: 'purelib-platlib-split', - pure: false, +# Use install_subdir() so this entry follows purelib in the install plan. +install_subdir( + 'plat', + strip_directory: true, + install_dir: py.get_install_dir(pure: false) / 'purelib-platlib-split', ) diff --git a/tests/packages/purelib-platlib-split/meson_options.txt b/tests/packages/purelib-platlib-split/meson_options.txt new file mode 100644 index 000000000..ba647f704 --- /dev/null +++ b/tests/packages/purelib-platlib-split/meson_options.txt @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2026 The meson-python developers +# +# SPDX-License-Identifier: MIT + +option('empty', type: 'boolean', value: false) diff --git a/tests/packages/purelib-platlib-split/plat.py b/tests/packages/purelib-platlib-split/plat/plat.py similarity index 100% rename from tests/packages/purelib-platlib-split/plat.py rename to tests/packages/purelib-platlib-split/plat/plat.py diff --git a/tests/packages/purelib-platlib-split/pure.py b/tests/packages/purelib-platlib-split/pure/pure.py similarity index 100% rename from tests/packages/purelib-platlib-split/pure.py rename to tests/packages/purelib-platlib-split/pure/pure.py diff --git a/tests/test_wheel.py b/tests/test_wheel.py index a7cb150dc..e9272d129 100644 --- a/tests/test_wheel.py +++ b/tests/test_wheel.py @@ -371,6 +371,18 @@ def test_purelib_platlib_split(package_purelib_platlib_split, tmp_path): project.wheel(tmp_path) +@pytest.mark.skipif(MESON_VERSION < (1, 1, 0), reason='meson too old to report excluded files') +def test_purelib_platlib_empty_subdir(package_purelib_platlib_split, tmp_path): + filename = mesonpy.build_wheel(tmp_path, {'setup-args': ['-Dempty=true']}) + artifact = wheel.wheelfile.WheelFile(tmp_path / filename) + assert wheel_contents(artifact) == { + 'purelib_platlib_split-1.0.0.dist-info/METADATA', + 'purelib_platlib_split-1.0.0.dist-info/RECORD', + 'purelib_platlib_split-1.0.0.dist-info/WHEEL', + 'purelib-platlib-split/plat.py', + } + + @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') @pytest.mark.parametrize('arch', ['x86_64', 'arm64']) def test_archflags_envvar(package_purelib_and_platlib, monkeypatch, tmp_path, arch):