1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# SPDX-FileCopyrightText: 2021 The meson-python developers
#
# SPDX-License-Identifier: MIT
import importlib.machinery
import os
import pathlib
import platform
import sys
import sysconfig
from collections import defaultdict
from unittest.mock import Mock
import packaging.tags
import pytest
import mesonpy
import mesonpy._tags
from .conftest import adjust_packaging_platform_tag
# Test against the wheel tag generated by packaging module.
tag = next(packaging.tags.sys_tags())
ABI = tag.abi
INTERPRETER = tag.interpreter
PLATFORM = adjust_packaging_platform_tag(tag.platform)
def get_abi3_suffix():
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
if '.abi3' in suffix: # Unix
return suffix
elif suffix == '.pyd': # Windows
return suffix
SUFFIX = sysconfig.get_config_var('EXT_SUFFIX')
ABI3SUFFIX = get_abi3_suffix()
def test_wheel_tag():
assert str(mesonpy._tags.Tag()) == f'{INTERPRETER}-{ABI}-{PLATFORM}'
assert str(mesonpy._tags.Tag(abi='abi3')) == f'{INTERPRETER}-abi3-{PLATFORM}'
@pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test')
def test_macos_platform_tag(monkeypatch):
for minor in range(9, 16):
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'10.{minor}')
version = (10, minor) if platform.mac_ver()[2] != 'arm64' else (11, 0)
assert next(packaging.tags.mac_platforms(version)) == mesonpy._tags.get_platform_tag()
for major in range(11, 20):
for minor in range(3):
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}.{minor}')
assert next(packaging.tags.mac_platforms((major, minor))) == mesonpy._tags.get_platform_tag()
for major in range(11, 13):
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}.0')
assert next(packaging.tags.mac_platforms((major, 0))) == mesonpy._tags.get_platform_tag()
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}')
assert next(packaging.tags.mac_platforms((major, 0))) == mesonpy._tags.get_platform_tag()
@pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test')
def test_macos_platform_tag_arm64(monkeypatch):
monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-12.0-arm64')
# Verify that the minimum platform ABI version on arm64 is 11.0.
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', '10.12')
assert mesonpy._tags.get_platform_tag() == 'macosx_11_0_arm64'
monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', '12.34')
assert mesonpy._tags.get_platform_tag() == 'macosx_12_0_arm64'
@pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test')
def test_python_host_platform(monkeypatch):
monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-12.0-arm64')
assert mesonpy._tags.get_platform_tag().endswith('arm64')
monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-11.1-x86_64')
assert mesonpy._tags.get_platform_tag().endswith('x86_64')
@pytest.mark.skipif(sys.version_info < (3, 13), reason='requires Python 3.13 or higher')
@pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test')
def test_ios_platform_tag(monkeypatch):
# Mock being on iOS
monkeypatch.setattr(sys.implementation, '_multiarch', 'arm64-iphoneos')
monkeypatch.setattr(sysconfig, 'get_platform', Mock(return_value='ios-13.0-arm64-iphoneos'))
ios_ver = platform.IOSVersionInfo('iOS', '13.0', 'iPhone', False)
monkeypatch.setattr(platform, 'ios_ver', Mock(return_value=ios_ver))
# Check the default value
assert next(packaging.tags.ios_platforms((13, 0))) == mesonpy._tags.get_platform_tag()
# Check the value when IPHONEOS_DEPLOYMENT_TARGET is set.
for major in range(13, 20):
for minor in range(3):
monkeypatch.setenv('IPHONEOS_DEPLOYMENT_TARGET', f'{major}.{minor}')
assert next(packaging.tags.ios_platforms((major, minor))) == mesonpy._tags.get_platform_tag()
def wheel_builder_test_factory(content, pure=True, limited_api=False):
manifest = defaultdict(list)
manifest.update({key: [(pathlib.Path(x), os.path.join('build', x)) for x in value] for key, value in content.items()})
return mesonpy._WheelBuilder(None, manifest, limited_api, False)
def test_tag_empty_wheel():
builder = wheel_builder_test_factory({})
assert str(builder.tag) == 'py3-none-any'
def test_tag_purelib_wheel():
builder = wheel_builder_test_factory({
'purelib': ['pure.py'],
})
assert str(builder.tag) == 'py3-none-any'
def test_tag_platlib_wheel():
builder = wheel_builder_test_factory({
'platlib': [f'extension{SUFFIX}'],
})
assert str(builder.tag) == f'{INTERPRETER}-{ABI}-{PLATFORM}'
def test_tag_stable_abi():
builder = wheel_builder_test_factory({
'platlib': [f'extension{ABI3SUFFIX}'],
}, limited_api=True)
# PyPy does not support the stable ABI.
abi = 'abi3' if '__pypy__' not in sys.builtin_module_names else ABI
assert str(builder.tag) == f'{INTERPRETER}-{abi}-{PLATFORM}'
@pytest.mark.xfail(sys.version_info < (3, 8) and sys.platform == 'win32', reason='Extension modules suffix without ABI tags')
@pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not support the stable ABI')
def test_tag_mixed_abi():
builder = wheel_builder_test_factory({
'platlib': [f'extension{ABI3SUFFIX}', f'another{SUFFIX}'],
}, pure=False, limited_api=True)
with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '):
assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}'
|