Files
cibuildwheel/test/test_dependency_versions.py
T
Joe Rickerby 9879937c63 Don't preinstall setuptools and wheel, remove from constraints
Reasons to do this:

- setuptools is no longer the only game in town. When cibuildwheel was created, setuptools was the only way to make wheels. these days, there are many build backends so special casing setuptools doesn't make so much sense
- we don't need to preinstall `wheel` any more, setuptools will do that itself when it needs it.
- projects with pyproject.toml (i.e. the vast majority of projects going forward) don't benefit from the pin anyway, because both `pip` and `build` create an isolated environment to install `build-system.requires` into.
- this makes it easier for end users (such as @webknjaz) to control build-system versions using `PIP_CONSTRAINT`, because there's less potential for a user-specified version to conflict with one of our pins.
  - (long-term, I'd love `build` to [support this directly](https://github.com/pypa/build/issues/292), and then we could have a proper way to keep pyproject.toml dependencies loose and forward-compatible while retaining build determinism. But PIP_CONSTRAINT is the best we have for now. PIP_CONSTRAINT isn't ideal because it affects other things, like the test virtualenv).

This PR also adds a pin for pypa/build. It appears that was missing before, but we should pin it.
2024-01-20 18:44:03 +00:00

163 lines
5.1 KiB
Python

from __future__ import annotations
import platform
import re
import textwrap
import pytest
import cibuildwheel.util
from . import test_projects, utils
project_with_expected_version_checks = test_projects.new_c_project(
setup_py_add=textwrap.dedent(
r"""
import subprocess
import os
versions_output_text = subprocess.check_output(
['pip', 'freeze', '--all', '-qq'],
universal_newlines=True,
)
versions = versions_output_text.strip().splitlines()
# `versions` now looks like:
# ['pip==x.x.x', 'setuptools==x.x.x', 'wheel==x.x.x']
print('Gathered versions', versions)
packages_to_test = ['pip']
for package_name in packages_to_test:
env_name = 'EXPECTED_{}_VERSION'.format(package_name.upper())
expected_version = os.environ[env_name]
assert '{}=={}'.format(package_name, expected_version) in versions, (
'error: {} version should equal {}'.format(package_name, expected_version)
)
"""
)
)
VERSION_REGEX = r"([\w-]+)==([^\s]+)"
def get_versions_from_constraint_file(constraint_file):
constraint_file_text = constraint_file.read_text(encoding="utf8")
return dict(re.findall(VERSION_REGEX, constraint_file_text))
@pytest.mark.parametrize("python_version", ["3.6", "3.8", "3.10"])
def test_pinned_versions(tmp_path, python_version, build_frontend_env):
if utils.platform == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
project_dir = tmp_path / "project"
project_with_expected_version_checks.generate(project_dir)
build_environment = {}
if python_version == "3.6":
if utils.platform == "macos" and platform.machine() == "arm64":
pytest.skip("macOS arm64 does not support Python 3.6")
constraint_filename = "constraints-python36.txt"
build_pattern = "[cp]p36-*"
elif python_version == "3.7":
constraint_filename = "constraints-python37.txt"
build_pattern = "[cp]p37-*"
elif python_version == "3.8":
constraint_filename = "constraints-python38.txt"
build_pattern = "[cp]p38-*"
else:
constraint_filename = "constraints-python310.txt"
build_pattern = "[cp]p310-*"
constraint_file = cibuildwheel.util.resources_dir / constraint_filename
constraint_versions = get_versions_from_constraint_file(constraint_file)
for package in ["pip"]:
env_name = f"EXPECTED_{package.upper()}_VERSION"
build_environment[env_name] = constraint_versions[package]
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
# build and test the wheels
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BUILD": build_pattern,
"CIBW_ENVIRONMENT": cibw_environment_option,
**build_frontend_env,
},
)
# also check that we got the right wheels
if python_version == "3.6":
expected_wheels = [
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp36" in w or "-pp36" in w
]
elif python_version == "3.8":
expected_wheels = [
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp38" in w or "-pp38" in w
]
elif python_version == "3.10":
expected_wheels = [
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp310" in w or "-pp310" in w
]
else:
msg = "unhandled python version"
raise ValueError(msg)
assert set(actual_wheels) == set(expected_wheels)
def test_dependency_constraints_file(tmp_path, build_frontend_env):
if utils.platform == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
project_dir = tmp_path / "project"
project_with_expected_version_checks.generate(project_dir)
tool_versions = {
"pip": "23.1.2",
"delocate": "0.10.3",
}
constraints_file = tmp_path / "constraints file.txt"
constraints_file.write_text(
textwrap.dedent(
"""
pip=={pip}
delocate=={delocate}
importlib-metadata<3,>=0.12; python_version < "3.8"
""".format(**tool_versions)
)
)
build_environment = {}
for package_name, version in tool_versions.items():
env_name = f"EXPECTED_{package_name.upper()}_VERSION"
build_environment[env_name] = version
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
# build and test the wheels
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_ENVIRONMENT": cibw_environment_option,
"CIBW_DEPENDENCY_VERSIONS": str(constraints_file),
"CIBW_SKIP": "cp36-*",
**build_frontend_env,
},
)
# also check that we got the right wheels
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "-cp36" not in w]
assert set(actual_wheels) == set(expected_wheels)