diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 2693f4f3d..20aa3d940 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -407,7 +407,11 @@ def build(options: Options, tmp_path: Path) -> None: config.version ) ) - build_env["PIP_CONSTRAINT"] = constraint_path.as_uri() + user_constraints = build_env.get("PIP_CONSTRAINT") + our_constraints = constraint_path.as_uri() + build_env["PIP_CONSTRAINT"] = " ".join( + c for c in [user_constraints, our_constraints] if c + ) build_env["VIRTUALENV_PIP"] = get_pip_version(env) call( "python", diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 3cc92f921..d2be65783 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -443,7 +443,12 @@ def build(options: Options, tmp_path: Path) -> None: tmp_file.write_bytes(constraints_path.read_bytes()) constraints_path = tmp_file - build_env["PIP_CONSTRAINT"] = str(constraints_path) + our_constraints = str(constraints_path) + user_constraints = build_env.get("PIP_CONSTRAINT") + build_env["PIP_CONSTRAINT"] = " ".join( + c for c in [our_constraints, user_constraints] if c + ) + build_env["VIRTUALENV_PIP"] = get_pip_version(env) call( "python", diff --git a/docs/options.md b/docs/options.md index 427b17e01..e2e742ad1 100644 --- a/docs/options.md +++ b/docs/options.md @@ -743,7 +743,7 @@ Platform-specific environment variables are also available:
cibuildwheel always defines the environment variable `CIBUILDWHEEL=1`. This can be useful for [building wheels with optional extensions](faq.md#building-packages-with-optional-c-extensions). !!! note - To do its work, cibuildwheel internally sets the options `PIP_CONSTRAINT`, `VIRTUALENV_PIP`, `DIST_EXTRA_CONFIG`, `SETUPTOOLS_EXT_SUFFIX`, `PIP_DISABLE_PIP_VERSION_CHECK`, `PIP_ROOT_USER_ACTION`. Your assignments to these options might be overridden. + To do its work, cibuildwheel sets the variables `VIRTUALENV_PIP`, `DIST_EXTRA_CONFIG`, `SETUPTOOLS_EXT_SUFFIX`, `PIP_DISABLE_PIP_VERSION_CHECK`, `PIP_ROOT_USER_ACTION`, and it extends the variables `PATH` and `PIP_CONSTRAINT`. Your assignments to these options might be replaced or extended. ### `CIBW_ENVIRONMENT_PASS_LINUX` {: #environment-pass} > Set environment variables on the host to pass-through to the container. diff --git a/test/test_environment.py b/test/test_environment.py index 35de87850..faaba7f3b 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -93,3 +93,52 @@ def test_overridden_path(tmp_path, capfd): assert len(os.listdir(output_dir)) == 0 captured = capfd.readouterr() assert "python available on PATH doesn't match our installed instance" in captured.err + + +@pytest.mark.parametrize("build_frontend", ["pip", "build"]) +def test_overridden_pip_constraint(tmp_path, build_frontend): + """ + Verify that users can use PIP_CONSTRAINT to specify a specific version of + a build-system.requires dependency, by asserting the version of pytz in the + setup.py. + """ + project_dir = tmp_path / "project" + + project = test_projects.new_c_project( + setup_py_add=textwrap.dedent( + """ + import pytz + assert pytz.__version__ == "2022.4" + """ + ) + ) + project.files["pyproject.toml"] = textwrap.dedent( + """ + [build-system] + requires = ["setuptools", "pytz"] + build-backend = "setuptools.build_meta" + """ + ) + project.generate(project_dir) + + if utils.platform == "linux": + # put the constraints file in the project directory, so it's available + # in the docker container + constraints_file = project_dir / "constraints.txt" + else: + constraints_file = tmp_path / "constraints.txt" + + constraints_file.write_text("pytz==2022.4") + + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_BUILD": "cp312-*", + "CIBW_BUILD_FRONTEND": build_frontend, + "PIP_CONSTRAINT": str(constraints_file), + "CIBW_ENVIRONMENT_LINUX": "PIP_CONSTRAINT=./constraints.txt", + }, + ) + + expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp312" in w] + assert set(actual_wheels) == set(expected_wheels)