ITADN

Clarify environment precedence: CIBW option env vars vs runtime env keys, and global vs platform TOML tables

#2836OpenIvanaGyro 创建于 2026-05-03
I
IvanaGyrocommented
## Disclosure This report was prepared with AI assistance. ## Description I ran into a documentation ambiguity while testing `pypa/cibuildwheel@v3.3.0` on GitHub Actions macOS runners. The configuration docs say that environment variables take precedence over TOML settings. I initially interpreted this to mean that a workflow environment variable would override the same key assigned in `[tool.cibuildwheel].environment` or `[tool.cibuildwheel.macos].environment`. After testing, the actual behavior appears to be more nuanced: 1. `CIBW_*` environment variables override TOML **cibuildwheel options**. 2. Ordinary runtime environment variables inherited from the GitHub Actions runner do **not** necessarily override duplicate keys assigned by the resolved `environment` option. 3. A platform-specific TOML `environment` table appears to replace the global TOML `environment` table, rather than key-merge with it. I think the implementation is probably correct, but the docs could clarify these separate precedence layers. ## Environment - GitHub Actions - `pypa/cibuildwheel@v3.3.0` - Platform: macOS runner ## Minimal experiment Workflow env: ```yaml env: CYTNX_CIBW_ENV_SENTINEL: workflow-env ```` A `before-build` command prints the value: ```toml [tool.cibuildwheel] before-build = "python - <<'PY'\nimport os\nprint('CYTNX_CIBW_ENV_SENTINEL=' + str(os.environ.get('CYTNX_CIBW_ENV_SENTINEL')))\nPY" ``` ### Case 1: global TOML `environment` defines the sentinel ```toml [tool.cibuildwheel.environment] CYTNX_CIBW_ENV_SENTINEL = "pyproject-global" ``` If no platform-specific macOS `environment` table exists, I would expect the printed value to be: ```text CYTNX_CIBW_ENV_SENTINEL=pyproject-global ``` because macOS starts from the host environment, then applies the resolved cibuildwheel `environment` assignments. ### Case 2: global TOML `environment` defines the sentinel, but macOS has its own `environment` table without that key ```toml [tool.cibuildwheel.environment] CYTNX_CIBW_ENV_SENTINEL = "pyproject-global" [tool.cibuildwheel.macos.environment] SOME_OTHER_KEY = "some-value" ``` Observed result: ```text CYTNX_CIBW_ENV_SENTINEL=workflow-env ``` My interpretation is that `[tool.cibuildwheel.macos].environment` replaces `[tool.cibuildwheel].environment` as the effective `environment` option, rather than key-merging with it. Since the effective macOS `environment` no longer assigns `CYTNX_CIBW_ENV_SENTINEL`, the inherited GitHub Actions value remains visible. ### Case 3: macOS TOML `environment` explicitly defines the sentinel ```toml [tool.cibuildwheel.environment] CYTNX_CIBW_ENV_SENTINEL = "pyproject-global" [tool.cibuildwheel.macos.environment] CYTNX_CIBW_ENV_SENTINEL = "pyproject-macos" ``` Observed result: ```text CYTNX_CIBW_ENV_SENTINEL=pyproject-macos ``` This suggests that once the resolved macOS `environment` option assigns the duplicate runtime key, that assignment overwrites the inherited GitHub Actions environment value. ## Source-code reasoning In `cibuildwheel/options.py`, `OptionsReader.get()` resolves options in roughly this order: 1. defaults 2. default platform options 3. global TOML config 4. platform TOML config 5. overrides 6. `CIBW_<OPTION>` 7. `CIBW_<OPTION>_<PLATFORM>` This supports the docs statement that environment variables override TOML settings when the variables are cibuildwheel option variables such as `CIBW_ENVIRONMENT` or `CIBW_ENVIRONMENT_MACOS`. However, once the effective `environment` option is resolved, macOS applies it on top of the inherited host environment. In `cibuildwheel/environment.py`, `ParsedEnvironment.as_dictionary()` starts with `prev_environment` and then applies assignments in order: ```python environment = {**prev_environment} for assignment in self.assignments: value = assignment.evaluated_value(environment=environment, executor=executor) environment[assignment.name] = value ``` Therefore, duplicate keys in the resolved TOML `environment` assignment overwrite ordinary inherited runtime environment variables. Separately, because global and platform TOML values are resolved as option values, a platform-specific `[tool.cibuildwheel.macos].environment` table appears to replace `[tool.cibuildwheel].environment` by default. This can make a global `environment` key disappear from the effective macOS build environment if the macOS table does not repeat it. ## Why this was confusing The docs phrase “Environment variables will take precedence if defined” can be read as applying to ordinary CI runtime environment variables, not only cibuildwheel option variables. For example, it is easy to expect this workflow env: ```yaml env: CYTNX_CIBW_ENV_SENTINEL: workflow-env ``` to override this TOML runtime environment assignment: ```toml [tool.cibuildwheel.macos.environment] CYTNX_CIBW_ENV_SENTINEL = "pyproject-macos" ``` But the observed/source behavior is that TOML `environment` wins for duplicate runtime keys once it is part of the resolved `environment` option. ## Suggested documentation clarification I suggest adding a note near the configuration precedence docs or the `environment` option docs, along these lines: > The statement that environment variables override TOML configuration refers to cibuildwheel option variables such as `CIBW_BUILD`, `CIBW_ENVIRONMENT`, and `CIBW_ENVIRONMENT_MACOS`. It does not mean that ordinary host environment variables override duplicate keys assigned by the `environment` option. On macOS and Windows, the build environment starts from the host environment and then applies the resolved `environment` assignments, so duplicate keys in `environment` take precedence over ordinary host variables. And, separately: > Platform-specific TOML option values such as `[tool.cibuildwheel.macos].environment` replace the corresponding global `[tool.cibuildwheel].environment` value by default. They are not key-merged with the global table unless using a supported inheritance mechanism, such as `inherit.environment = "append"` in an override. For Linux, a related note could mention: > On Linux, `environment-pass` variables are inserted before evaluating `environment`, so duplicate keys assigned in `environment` take precedence over passed-through host values. ### Build log https://github.com/Cytnx-dev/Cytnx/actions/runs/25284460725/job/74126634485?pr=795 ### CI config https://github.com/Cytnx-dev/Cytnx/blob/73caa27a2c325e595819ea3e2a23dbedf20ea137/.github/workflows/release_pypi.yml
2 条评论