Skip to content

Commit dc5300c

Browse files
dnicolodirgommers
authored andcommitted
MAINT: remove the is_pure property from project
This removes some criss-crossing dependencies between wheel builder and project. Make the wheel builder property private while at it. Also fix test_install_tags to actually look at tags.
1 parent 90bd23d commit dc5300c

File tree

4 files changed

+46
-51
lines changed

4 files changed

+46
-51
lines changed

mesonpy/__init__.py

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,29 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[T
178178
return wheel_files
179179

180180

181+
def _is_native(file: Path) -> bool:
182+
"""Check if file is a native file."""
183+
184+
with open(file, 'rb') as f:
185+
if sys.platform == 'linux':
186+
return f.read(4) == b'\x7fELF' # ELF
187+
elif sys.platform == 'darwin':
188+
return f.read(4) in (
189+
b'\xfe\xed\xfa\xce', # 32-bit
190+
b'\xfe\xed\xfa\xcf', # 64-bit
191+
b'\xcf\xfa\xed\xfe', # arm64
192+
b'\xca\xfe\xba\xbe', # universal / fat (same as java class so beware!)
193+
)
194+
elif sys.platform == 'win32':
195+
return f.read(2) == b'MZ'
196+
197+
# For unknown platforms, check for file extensions.
198+
_, ext = os.path.splitext(file)
199+
if ext in ('.so', '.a', '.out', '.exe', '.dll', '.dylib', '.pyd'):
200+
return True
201+
return False
202+
203+
181204
def _showwarning(
182205
message: Union[Warning, str],
183206
category: Type[Warning],
@@ -276,6 +299,16 @@ def _has_extension_modules(self) -> bool:
276299
# Assume that all code installed in {platlib} is Python ABI dependent.
277300
return bool(self._manifest.get('platlib'))
278301

302+
@cached_property
303+
def _pure(self) -> bool:
304+
"""Whether the wheel is architecture independent"""
305+
if self._manifest['platlib']:
306+
return False
307+
for _, file in self._manifest['scripts']:
308+
if _is_native(file):
309+
return False
310+
return True
311+
279312
@property
280313
def normalized_name(self) -> str:
281314
return self._metadata.name.replace('-', '_')
@@ -288,7 +321,7 @@ def basename(self) -> str:
288321
@property
289322
def tag(self) -> mesonpy._tags.Tag:
290323
"""Wheel tags."""
291-
if self.is_pure:
324+
if self._pure:
292325
return mesonpy._tags.Tag('py3', 'none', 'any')
293326
if not self._has_extension_modules:
294327
# The wheel has platform dependent code (is not pure) but
@@ -318,20 +351,6 @@ def _license_file(self) -> Optional[pathlib.Path]:
318351
return license_.file
319352
return None
320353

321-
@cached_property
322-
def is_pure(self) -> bool:
323-
"""Is the wheel "pure" (architecture independent)?"""
324-
# XXX: I imagine some users might want to force the package to be
325-
# non-pure, but I think it's better that we evaluate use-cases as they
326-
# arise and make sure allowing the user to override this is indeed the
327-
# best option for the use-case.
328-
if self._manifest['platlib']:
329-
return False
330-
for _, file in self._manifest['scripts']:
331-
if self._is_native(file):
332-
return False
333-
return True
334-
335354
@property
336355
def wheel(self) -> bytes:
337356
"""Return WHEEL file for dist-info."""
@@ -341,7 +360,7 @@ def wheel(self) -> bytes:
341360
Root-Is-Purelib: {is_purelib}
342361
Tag: {tag}
343362
''').strip().format(
344-
is_purelib='true' if self.is_pure else 'false',
363+
is_purelib='true' if self._pure else 'false',
345364
tag=self.tag,
346365
).encode()
347366

@@ -398,34 +417,11 @@ def top_level_modules(self) -> Collection[str]:
398417
modules.add(name)
399418
return modules
400419

401-
def _is_native(self, file: Union[str, pathlib.Path]) -> bool:
402-
"""Check if file is a native file."""
403-
self._project.build() # the project needs to be built for this :/
404-
405-
with open(file, 'rb') as f:
406-
if sys.platform == 'linux':
407-
return f.read(4) == b'\x7fELF' # ELF
408-
elif sys.platform == 'darwin':
409-
return f.read(4) in (
410-
b'\xfe\xed\xfa\xce', # 32-bit
411-
b'\xfe\xed\xfa\xcf', # 64-bit
412-
b'\xcf\xfa\xed\xfe', # arm64
413-
b'\xca\xfe\xba\xbe', # universal / fat (same as java class so beware!)
414-
)
415-
elif sys.platform == 'win32':
416-
return f.read(2) == b'MZ'
417-
418-
# For unknown platforms, check for file extensions.
419-
_, ext = os.path.splitext(file)
420-
if ext in ('.so', '.a', '.out', '.exe', '.dll', '.dylib', '.pyd'):
421-
return True
422-
return False
423-
424420
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path) -> None:
425421
"""Add a file to the wheel."""
426422

427423
if self._has_internal_libs:
428-
if self._is_native(os.fspath(origin)):
424+
if _is_native(origin):
429425
# When an executable, libray, or Python extension module is
430426
# dynamically linked to a library built as part of the project,
431427
# Meson adds a library load path to it pointing to the build
@@ -463,7 +459,7 @@ def build(self, directory: Path) -> pathlib.Path:
463459

464460
with mesonpy._util.cli_counter(sum(len(x) for x in self._manifest.values())) as counter:
465461

466-
root = 'purelib' if self.is_pure else 'platlib'
462+
root = 'purelib' if self._pure else 'platlib'
467463

468464
for path, entries in self._manifest.items():
469465
for dst, src in entries:
@@ -843,11 +839,6 @@ def version(self) -> str:
843839
"""Project version."""
844840
return str(self._metadata.version)
845841

846-
@property
847-
def is_pure(self) -> bool:
848-
"""Is the wheel "pure" (architecture independent)?"""
849-
return bool(self._wheel_builder.is_pure)
850-
851842
def sdist(self, directory: Path) -> pathlib.Path:
852843
"""Generates a sdist (source distribution) in the specified directory."""
853844
# generate meson dist file

tests/packages/purelib-and-platlib/meson.build

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ project('purelib-and-platlib', 'c', version: '1.0.0')
66

77
py = import('python').find_installation()
88

9-
py.install_sources('pure.py')
9+
py.install_sources(
10+
'pure.py',
11+
install_tag: 'purelib',
12+
)
1013

1114
py.extension_module(
1215
'plat',
1316
'plat.c',
1417
install: true,
18+
install_tag: 'platlib',
1519
)

tests/test_project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def test_install_tags(package_purelib_and_platlib, tmp_path_session):
153153
'install': ['--tags', 'purelib'],
154154
}
155155
)
156-
assert project.is_pure
156+
assert 'platlib' not in project._manifest
157157

158158

159159
def test_validate_pyproject_config_one():

tests/test_tags.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_python_host_platform(monkeypatch):
6262
assert mesonpy._tags.get_platform_tag().endswith('x86_64')
6363

6464

65-
def wheel_builder_test_factory(monkeypatch, content, limited_api=False):
65+
def wheel_builder_test_factory(monkeypatch, content, pure=True, limited_api=False):
6666
files = defaultdict(list)
6767
files.update({key: [(pathlib.Path(x), os.path.join('build', x)) for x in value] for key, value in content.items()})
6868
class Project:
@@ -92,7 +92,7 @@ def test_tag_platlib_wheel(monkeypatch):
9292
def test_tag_stable_abi(monkeypatch):
9393
builder = wheel_builder_test_factory(monkeypatch, {
9494
'platlib': [f'extension{ABI3SUFFIX}'],
95-
}, True)
95+
}, limited_api=True)
9696
assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}'
9797

9898

@@ -101,6 +101,6 @@ def test_tag_stable_abi(monkeypatch):
101101
def test_tag_mixed_abi(monkeypatch):
102102
builder = wheel_builder_test_factory(monkeypatch, {
103103
'platlib': [f'extension{ABI3SUFFIX}', f'another{SUFFIX}'],
104-
}, True)
104+
}, pure=False, limited_api=True)
105105
with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '):
106106
assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}'

0 commit comments

Comments
 (0)