Compare commits

...
107 Commits
Author SHA1 Message Date
Joe Rickerby 41891277d3 Bump version: v1.5.0 2020-06-24 09:54:55 +01:00
Joe Rickerby 78ac83ff7e Merge pull request #358 from henryiii/henryiii/pep517
Adding PEP 518 test, fix 3.5 Python on Windows
2020-06-24 09:34:25 +01:00
Joe Rickerby 3ff84c52f9 Merge branch 'master' into henryiii/pep517 2020-06-23 19:39:59 +01:00
probot-auto-merge[bot] e72e4683db Merge pull request #383 from joerick/circleci-debug
Debug CircleCI failures
2020-06-23 11:26:55 +00:00
Joe Rickerby dfd8f4809a Merge remote-tracking branch 'origin/master' into circleci-debug 2020-06-23 11:17:36 +01:00
Joe Rickerby 666699a51e Configure probot-auto-merge 2020-06-23 11:16:23 +01:00
Joe Rickerby 947059bbf4 Don't try to install virtualenv 2020-06-23 10:27:23 +01:00
Joe Rickerby 4302090f08 Uninstall poetry 2020-06-23 10:25:35 +01:00
Joe Rickerby c68d50a073 Lock virtualenv version 2020-06-23 10:19:09 +01:00
Joe Rickerby a03a26c90e Update README options table 2020-06-23 09:59:22 +01:00
Joe Rickerby e3b272201e Merge pull request #342 from Czaki/setup_data
Add BEFORE_ALL options
2020-06-23 09:51:35 +01:00
Grzegorz Bokota 43fcb31231 fix tests 2020-06-22 13:55:04 +02:00
Grzegorz Bokota b4b46a1f06 fix mypy 2020-06-22 13:55:04 +02:00
Joe Rickerby 2057bba07f Update docs to reflect linux available python change 2020-06-22 13:55:04 +02:00
Joe Rickerby 46352c8e30 Add a modern python to linux build before_all environment 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 2e15fdddfd change to new test engine 2020-06-22 13:55:04 +02:00
Grzegorz Bokota fc52c5e7b6 add unit_test 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 7b7e24d36d add missed quote of before_all command 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 9f6c91404d fix flake8 2020-06-22 13:55:04 +02:00
Grzegorz BokotaandJoe Rickerby 219a65d5e3 Apply suggestions from code review
Co-authored-by: Joe Rickerby <joerick@mac.com>
2020-06-22 13:55:04 +02:00
Grzegorz Bokota 36b8f7fff2 changes in code from code review 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 4d5cf4629e fix mypy type warning 2020-06-22 13:55:04 +02:00
Grzegorz Bokota c1f155c0f2 add environment evaluation 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 3fe560cf14 fix mypy 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 75a0384d02 fix flake8 errors 2020-06-22 13:55:04 +02:00
Grzegorz Bokota 6501470357 Add BEFORE_ALL options 2020-06-22 13:55:04 +02:00
Joe Rickerby 8bfc313d02 Merge pull request #347 from Czaki/pre_commit
Pre commit
2020-06-22 12:19:11 +01:00
Joe Rickerby e6ac527416 Convert the workaround to use Path objects 2020-06-22 12:08:40 +01:00
Joe Rickerby c27c5feadb Merge branch 'master' into henryiii/pep517 2020-06-22 12:06:32 +01:00
Joe Rickerby 2b22ffda9b Add python3.9 note to version matrix 2020-06-22 11:42:41 +01:00
Yannick Jadoul 9a1f8a99e0 Merge pull request #376 from YannickJadoul/pathlib
Use pathlib.Path
2020-06-22 12:27:20 +02:00
Yannick Jadoul d552d29eae Revert use of Path.joinpath instead of Path.__div__ 2020-06-21 13:14:53 +02:00
Grzegorz Bokota aa99405a9c unpin flake, exclude pinned_docker_images.cfg 2020-06-19 21:15:33 +02:00
Grzegorz Bokota 39101ae8ea update mypy config 2020-06-19 21:12:12 +02:00
Grzegorz Bokota 1a83967261 remove json check 2020-06-19 21:12:12 +02:00
Grzegorz Bokota d43817b49a fixed files 2020-06-19 21:12:12 +02:00
Grzegorz Bokota 3b1f0dd453 add pre-commit configuration 2020-06-19 21:12:12 +02:00
Joe Rickerby a1db0f7ebb Merge pull request #378 from YannickJadoul/ignore-TestProject
Suppress warnings about pytest trying to collect TestProject
2020-06-19 11:02:52 +01:00
Yannick Jadoul acf5c24881 Use patlib.Path in tests and tools 2020-06-18 15:29:48 +02:00
Yannick Jadoul f012fa1af0 Mock Path.mkdir calls in unit tests 2020-06-18 00:23:25 +02:00
Yannick Jadoul b62b17a223 Replace shutil.move with Path.rename or Path.replace 2020-06-18 00:23:25 +02:00
Yannick Jadoul 265708854a Attend to review remarks 2020-06-18 00:23:25 +02:00
Yannick Jadoul e58aed1731 Fix overlooked os.path.abspath 2020-06-18 00:23:25 +02:00
Yannick Jadoul b3ffb04a2c Fix order of pathlib.Path.symlink_to arguments in windows.py 2020-06-18 00:23:25 +02:00
Yannick Jadoul c53e7824a7 Remove unused imports 2020-06-18 00:23:25 +02:00
Yannick Jadoul 46a39b06cb Fix paths in unit tests 2020-06-18 00:23:25 +02:00
Yannick Jadoul a7f73f1593 Use pathlib.Path in main cibuildwheel files 2020-06-18 00:23:25 +02:00
Yannick Jadoul 47323761dd Suppress warnings about pytest trying to collect TestProject 2020-06-18 00:23:09 +02:00
Yannick Jadoul 43fbcfe008 Merge pull request #379 from YannickJadoul/fix-travis-ci-windows-root-ca
Fix SSL error on Windows on Travis CI
2020-06-18 00:21:33 +02:00
Yannick Jadoul 5c19ff3f95 Fix 'ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)' error on Windows on Travis CI 2020-06-17 23:26:39 +02:00
Joe Rickerby 02e9ee3e96 Merge pull request #369 from Czaki/ensure_dir_name
Ensure dir name
2020-06-16 15:07:58 +01:00
Joe Rickerby df07aafae1 Merge pull request #374 from YannickJadoul/detect-virtualenv-real_prefix
Simplify virtualenv test in test_testing
2020-06-16 15:06:00 +01:00
Joe Rickerby 78edb0a06a Merge pull request #375 from joerick/appveyor-macos-allow-failures
Allow failures on Appveyor macos
2020-06-16 15:03:14 +01:00
Henry Schreiner 901ac79dbc review: Address review suggestion 2020-06-14 11:25:14 -04:00
Henry Schreiner 0597088f64 Adding PEP 518 test 2020-06-14 09:57:58 -04:00
Joe Rickerby f1c4ebbed0 Allow failures on Appveyor macos
Temporarily allow this build to fail to get the tests green again
2020-06-14 11:03:38 +01:00
Joe Rickerby fd9e3202a0 Merge pull request #348 from YannickJadoul/before-test-docs-order
Making order of options more consistent in docs and BuildOptions fields
2020-06-14 10:55:11 +01:00
Joe Rickerby 7afdd40714 Merge pull request #354 from henryiii/patch-2
Better help for GitHub Actions + Py27 workaround
2020-06-14 09:56:22 +01:00
Yannick Jadoul ed491d0e22 Simplify virtualenv test in test_testing 2020-06-14 00:37:34 +02:00
Joe Rickerby e12ca14006 Merge pull request #362 from breznak/gh-action-pypi-publish
example: for GH Actions use action to publish
2020-06-10 13:20:16 +01:00
Joe Rickerby 58fc418563 Update to add clarity to on: section 2020-06-10 13:18:22 +01:00
Yannick Jadoul 57e6f0f56d Replace "startsWith(matrix.os, 'windows')" by "runner.os == 'Windows'" in GitHub Actions configurations 2020-06-10 01:53:41 +02:00
Yannick Jadoul cc8dbbe8b3 Make deploy on published GitHub release optional in examples/github-deploy.yml 2020-06-08 15:50:38 +02:00
Yannick Jadoul bb5aac3d69 Move if-clause of PyPI upload to job level rather than action level, and specify to use only published releases 2020-06-08 13:23:28 +02:00
Grzegorz Bokota 374e88382b move abspath to system specific files 2020-06-08 10:19:02 +02:00
Grzegorz Bokota c74acd6363 change to abspath 2020-06-08 08:05:25 +02:00
Grzegorz Bokota 90023a3a70 fix logic for test 2020-06-06 20:26:50 +02:00
Grzegorz Bokota 0b82ab6674 ensure that package_dir is provided as package 2020-06-06 20:05:09 +02:00
Henry Schreiner fb0e192681 Add example snippit 2020-06-05 16:58:57 -04:00
Yannick Jadoul eedc5c6b79 Remove twine check from examples/github-deploy.yml as it's now integrated into the pypa/gh-action-pypi-publish action 2020-06-03 19:01:01 +02:00
Joe Rickerby 31c9247921 Merge pull request #360 from heitorlessa/improv/support-pyproject-poetry
Support projects without setup.py (pyproject.toml and setup.cfg are also valid)
2020-06-02 21:30:48 +01:00
Yannick JadoulandJoe Rickerby 4c3cbf702c Update examples/github-deploy.yml to upload on tags, as alternative to GitHub releases
Co-authored-by: Joe Rickerby <joerick@mac.com>
2020-06-02 22:09:33 +02:00
Yannick Jadoul a06998e2f6 Merge pull request #366 from YannickJadoul/ignore-docker-rm
Ignore errors when cleaning up docker container in linux.py
2020-06-02 21:45:50 +02:00
Joe Rickerby 4e15e202c8 style- inline function 2020-06-02 20:03:04 +01:00
Joe Rickerby 35ea7b6307 Remove debugging flags 2020-06-02 20:02:54 +01:00
Yannick Jadoul 46688ae3f9 Revert previous solution and just don't try removing the container if 'docker create' errors 2020-06-02 17:15:27 +02:00
Yannick Jadoul 9c3f44d086 Rename examples/*-deploy-only.yml to examples/*-deploy.yml, and keep sdist in dist/ in examples/github-deploy.yml 2020-06-02 17:07:18 +02:00
Yannick Jadoul 896337cbb1 Updating all GitHub actions version to actions/checkout@v2, actions/setup-python@v2, and actions/upload-artifact@v2 2020-06-02 15:23:15 +02:00
Yannick Jadoul a0dab888a7 Ignore errors when cleaning up docker container in linux.py 2020-06-02 15:09:41 +02:00
Yannick Jadoul d7cffde00f Add 'release' to 'on' section in examples/github-deploy-only.yml 2020-06-02 15:07:06 +02:00
Yannick Jadoul 562d81c6ea Add links to the PyPI deployment examples to the docs 2020-06-02 12:03:06 +02:00
Yannick Jadoul 66b392f4ee Implement @henriii's suggestion, adding a separate job on Linux to upload all artifacts at once 2020-06-02 11:48:15 +02:00
Marek Otahal dd3c87ece2 example: small doc 2020-06-01 16:04:44 +02:00
Marek Otahal 63f7a2ddc4 examples: revert to minima GH example, add deploymet
example showing pypi and GH release
2020-06-01 16:01:29 +02:00
Marek Otahal ca49d86ed8 example: publish to PyPI only on release tag 2020-06-01 15:32:51 +02:00
heitorlessa d9a317c370 fix: address Yannick's PR feedback 2020-06-01 14:30:14 +01:00
Marek Otahal add792de30 example: for GH Actions use action to publish
to PyPI, instead of calling twine directly.
2020-06-01 15:02:26 +02:00
heitorlessa 004fc03899 fix: remove integ test 2020-06-01 13:21:52 +01:00
heitorlessa 15f1678439 fix: install poetry before build for windows
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-06-01 10:44:58 +01:00
heitorlessa 3de38fc679 fix: assert single wheel workaround
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-06-01 10:03:53 +01:00
heitorlessa 63eda18cf9 chore: increase test verbosity to capture errors
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-06-01 09:31:54 +01:00
heitorlessa a15a5f1c0f fix: exclude pypy build that's failing
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-06-01 08:58:24 +01:00
heitorlessa d41cf65173 improv: address Henrii's feedback
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-06-01 08:37:08 +01:00
Yannick Jadoul e97b103148 Group environment variables querying in __main__.py 2020-06-01 00:04:32 +02:00
heitorlessa 4e6246d2a7 chore: flake8
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 22:43:30 +01:00
heitorlessa ab4f5209b5 improv: document test given when then
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 22:39:19 +01:00
heitorlessa 8a25718c71 fix: ignores images with outdated pip version
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 22:37:52 +01:00
heitorlessa a8bdac07e6 fix: python version requirement range
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 22:02:27 +01:00
Yannick Jadoul 2790fd1dd7 Put CIBW_TEST_COMMAND as first test option everywhere 2020-05-31 21:42:21 +02:00
heitorlessa f9401d94c2 fix: support py2.7 to accommodate current setup
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 20:14:24 +01:00
heitorlessa 4fb7874ca3 chore: address PR feedback
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 20:13:52 +01:00
heitorlessa bb1b050ab5 improv: add integ test dummy poetry package 2020-05-31 19:55:27 +01:00
heitorlessa e8d857db21 chore: flake8 mypy linting
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 17:56:43 +01:00
heitorlessa f3a136be78 improv: support pyproject.toml existence
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
2020-05-31 17:36:30 +01:00
Henry Schreiner 2c564dfb9c Mention action, drop example code. 2020-05-27 19:45:34 -04:00
Henry Schreiner 901f708d4c Better help for GitHub Actions + Py27 workaround 2020-05-27 15:56:12 -04:00
Yannick Jadoul edd461ad42 Making order of options more consistent in docs and BuildOptions fields 2020-05-17 22:30:18 +02:00
41 changed files with 692 additions and 338 deletions
+3 -1
View File
@@ -1,6 +1,8 @@
set -o errexit
set -o xtrace
$PYTHON --version
$PYTHON -m pip --version
$PYTHON -m pip install -q --user --ignore-installed --upgrade virtualenv
$PYTHON -m virtualenv -p $PYTHON venv
venv/bin/python -m pip install -r requirements-dev.txt
venv/bin/python -m pip freeze
+7
View File
@@ -0,0 +1,7 @@
# config file for https://github.com/bobvanderlinden/probot-auto-merge
# no approvals required, just the label is enough
minApprovals: {}
requiredLabels:
- merge when green
+3 -3
View File
@@ -18,8 +18,8 @@ jobs:
os: [ubuntu-18.04, windows-latest, macos-latest]
python_version: ['3.7']
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
name: Install Python ${{ matrix.python_version }}
with:
python-version: ${{ matrix.python_version }}
@@ -28,7 +28,7 @@ jobs:
run: |
python -m pip install -r requirements-dev.txt
- name: Install Visual C++ for Python 2.7
if: startsWith(matrix.os, 'windows')
if: runner.os == 'Windows'
run: |
choco install vcpython27 -f -y
- name: Test cibuildwheel
+21
View File
@@ -0,0 +1,21 @@
repos:
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.1
hooks:
- id: flake8
pass_filenames: true
# this seems to need to be here in addition to setup.cfg
exclude: cibuildwheel/resources/
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: check-merge-conflict
- id: end-of-file-fixer
exclude: cibuildwheel/resources/pinned_docker_images.cfg
- repo: https://github.com/pre-commit/mirrors-mypy
rev: '' # Use the sha / tag you want to point at
hooks:
- id: mypy
files: cibuildwheel|test
exclude: cibuildwheel/resources
+2
View File
@@ -35,6 +35,8 @@ jobs:
language: shell
before_install:
- choco install python3 --version 3.6.8 --no-progress -y
# Update root certificates to fix SSL error; see http://www.chawn.com/RootCerts.htm
- powershell "md C:\temp\certs; CertUtil -generateSSTFromWU C:\temp\certs\RootStore.sst; Get-ChildItem -Path C:\\temp\certs\Rootstore.sst | Import-Certificate -CertStoreLocation Cert:\\LocalMachine\\Root\\ | out-null"
env:
- PYTHON=C:\\Python36\\python
+39 -16
View File
@@ -22,11 +22,13 @@ What does it do?
| CPython 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
| CPython 3.9³ | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | |
| PyPy 2.7 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
| PyPy 3.6 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
<sup>¹ Not supported on Travis</sup><br>
<sup>² Beta support until Travis CI fixes <a href="https://travis-ci.community/t/no-space-left-on-device-for-system-z/5954/11">a bug</a></sup>
<sup>² Beta support until Travis CI fixes <a href="https://travis-ci.community/t/no-space-left-on-device-for-system-z/5954/11">a bug</a></sup><br>
<sup>³ Python 3.9 is not yet ABI stable, so you shouldn't publish wheels with it yet. But if you want to check that your wheels build on Python 3.9, try our [`python3.9` branch](https://github.com/joerick/cibuildwheel/pull/382)!</sup>
- Builds manylinux, macOS and Windows wheels for CPython and PyPy using Azure Pipelines, Travis CI, AppVeyor, and CircleCI
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
@@ -77,7 +79,7 @@ env:
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
install:
- python3 -m pip install cibuildwheel==1.4.2
- python3 -m pip install cibuildwheel==1.5.0
script:
# build the wheels, put them into './wheelhouse'
@@ -100,17 +102,20 @@ Options
| | Option | Description |
|---|--------|-------------|
| **Build selection** | [`CIBW_PLATFORM`](https://cibuildwheel.readthedocs.io/en/stable/options/#platform) | Override the auto-detected target platform |
| | [`CIBW_BUILD`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) [`CIBW_SKIP`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) | Choose the Python versions to build |
| **Build environment** | [`CIBW_ENVIRONMENT`](https://cibuildwheel.readthedocs.io/en/stable/options/#environment) | Set environment variables needed during the build |
| | [`CIBW_BUILD`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) <br> [`CIBW_SKIP`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) | Choose the Python versions to build |
| **Build customization** | [`CIBW_ENVIRONMENT`](https://cibuildwheel.readthedocs.io/en/stable/options/#environment) | Set environment variables needed during the build |
| | [`CIBW_BEFORE_ALL`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-all) | Execute a shell command on the build system before any wheels are built. |
| | [`CIBW_BEFORE_BUILD`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-build) | Execute a shell command preparing each wheel's build |
| | [`CIBW_REPAIR_WHEEL_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#repair-wheel-command) | Execute a shell command to repair each (non-pure Python) built wheel |
| | [`CIBW_MANYLINUX_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) [`CIBW_MANYLINUX_I686_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) [`CIBW_MANYLINUX_PYPY_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) | Specify alternative manylinux docker images |
| | [`CIBW_MANYLINUX_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) <br> [`CIBW_MANYLINUX_I686_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) <br> [`CIBW_MANYLINUX_PYPY_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) <br> [`CIBW_MANYLINUX_AARCH64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) <br> [`CIBW_MANYLINUX_PPC64LE_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) <br> [`CIBW_MANYLINUX_S390X_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) | Specify alternative manylinux docker images |
| | [`CIBW_DEPENDENCY_VERSIONS`](https://cibuildwheel.readthedocs.io/en/stable/options/#dependency-versions) | Specify how cibuildwheel controls the versions of the tools it uses |
| **Testing** | [`CIBW_TEST_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-command) | Execute a shell command to test each built wheel |
| | [`CIBW_BEFORE_TEST`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-test) | Execute shell command to prepare test environment |
| | [`CIBW_BEFORE_TEST`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-test) | Execute a shell command before testing each wheel |
| | [`CIBW_TEST_REQUIRES`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-requires) | Install Python dependencies before running the tests |
| | [`CIBW_TEST_EXTRAS`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-extras) | Install your wheel for testing using extras_require |
| **Other** | [`CIBW_BUILD_VERBOSITY`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-verbosity) | Increase/decrease the output of pip wheel |
Working examples
----------------
@@ -147,6 +152,24 @@ This is similar to static linking, so it might have some licence implications. C
Changelog
=========
### 1.5.0
_24 June 2020_
- 🌟 Add [`CIBW_BEFORE_ALL`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-all)
option, which lets you run a command on the build machine before any wheels
are built. This is especially useful when building on Linux, to `make`
something external to Python, or to `yum install` a dependency. (#342)
- ✨ Added support for projects using pyproject.toml instead of setup.py
(#360, #358)
- ✨ Added workaround to allow Python 3.5 on Windows to pull dependencies from
pyproject.toml. (#358)
- 📚 Improved Github Actions examples and docs (#354, #362)
- 🐛 Ensure pip wheel uses the specified package, and doesn't build a wheel
from PyPI (#369)
- 🛠 Internal changes: using pathlib.Path, precommit hooks, testing
improvements.
### 1.4.2
_25 May 2020_
@@ -169,7 +192,7 @@ _4 May 2020_
_2 May 2020_
- Deterministic builds. cibuildwheel now locks the versions of the tools it
- 🌟 Deterministic builds. cibuildwheel now locks the versions of the tools it
uses. This means that pinning your version of cibuildwheel pins the versions
of pip, setuptools, manylinux etc. that are used under the hood. This should
make things more reliable. But note that we don't control the entire build
@@ -199,7 +222,7 @@ _2 May 2020_
_12 March 2020_
- Add support for building on Github Actions! Check out the
- 🌟 Add support for building on Github Actions! Check out the
[docs](https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions)
for information on how to set it up. (#194)
- ✨ Add the `CIBW_BEFORE_TEST` option, which lets you run a command to
@@ -209,9 +232,9 @@ _12 March 2020_
_8 March 2020_
- Add support for building PyPy wheels, across Manylinux, macOS, and
- 🌟 Add support for building PyPy wheels, across Manylinux, macOS, and
Windows. (#185)
- Added the ability to build ARM64 (aarch64), ppc64le, and s390x wheels,
- 🌟 Added the ability to build ARM64 (aarch64), ppc64le, and s390x wheels,
using manylinux2014 and Travis CI. (#273)
- ✨ You can now build macOS wheels on Appveyor. (#230)
- 🛠 Changed default macOS minimum target to 10.9, from 10.6. This allows the
@@ -232,7 +255,7 @@ _8 March 2020_
_7 December 2019_
- Add support for building manylinux2014 wheels. To use, set
- 🌟 Add support for building manylinux2014 wheels. To use, set
`CIBW_MANYLINUX_X86_64_IMAGE` and CIBW_MANYLINUX_I686_IMAGE to
`manylinux2014`.
- ✨ Add support for [Linux on Appveyor](https://www.appveyor.com/blog/2018/03/06/appveyor-for-linux/) (#204, #207)
@@ -245,8 +268,8 @@ _7 December 2019_
_10 November 2019_
- Add support for building Python 3.8 wheels! (#180)
- Add support for building manylinux2010 wheels. cibuildwheel will now
- 🌟 Add support for building Python 3.8 wheels! (#180)
- 🌟 Add support for building manylinux2010 wheels. cibuildwheel will now
build using the manylinux2010 images by default. If your project is still
manylinux1 compatible, you should get both manylinux1 and manylinux2010
wheels - you can upload both to PyPI. If you always require manylinux1 wheels, you can
@@ -282,7 +305,7 @@ _28 May 2019_
_26 May 2019_
- Add support for building on Azure pipelines! This lets you build all
- 🌟 Add support for building on Azure pipelines! This lets you build all
Linux, Mac and Windows wheels on one service, so it promises to be the
easiest to set up! Check out the quickstart in the docs, or
[cibuildwheel-azure-example](https://github.com/joerick/cibuildwheel-azure-example)
@@ -312,8 +335,8 @@ _3 February 2019_
_23 September 2018_
- Add `CIBW_BUILD` option, for specifying which specific builds to perform (#101)
- Add support for building Mac and Linux on CircleCI (#91, #97)
- 🌟 Add `CIBW_BUILD` option, for specifying which specific builds to perform (#101)
- 🌟 Add support for building Mac and Linux on CircleCI (#91, #97)
- 🛠 Improved support for building universal wheels (#95)
- 🛠 Ensure log output is unbuffered and therefore in the correct order (#92)
- 🛠 Improved error reporting for errors that occur inside a package's setup.py (#88)
+5
View File
@@ -10,6 +10,11 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave
APPVEYOR_JOB_NAME: "python37-x64-macos-mojave"
# while pypy libffi dependency is failing the build, allow failures on macos
matrix:
allow_failures:
- APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave
stack: python 3.7
build: off
-1
View File
@@ -42,4 +42,3 @@ jobs:
- bash: |
python -m pip install -r requirements-dev.txt pytest-azurepipelines
python ./bin/run_tests.py
+2 -1
View File
@@ -3,10 +3,11 @@
import os
import subprocess
import sys
from pathlib import Path
if __name__ == '__main__':
# move cwd to the project root
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.chdir(Path(__file__).resolve().parents[1])
# run the unit tests
subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test'])
+1 -1
View File
@@ -1 +1 @@
__version__ = '1.4.2'
__version__ = '1.5.0'
+35 -29
View File
@@ -4,6 +4,7 @@ import sys
import textwrap
import traceback
from configparser import ConfigParser
from pathlib import Path
from typing import Any, Dict, List, Optional, overload
@@ -20,6 +21,7 @@ from cibuildwheel.util import (
BuildSelector,
DependencyConstraints,
Unbuffered,
resources_dir,
)
@@ -114,31 +116,44 @@ def main() -> None:
file=sys.stderr)
exit(2)
output_dir = args.output_dir
test_command = get_option_from_environment('CIBW_TEST_COMMAND', platform=platform)
test_requires = get_option_from_environment('CIBW_TEST_REQUIRES', platform=platform, default='').split()
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
package_dir = args.package_dir
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
package_dir = Path(args.package_dir)
output_dir = Path(args.output_dir)
if platform == 'linux':
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
elif platform == 'macos':
repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs x86_64 -w {dest_dir} {wheel}'
else:
repair_command_default = ''
repair_command = get_option_from_environment('CIBW_REPAIR_WHEEL_COMMAND', platform=platform, default=repair_command_default)
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
before_test = get_option_from_environment('CIBW_BEFORE_TEST', platform=platform, default='')
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
before_all = get_option_from_environment('CIBW_BEFORE_ALL', platform=platform, default='')
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
repair_command = get_option_from_environment('CIBW_REPAIR_WHEEL_COMMAND', platform=platform, default=repair_command_default)
dependency_versions = get_option_from_environment('CIBW_DEPENDENCY_VERSIONS', platform=platform, default='pinned')
test_command = get_option_from_environment('CIBW_TEST_COMMAND', platform=platform)
before_test = get_option_from_environment('CIBW_BEFORE_TEST', platform=platform)
test_requires = get_option_from_environment('CIBW_TEST_REQUIRES', platform=platform, default='').split()
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
build_selector = BuildSelector(build_config, skip_config)
try:
environment = parse_environment(environment_config)
except (EnvironmentParseError, ValueError):
print(f'cibuildwheel: Malformed environment option "{environment_config}"', file=sys.stderr)
traceback.print_exc(None, sys.stderr)
exit(2)
if dependency_versions == 'pinned':
dependency_constraints: Optional[DependencyConstraints] = DependencyConstraints.with_defaults()
elif dependency_versions == 'latest':
dependency_constraints = None
else:
dependency_constraints = DependencyConstraints(dependency_versions)
dependency_versions_path = Path(dependency_versions)
dependency_constraints = DependencyConstraints(dependency_versions_path)
if test_extras:
test_extras = f'[{test_extras}]'
@@ -148,21 +163,13 @@ def main() -> None:
except ValueError:
build_verbosity = 0
try:
environment = parse_environment(environment_config)
except (EnvironmentParseError, ValueError):
print(f'cibuildwheel: Malformed environment option "{environment_config}"', file=sys.stderr)
traceback.print_exc(None, sys.stderr)
exit(2)
build_selector = BuildSelector(build_config, skip_config)
# Add CIBUILDWHEEL environment variable
# This needs to be passed on to the docker container in linux.py
os.environ['CIBUILDWHEEL'] = '1'
if not os.path.exists(os.path.join(package_dir, 'setup.py')):
print('cibuildwheel: Could not find setup.py at root of package', file=sys.stderr)
if not any((package_dir / name).exists()
for name in ["setup.py", "setup.cfg", "pyproject.toml"]):
print('cibuildwheel: Could not find setup.py, setup.cfg or pyproject.toml at root of package', file=sys.stderr)
exit(2)
if args.print_build_identifiers:
@@ -171,9 +178,7 @@ def main() -> None:
manylinux_images: Optional[Dict[str, str]] = None
if platform == 'linux':
pinned_docker_images_file = os.path.join(
os.path.dirname(__file__), 'resources', 'pinned_docker_images.cfg'
)
pinned_docker_images_file = resources_dir / 'pinned_docker_images.cfg'
all_pinned_docker_images = ConfigParser()
all_pinned_docker_images.read(pinned_docker_images_file)
# all_pinned_docker_images looks like a dict of dicts, e.g.
@@ -206,12 +211,13 @@ def main() -> None:
test_command=test_command,
test_requires=test_requires,
test_extras=test_extras,
before_test=before_test,
before_build=before_build,
before_all=before_all,
build_verbosity=build_verbosity,
build_selector=build_selector,
repair_command=repair_command,
environment=environment,
before_test=before_test,
dependency_constraints=dependency_constraints,
manylinux_images=manylinux_images,
)
@@ -221,8 +227,8 @@ def main() -> None:
print_preamble(platform, build_options)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
if not output_dir.exists():
output_dir.mkdir(parents=True)
if platform == 'linux':
cibuildwheel.linux.build(build_options)
+3 -3
View File
@@ -1,6 +1,6 @@
import bashlex # type: ignore
from typing import Dict, List
from typing import Dict, List, Mapping
from . import bashlex_eval
@@ -61,8 +61,8 @@ class ParsedEnvironment:
def __init__(self, assignments: List[EnvironmentAssignment]):
self.assignments = assignments
def as_dictionary(self, prev_environment: Dict[str, str]) -> Dict[str, str]:
environment = prev_environment.copy()
def as_dictionary(self, prev_environment: Mapping[str, str]) -> Dict[str, str]:
environment = dict(**prev_environment)
for assignment in self.assignments:
value = assignment.evaluated_value(environment=environment)
+42 -21
View File
@@ -5,6 +5,7 @@ import subprocess
import sys
import textwrap
import uuid
from pathlib import Path, PurePath
from typing import List, NamedTuple, Optional, Union
@@ -104,32 +105,58 @@ def build(options: BuildOptions) -> None:
('pp', 'manylinux_x86_64', options.manylinux_images['pypy_x86_64']),
]
if not os.path.realpath(options.package_dir).startswith(os.path.realpath('.')):
cwd = Path.cwd()
abs_package_dir = options.package_dir.resolve()
if cwd != abs_package_dir and cwd not in abs_package_dir.parents:
raise Exception('package_dir must be inside the working directory')
container_package_dir = os.path.join('/project', os.path.relpath(options.package_dir, '.'))
container_package_dir = PurePath('/project') / abs_package_dir.relative_to(cwd)
for implementation, platform_tag, docker_image in platforms:
platform_configs = [c for c in python_configurations if c.identifier.startswith(implementation) and c.identifier.endswith(platform_tag)]
if not platform_configs:
continue
shell_cmd = ['linux32', '/bin/bash'] if platform_tag.endswith("i686") else ['/bin/bash']
container_name = f'cibuildwheel-{uuid.uuid4()}'
call(['docker', 'create',
'--env', 'CIBUILDWHEEL',
'--name', container_name,
'-i',
'-v', '/:/host', # ignored on CircleCI
docker_image,
'/bin/bash'])
try:
shell_cmd = ['linux32', '/bin/bash'] if platform_tag.endswith("i686") else ['/bin/bash']
call(['docker', 'create',
'--env', 'CIBUILDWHEEL',
'--name', container_name,
'-i',
'-v', '/:/host', # ignored on CircleCI
docker_image,
'/bin/bash'])
call(['docker', 'cp', '.', container_name + ':/project'])
call(['docker', 'start', container_name])
if options.before_all:
call(
['docker', 'exec', '-i', container_name] + shell_cmd,
universal_newlines=True,
input='''
PS4=' + '
set -o errexit
set -o xtrace
# add a modern Python interpreter to PATH so it can be used by BEFORE_ALL
# commands
export PATH=/opt/python/cp38-cp38:$PATH
{environment_exports}
sh -c {before_all}
'''.format(
environment_exports='\n'.join(options.environment.as_shell_commands()),
before_all=shlex.quote(prepare_command(options.before_all, project='/project', package=container_package_dir))
)
)
for config in platform_configs:
if options.dependency_constraints:
constraints_file = options.dependency_constraints.get_for_python_version(config.version)
@@ -200,7 +227,6 @@ def build(options: BuildOptions) -> None:
pip install {dependency_install_flags} virtualenv
venv_dir=`mktemp -d`/venv
python -m virtualenv --no-download "$venv_dir"
export __CIBW_VIRTUALENV_PATH__=$venv_dir
# run the tests in a subshell to keep that `activate`
# script from polluting the env
@@ -273,7 +299,7 @@ def build(options: BuildOptions) -> None:
# copy the output back into the host
call(['docker', 'cp',
container_name + ':/output/.',
os.path.abspath(options.output_dir)])
str(options.output_dir.resolve())])
except subprocess.CalledProcessError as error:
troubleshoot(options.package_dir, error)
exit(1)
@@ -282,16 +308,11 @@ def build(options: BuildOptions) -> None:
call(['docker', 'rm', '--force', '-v', container_name])
def troubleshoot(package_dir: str, error: Exception) -> None:
def troubleshoot(package_dir: Path, error: Exception) -> None:
if (isinstance(error, subprocess.CalledProcessError) and 'exec' in error.cmd):
# the bash script failed
print('Checking for common errors...')
so_files = []
for root, dirs, files in os.walk(package_dir):
for name in files:
_, ext = os.path.splitext(name)
if ext == '.so':
so_files.append(os.path.join(root, name))
so_files = list(package_dir.glob('**/*.so'))
if so_files:
print(textwrap.dedent('''
@@ -305,5 +326,5 @@ def troubleshoot(package_dir: str, error: Exception) -> None:
'''))
print(' Files detected:')
print('\n'.join([' ' + f for f in so_files]))
print('\n'.join([f' {f}' for f in so_files]))
print('')
+54 -47
View File
@@ -4,7 +4,7 @@ import shutil
import subprocess
import sys
import tempfile
from glob import glob
from pathlib import Path
from typing import Dict, List, Optional, NamedTuple, Union
@@ -52,41 +52,41 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
return [c for c in python_configurations if build_selector(c.identifier)]
SYMLINKS_DIR = '/tmp/cibw_bin'
SYMLINKS_DIR = Path('/tmp/cibw_bin')
def make_symlinks(installation_bin_path: str, python_executable: str, pip_executable: str) -> None:
assert os.path.exists(os.path.join(installation_bin_path, python_executable))
def make_symlinks(installation_bin_path: Path, python_executable: str, pip_executable: str) -> None:
assert (installation_bin_path / python_executable).exists()
# Python bin folders on Mac don't symlink `python3` to `python`, and neither
# does PyPy for `pypy` or `pypy3`, so we do that so `python` and `pip` always
# point to the active configuration.
if os.path.exists(SYMLINKS_DIR):
if SYMLINKS_DIR.exists():
shutil.rmtree(SYMLINKS_DIR)
os.makedirs(SYMLINKS_DIR)
SYMLINKS_DIR.mkdir(parents=True)
os.symlink(os.path.join(installation_bin_path, python_executable), os.path.join(SYMLINKS_DIR, 'python'))
os.symlink(os.path.join(installation_bin_path, python_executable + '-config'), os.path.join(SYMLINKS_DIR, 'python-config'))
os.symlink(os.path.join(installation_bin_path, pip_executable), os.path.join(SYMLINKS_DIR, 'pip'))
(SYMLINKS_DIR / 'python').symlink_to(installation_bin_path / python_executable)
(SYMLINKS_DIR / 'python-config').symlink_to(installation_bin_path / (python_executable + '-config'))
(SYMLINKS_DIR / 'pip').symlink_to(installation_bin_path / pip_executable)
def install_cpython(version: str, url: str) -> str:
def install_cpython(version: str, url: str) -> Path:
installed_system_packages = subprocess.check_output(['pkgutil', '--pkgs'], universal_newlines=True).splitlines()
# if this version of python isn't installed, get it from python.org and install
python_package_identifier = f'org.python.Python.PythonFramework-{version}'
if python_package_identifier not in installed_system_packages:
# download the pkg
download(url, '/tmp/Python.pkg')
download(url, Path('/tmp/Python.pkg'))
# install
call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/'])
# patch open ssl
if version == '3.5':
open_ssl_patch_url = f'https://github.com/mayeut/patch-macos-python-openssl/releases/download/v1.0.2u/patch-macos-python-{version}-openssl-v1.0.2u.tar.gz'
download(open_ssl_patch_url, '/tmp/python-patch.tar.gz')
download(open_ssl_patch_url, Path('/tmp/python-patch.tar.gz'))
call(['sudo', 'tar', '-C', f'/Library/Frameworks/Python.framework/Versions/{version}/', '-xmf', '/tmp/python-patch.tar.gz'])
installation_bin_path = f'/Library/Frameworks/Python.framework/Versions/{version}/bin'
installation_bin_path = Path(f'/Library/Frameworks/Python.framework/Versions/{version}/bin')
python_executable = 'python3' if version[0] == '3' else 'python'
pip_executable = 'pip3' if version[0] == '3' else 'pip'
make_symlinks(installation_bin_path, python_executable, pip_executable)
@@ -94,16 +94,18 @@ def install_cpython(version: str, url: str) -> str:
return installation_bin_path
def install_pypy(version: str, url: str) -> str:
def install_pypy(version: str, url: str) -> Path:
pypy_tar_bz2 = url.rsplit('/', 1)[-1]
assert pypy_tar_bz2.endswith(".tar.bz2")
pypy_base_filename = os.path.splitext(os.path.splitext(pypy_tar_bz2)[0])[0]
installation_path = os.path.join('/tmp', pypy_base_filename)
if not os.path.exists(installation_path):
download(url, os.path.join("/tmp", pypy_tar_bz2))
call(['tar', '-C', '/tmp', '-xf', os.path.join("/tmp", pypy_tar_bz2)])
extension = ".tar.bz2"
assert pypy_tar_bz2.endswith(extension)
pypy_base_filename = pypy_tar_bz2[:-len(extension)]
installation_path = Path('/tmp') / pypy_base_filename
if not installation_path.exists():
downloaded_tar_bz2 = Path("/tmp") / pypy_tar_bz2
download(url, downloaded_tar_bz2)
call(['tar', '-C', '/tmp', '-xf', str(downloaded_tar_bz2)])
installation_bin_path = os.path.join(installation_path, 'bin')
installation_bin_path = installation_path / 'bin'
python_executable = 'pypy3' if version[0] == '3' else 'pypy'
pip_executable = 'pip3' if version[0] == '3' else 'pip'
make_symlinks(installation_bin_path, python_executable, pip_executable)
@@ -121,8 +123,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
env = os.environ.copy()
env['PATH'] = os.pathsep.join([
SYMLINKS_DIR,
installation_bin_path,
str(SYMLINKS_DIR),
str(installation_bin_path),
env['PATH'],
])
@@ -144,8 +146,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
exit(1)
# install pip & wheel
call(['python', get_pip_script] + dependency_constraint_flags, env=env, cwd="/tmp")
assert os.path.exists(os.path.join(installation_bin_path, 'pip'))
call(['python', str(get_pip_script)] + dependency_constraint_flags, env=env, cwd="/tmp")
assert (installation_bin_path / 'pip').exists()
call(['which', 'pip'], env=env)
call(['pip', '--version'], env=env)
which_pip = subprocess.check_output(['which', 'pip'], env=env, universal_newlines=True).strip()
@@ -170,9 +172,14 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
def build(options: BuildOptions) -> None:
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
repaired_wheel_dir = os.path.join(temp_dir, 'repaired_wheel')
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
if options.before_all:
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
call([before_all_prepared], shell=True, env=env)
python_configurations = get_python_configurations(options.build_selector)
@@ -180,7 +187,7 @@ def build(options: BuildOptions) -> None:
dependency_constraint_flags = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
'-c', str(options.dependency_constraints.get_for_python_version(config.version))
]
env = setup_python(config, dependency_constraint_flags, options.environment)
@@ -191,40 +198,41 @@ def build(options: BuildOptions) -> None:
call(before_build_prepared, env=env, shell=True)
# build the wheel
if os.path.exists(built_wheel_dir):
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
os.makedirs(built_wheel_dir)
call(['pip', 'wheel', options.package_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(options.build_verbosity), env=env)
built_wheel = glob(os.path.join(built_wheel_dir, '*.whl'))[0]
built_wheel_dir.mkdir(parents=True)
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
call(['pip', 'wheel', str(options.package_dir.resolve()), '-w', str(built_wheel_dir), '--no-deps'] + get_build_verbosity_extra_flags(options.build_verbosity), env=env)
built_wheel = next(built_wheel_dir.glob('*.whl'))
# repair the wheel
if os.path.exists(repaired_wheel_dir):
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
os.makedirs(repaired_wheel_dir)
if built_wheel.endswith('none-any.whl') or not options.repair_command:
repaired_wheel_dir.mkdir(parents=True)
if built_wheel.name.endswith('none-any.whl') or not options.repair_command:
# pure Python wheel or empty repair command
shutil.move(built_wheel, repaired_wheel_dir)
built_wheel.rename(repaired_wheel_dir / built_wheel.name)
else:
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
call(repair_command_prepared, env=env, shell=True)
repaired_wheel = glob(os.path.join(repaired_wheel_dir, '*.whl'))[0]
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
if options.test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv'] + dependency_constraint_flags, env=env)
venv_dir = tempfile.mkdtemp()
venv_dir = Path(tempfile.mkdtemp())
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
call(['python', '-m', 'virtualenv', '--no-download', str(venv_dir)], env=env)
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
os.path.join(venv_dir, 'bin'),
str(venv_dir / 'bin'),
virtualenv_env['PATH'],
])
virtualenv_env["__CIBW_VIRTUALENV_PATH__"] = venv_dir
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
@@ -234,7 +242,7 @@ def build(options: BuildOptions) -> None:
call(before_test_prepared, env=virtualenv_env, shell=True)
# install the wheel
call(['pip', 'install', repaired_wheel + options.test_extras], env=virtualenv_env)
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
# test the wheel
if options.test_requires:
@@ -245,8 +253,8 @@ def build(options: BuildOptions) -> None:
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=os.path.abspath('.'),
package=os.path.abspath(options.package_dir)
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
@@ -254,5 +262,4 @@ def build(options: BuildOptions) -> None:
shutil.rmtree(venv_dir)
# we're all done here; move it to output (overwrite existing)
dst = os.path.join(options.output_dir, os.path.basename(repaired_wheel))
shutil.move(repaired_wheel, dst)
repaired_wheel.replace(options.output_dir / repaired_wheel.name)
+30 -29
View File
@@ -1,14 +1,15 @@
import os
import urllib.request
from fnmatch import fnmatch
from pathlib import Path
from time import sleep
from typing import Dict, List, NamedTuple, Optional
from typing import Dict, List, NamedTuple, Optional, Union
from .environment import ParsedEnvironment
def prepare_command(command: str, **kwargs: str) -> str:
def prepare_command(command: str, **kwargs: Union[str, os.PathLike]) -> str:
'''
Preprocesses a command by expanding variables like {python}.
@@ -58,11 +59,11 @@ class Unbuffered:
return getattr(self.stream, attr)
def download(url: str, dest: str) -> None:
print('+ Download ' + url + ' to ' + dest)
dest_dir = os.path.dirname(dest)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
def download(url: str, dest: Path) -> None:
print(f'+ Download {url} to {dest}')
dest_dir = dest.parent
if not dest_dir.exists():
dest_dir.mkdir(parents=True)
repeat_num = 3
for i in range(repeat_num):
@@ -76,52 +77,52 @@ def download(url: str, dest: str) -> None:
break
try:
with open(dest, 'wb') as file:
file.write(response.read())
dest.write_bytes(response.read())
finally:
response.close()
class DependencyConstraints:
def __init__(self, base_file_path: str):
assert os.path.exists(base_file_path)
self.base_file_path = os.path.abspath(base_file_path)
def __init__(self, base_file_path: Path):
assert base_file_path.exists()
self.base_file_path = base_file_path.resolve()
@staticmethod
def with_defaults() -> 'DependencyConstraints':
return DependencyConstraints(
base_file_path=os.path.join(os.path.dirname(__file__), 'resources', 'constraints.txt')
base_file_path=resources_dir / 'constraints.txt'
)
def get_for_python_version(self, version: str) -> str:
def get_for_python_version(self, version: str) -> Path:
version_parts = version.split('.')
# try to find a version-specific dependency file e.g. if
# ./constraints.txt is the base, look for ./constraints-python27.txt
base, ext = os.path.splitext(self.base_file_path)
specific = base + f'-python{version_parts[0]}{version_parts[1]}'
specific_file_path = specific + ext
if os.path.exists(specific_file_path):
specific_stem = self.base_file_path.stem + f'-python{version_parts[0]}{version_parts[1]}'
specific_name = specific_stem + self.base_file_path.suffix
specific_file_path = self.base_file_path.with_name(specific_name)
if specific_file_path.exists():
return specific_file_path
else:
return self.base_file_path
class BuildOptions(NamedTuple):
package_dir: str
output_dir: str
package_dir: Path
output_dir: Path
build_selector: BuildSelector
environment: ParsedEnvironment
before_all: str
before_build: Optional[str]
repair_command: str
manylinux_images: Optional[Dict[str, str]]
dependency_constraints: Optional[DependencyConstraints]
test_command: Optional[str]
before_test: Optional[str]
test_requires: List[str]
test_extras: str
before_build: Optional[str]
build_verbosity: int
build_selector: BuildSelector
repair_command: str
environment: ParsedEnvironment
before_test: str
dependency_constraints: Optional[DependencyConstraints]
manylinux_images: Optional[Dict[str, str]]
resources_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources'))
get_pip_script = os.path.join(resources_dir, 'get-pip.py')
resources_dir = Path(__file__).resolve().parent / 'resources'
get_pip_script = resources_dir / 'get-pip.py'
+83 -49
View File
@@ -3,8 +3,9 @@ import shutil
import subprocess
import sys
import tempfile
from glob import glob
from pathlib import Path
from zipfile import ZipFile
import toml
from typing import Dict, List, Optional, NamedTuple
@@ -19,7 +20,7 @@ from .util import (
)
IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache')
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
@@ -71,36 +72,38 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
return python_configurations
def extract_zip(zip_src: str, dest: str) -> None:
def extract_zip(zip_src: Path, dest: Path) -> None:
with ZipFile(zip_src) as zip:
zip.extractall(dest)
def install_cpython(version: str, arch: str, nuget: str) -> str:
def install_cpython(version: str, arch: str, nuget: Path) -> Path:
nuget_args = get_nuget_args(version, arch)
installation_path = os.path.join(nuget_args[-1], nuget_args[0] + '.' + version, 'tools')
shell([nuget, 'install'] + nuget_args)
installation_path = Path(nuget_args[-1]) / (nuget_args[0] + '.' + version) / 'tools'
shell([str(nuget), 'install'] + nuget_args)
return installation_path
def install_pypy(version: str, arch: str, url: str) -> str:
def install_pypy(version: str, arch: str, url: str) -> Path:
assert arch == '32'
# Inside the PyPy zip file is a directory with the same name
zip_filename = url.rsplit('/', 1)[-1]
installation_path = os.path.join('C:\\cibw', os.path.splitext(zip_filename)[0])
if not os.path.exists(installation_path):
pypy_zip = os.path.join('C:\\cibw', zip_filename)
extension = ".zip"
assert zip_filename.endswith(extension)
installation_path = Path('C:\\cibw') / zip_filename[:-len(extension)]
if not installation_path.exists():
pypy_zip = Path('C:\\cibw') / zip_filename
download(url, pypy_zip)
# Extract to the parent directory because the zip file still contains a directory
extract_zip(pypy_zip, os.path.dirname(installation_path))
extract_zip(pypy_zip, installation_path.parent)
pypy_exe = 'pypy3.exe' if version[0] == '3' else 'pypy.exe'
shell(['mklink', os.path.join(installation_path, 'python.exe'), os.path.join(installation_path, pypy_exe)])
(installation_path / 'python.exe').symlink_to(installation_path / pypy_exe)
return installation_path
def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: List[str], environment: ParsedEnvironment) -> Dict[str, str]:
nuget = 'C:\\cibw\\nuget.exe'
if not os.path.exists(nuget):
nuget = Path('C:\\cibw\\nuget.exe')
if not nuget.exists():
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
if python_configuration.identifier.startswith('cp'):
@@ -111,15 +114,15 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
else:
raise ValueError("Unknown Python implementation")
assert os.path.exists(os.path.join(installation_path, 'python.exe'))
assert (installation_path / 'python.exe').exists()
# set up PATH and environment variables for run_with_env
env = os.environ.copy()
env['PYTHON_VERSION'] = python_configuration.version
env['PYTHON_ARCH'] = python_configuration.arch
env['PATH'] = os.pathsep.join([
installation_path,
os.path.join(installation_path, 'Scripts'),
str(installation_path),
str(installation_path / 'Scripts'),
env['PATH']
])
# update env with results from CIBW_ENVIRONMENT
@@ -130,16 +133,16 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
shell(['python', '--version'], env=env)
shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)"'], env=env)
where_python = subprocess.check_output(['where', 'python'], env=env, universal_newlines=True).splitlines()[0].strip()
if where_python != os.path.join(installation_path, 'python.exe'):
if where_python != str(installation_path / 'python.exe'):
print("cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it.", file=sys.stderr)
exit(1)
# make sure pip is installed
if not os.path.exists(os.path.join(installation_path, 'Scripts', 'pip.exe')):
shell(['python', get_pip_script] + dependency_constraint_flags, env=env, cwd="C:\\cibw")
assert os.path.exists(os.path.join(installation_path, 'Scripts', 'pip.exe'))
if not (installation_path / 'Scripts' / 'pip.exe').exists():
shell(['python', str(get_pip_script)] + dependency_constraint_flags, env=env, cwd="C:\\cibw")
assert (installation_path / 'Scripts' / 'pip.exe').exists()
where_pip = subprocess.check_output(['where', 'pip'], env=env, universal_newlines=True).splitlines()[0].strip()
if where_pip.strip() != os.path.join(installation_path, 'Scripts', 'pip.exe'):
if where_pip.strip() != str(installation_path / 'Scripts' / 'pip.exe'):
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
@@ -151,21 +154,51 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
return env
def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
"""
Python 3.5 PEP 518 hack (see https://github.com/pypa/pip/issues/8392#issuecomment-639563494)
Basically, nuget's Python is an embedded Python distribution, which is not supported by pip.
Before version 3.6, there was no way to disable the "embedded" behavior, including the ignoring
of environment variables, including the ones pip uses to setup PEP 518 builds.
The fix here is as suggested in that issue; we manually setup the PEP 518 requirements. Since we
are in a fresh environment (except for pinned cibuildweel dependencies), the build is already
mostly "isolated".
"""
pyproject_path = package_dir / 'pyproject.toml'
if pyproject_path.exists():
data = toml.load(pyproject_path)
requirements = (
data['build-system'].get('requires', [])
if 'build-system' in data
else []
)
if requirements:
shell(['pip', 'install'] + requirements, env=env)
def build(options: BuildOptions) -> None:
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
repaired_wheel_dir = os.path.join(temp_dir, 'repaired_wheel')
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
# install nuget as best way to provide python
nuget = 'C:\\cibw\\nuget.exe'
nuget = Path('C:\\cibw\\nuget.exe')
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
if options.before_all:
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
shell([before_all_prepared], env=env)
python_configurations = get_python_configurations(options.build_selector)
for config in python_configurations:
dependency_constraint_flags = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
'-c', str(options.dependency_constraints.get_for_python_version(config.version))
]
# install Python
@@ -176,43 +209,47 @@ def build(options: BuildOptions) -> None:
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
shell([before_build_prepared], env=env)
# activate the PEP 518 patch if on Windows Python 3.5
# (will only have an effect if PEP 517 builds are used):
if config.version.startswith('3.5'):
pep_518_cp35_workaround(options.package_dir, env)
# build the wheel
if os.path.exists(built_wheel_dir):
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
os.makedirs(built_wheel_dir)
shell(['pip', 'wheel', options.package_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(options.build_verbosity), env=env)
built_wheel = glob(os.path.join(built_wheel_dir, '*.whl'))[0]
built_wheel_dir.mkdir(parents=True)
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
shell(['pip', 'wheel', str(options.package_dir.resolve()), '-w', str(built_wheel_dir), '--no-deps'] + get_build_verbosity_extra_flags(options.build_verbosity), env=env)
built_wheel = next(built_wheel_dir.glob('*.whl'))
# repair the wheel
if os.path.exists(repaired_wheel_dir):
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
os.makedirs(repaired_wheel_dir)
if built_wheel.endswith('none-any.whl') or not options.repair_command:
repaired_wheel_dir.mkdir(parents=True)
if built_wheel.name.endswith('none-any.whl') or not options.repair_command:
# pure Python wheel or empty repair command
shutil.move(built_wheel, repaired_wheel_dir)
built_wheel.rename(repaired_wheel_dir / built_wheel.name)
else:
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
shell([repair_command_prepared], env=env)
repaired_wheel = glob(os.path.join(repaired_wheel_dir, '*.whl'))[0]
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
if options.test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
shell(['pip', 'install', 'virtualenv'] + dependency_constraint_flags, env=env)
venv_dir = tempfile.mkdtemp()
venv_dir = Path(tempfile.mkdtemp())
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
shell(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
shell(['python', '-m', 'virtualenv', '--no-download', str(venv_dir)], env=env)
virtualenv_env = env.copy()
venv_script_path = os.path.join(venv_dir, 'Scripts')
virtualenv_env['PATH'] = os.pathsep.join([
venv_script_path,
str(venv_dir / 'Scripts'),
virtualenv_env['PATH'],
])
virtualenv_env["__CIBW_VIRTUALENV_PATH__"] = venv_dir
# check that we are using the Python from the virtual environment
shell(['which', 'python'], env=virtualenv_env)
@@ -226,7 +263,7 @@ def build(options: BuildOptions) -> None:
shell([before_test_prepared], env=virtualenv_env)
# install the wheel
shell(['pip', 'install', repaired_wheel + options.test_extras], env=virtualenv_env)
shell(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
# test the wheel
if options.test_requires:
@@ -237,8 +274,8 @@ def build(options: BuildOptions) -> None:
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=os.path.abspath('.'),
package=os.path.abspath(options.package_dir)
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
shell([test_command_prepared], cwd='c:\\', env=virtualenv_env)
@@ -246,7 +283,4 @@ def build(options: BuildOptions) -> None:
shutil.rmtree(venv_dir)
# we're all done here; move it to output (remove if already exists)
dst = os.path.join(options.output_dir, os.path.basename(repaired_wheel))
if os.path.isfile(dst):
os.remove(dst)
shutil.move(repaired_wheel, dst)
repaired_wheel.replace(options.output_dir / repaired_wheel.name)
+28 -2
View File
@@ -39,5 +39,31 @@ Forcing `distutils` or `setuptools` to use a more recent version of MSVC that su
1. Set the environment variables `DISTUTILS_USE_SDK=1` and `MSSdk=1`. These two environment variables will tell `distutils`/`setuptools` to not search and set up a build environment that uses Visual C++ for Python 2.7 (aka. MSVC 9).
2. Set up the build Visual Studio build environment you want to use, making sure that e.g. `PATH` contains `cl`, `link`, etc.
- Usually, this can be done through `vcvarsall.bat x86` or `vcvarsall.bat x64`. The exact location of this file depends on the installation, but the default path for VS 2019 Community (e.g. used in AppVeyor's `Visual Studio 2019` image) is `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat`. **Note**: `vcvarsall.bat` changes the environment variables, so this cannot be run in a subprocess/subshell and consequently running `vsvarsall.bat` in `CIBW_BEFORE_BUILD` does not have any effect.
- In Azure Pipelines, [a `VSBuild` task is available](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/visual-studio-build) and GitHub Actions has [an action `microsoft/setup-msbuild`](https://github.com/microsoft/setup-msbuild) that help setting up the Visual Studio environment.
3. Next, call `cibuildwheel`. Unfortunately, MSVC has separate toolchains for compiling 32-bit and 64-bit, so you will need to run `cibuildwheel` twice: once with `CIBW_BUILD=*-win32` after setting up the `x86` build environment, and once with `CIBW_BUILD=*-win_amd64` in a `x64` enviroment (see previous step).
- In Azure Pipelines, [a `VSBuild` task is available](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/visual-studio-build)
- In GitHub Actions, the default shell is powershell, so you'll need to use `shell: cmd` to source a `.bat` file, and the directory is `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat"`. Or you can use an action, such as the [`ilammy/msvc-dev-cmd@v1`](https://github.com/ilammy/msvc-dev-cmd) action to setup the environment (see example below).
3. Next, call `cibuildwheel`. Unfortunately, MSVC has separate toolchains for compiling 32-bit and 64-bit, so you will need to run `cibuildwheel` twice: once with `CIBW_BUILD=*-win32` after setting up the `x86` build environment, and once with `CIBW_BUILD=*-win_amd64` in a `x64` environment (see previous step).
**GitHub Action example with ilammy/msvc-dev-cmd**:
```yaml
- uses: ilammy/msvc-dev-cmd@v1
- name: Build 64-bit wheel
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_BUILD: cp27-win_amd64
DISTUTILS_USE_SDK: 1
MSSdk: 1
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86
- name: Build 32-bit wheel
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_BUILD: cp27-win32
DISTUTILS_USE_SDK: 1
MSSdk: 1
```
+1 -1
View File
@@ -33,4 +33,4 @@ Obviously, manual steps are for chumps, so we can automate this a little by usin
If you don't need much control over the release of a package, you can set up cibuildwheel to deliver the wheels straight to PyPI. This doesn't require anycloud storage to work - you just need to bump the version and tag it.
Check out [this example repo](https://github.com/joerick/cibuildwheel-autopypi-example) for instructions on how to set this up.
[`examples/travis-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/travis-deploy.yml) and [`examples/github-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/travis-deploy.yml) are example configurations that automatocially upload wheels to PyPI. Also check out [this example repo](https://github.com/joerick/cibuildwheel-autopypi-example) for more detailed instructions on how to set this up.
-1
View File
@@ -2,4 +2,3 @@
$('.rst-content pre')
.prev('blockquote')
.addClass('code-block-filename');
@@ -1,7 +1,6 @@
import cgi
import io
import os
import re
from pathlib import Path
import mkdocs
@@ -41,13 +40,12 @@ class ImportMarkdownPlugin(mkdocs.plugins.BasePlugin):
def found_include_tag(match):
filename = match.group('filename')
file_path_abs = os.path.join(os.path.dirname(page_src_path), filename)
file_path_abs = Path(page_src_path).parent / filename
if not os.path.exists(file_path_abs):
if not file_path_abs.exists():
raise ValueError('file not found', filename)
with io.open(file_path_abs, encoding='utf8') as f:
text_to_include = f.read()
text_to_include = file_path_abs.read_text(encoding='utf8')
# Allow good practice of having a final newline in the file
if text_to_include.endswith('\n'):
@@ -60,13 +58,12 @@ class ImportMarkdownPlugin(mkdocs.plugins.BasePlugin):
start = match.group('start')
end = match.group('end')
file_path_abs = os.path.join(os.path.dirname(page_src_path), filename)
file_path_abs = Path(page_src_path).parent / filename
if not os.path.exists(file_path_abs):
if not file_path_abs.exists():
raise ValueError('file not found', filename)
with io.open(file_path_abs, encoding='utf8') as f:
text_to_include = f.read()
text_to_include = file_path_abs.read_text(encoding='utf8')
if start:
_, _, text_to_include = text_to_include.partition(start)
+54 -30
View File
@@ -52,7 +52,6 @@ env:
## Build selection
### `CIBW_PLATFORM` {: #platform}
> Override the auto-detected target platform
@@ -67,6 +66,7 @@ For `linux` you need Docker running, on macOS or Linux. For `macos`, you need a
This option can also be set using the command-line option `--platform`.
### `CIBW_BUILD`, `CIBW_SKIP` {: #build-skip}
> Choose the Python versions to build
@@ -155,7 +155,6 @@ CIBW_SKIP: pp*
## Build customization
### `CIBW_ENVIRONMENT` {: #environment}
> Set environment variables needed during the build
@@ -191,6 +190,28 @@ CIBW_ENVIRONMENT: "BUILD_TIME=$(date) SAMPLE_TEXT=\"sample text\""
!!! note
`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).
### `CIBW_BEFORE_ALL` {: #before-all}
> Execute a shell command on the build system before any wheels are built.
Shell command to prepare a common part of the project (e.g. build or install libraries which does not depend on the specific version of Python).
This option is very useful for the Linux build, where builds take place in isolated Docker containers managed by cibuildwheel. This command will run inside the container before the wheel builds start. Note, if you're building both x86_64 and i686 wheels (the default), your build uses two different Docker images. In that case, this command will execute twice - once per build container.
The placeholder `{package}` can be used here; it will be replaced by the path to the package being built by `cibuildwheel`.
On Windows and macOS, the version of Python available inside `CIBW_BEFORE_ALL` is whatever is available on the host machine. On Linux, a modern Python version is available on PATH.
Platform-specific variants also available:<br/>
`CIBW_BEFORE_ALL_MACOS` | `CIBW_BEFORE_ALL_WINDOWS` | `CIBW_BEFORE_ALL_LINUX`
#### Examples
```yaml
# build third party library
CIBW_BEFORE_ALL: make -C third_party_lib
# install system library
CIBW_BEFORE_ALL_LINUX: yum install -y libffi-dev
```
### `CIBW_BEFORE_BUILD` {: #before-build}
> Execute a shell command preparing each wheel's build
@@ -296,6 +317,7 @@ CIBW_MANYLINUX_X86_64_IMAGE: dockcross/manylinux-x64
CIBW_MANYLINUX_I686_IMAGE: dockcross/manylinux-x86
```
### `CIBW_DEPENDENCY_VERSIONS` {: #dependency-versions}
> Specify how cibuildwheel controls the versions of the tools it uses
@@ -372,6 +394,35 @@ CIBW_TEST_COMMAND: pytest {package}/tests
```
### `CIBW_BEFORE_TEST` {: #before-test}
> Execute a shell command before testing each wheel
A shell command to run in **each** test virtual environment, before your wheel is installed and tested. This is useful if you need to install a non pip package, change values of environment variables
or perform multi step pip installation (e.g. installing `scikit-build` or `cython` before install test package)
The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. The placeholder `{package}` can be used here; it will be replaced by the path to the package being built by `cibuildwheel`.
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
Platform-specific variants also available:<br/>
`CIBW_BEFORE_TEST_MACOS` | `CIBW_BEFORE_TEST_WINDOWS` | `CIBW_BEFORE_TEST_LINUX`
#### Examples
```yaml
# install test dependencies with overwritten environment variables.
CIBW_BEFORE_TEST: CC=gcc CXX=g++ pip install -r requirements.txt
# chain commands using &&
CIBW_BEFORE_TEST: rm -rf ./data/cache && mkdir -p ./data/cache
# install non pip python package
CIBW_BEFORE_TEST: cd some_dir; ./configure; make; make install
# install python packages that are required to install test dependencies
CIBW_BEFORE_TEST: pip install cmake scikit-build
```
### `CIBW_TEST_REQUIRES` {: #test-requires}
> Install Python dependencies before running the tests
@@ -411,33 +462,6 @@ Platform-specific variants also available:<br/>
CIBW_TEST_EXTRAS: test,qt
```
### `CIBW_BEFORE_TEST` {: #before-test}
> Execute a shell command before testing each wheel
A shell command to run in **each** test virtual environment, before your wheel is installed and tested. This is useful if you need to install a non pip package, change values of environment variables
or perform multi step pip installation (e.g. installing `scikit-build` or `cython` before install test package)
The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. The placeholder `{package}` can be used here; it will be replaced by the path to the package being built by `cibuildwheel`.
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
Platform-specific variants also available:<br/>
`CIBW_BEFORE_TEST_MACOS` | `CIBW_BEFORE_TEST_WINDOWS` | `CIBW_BEFORE_TEST_LINUX`
#### Examples
```yaml
# install test dependencies with overwritten environment variables.
CIBW_BEFORE_TEST: CC=gcc CXX=g++ pip install -r requirements.txt
# chain commands using &&
CIBW_BEFORE_TEST: rm -rf ./data/cache && mkdir -p ./data/cache
# install non pip python package
CIBW_BEFORE_TEST: cd some_dir; ./configure; make; make install
# install python packages that are required to install test dependencies
CIBW_BEFORE_TEST: pip install cmake scikit-build
```
## Other
@@ -601,7 +625,7 @@ optional arguments:
var url = 'https://cibuildwheel.readthedocs.io/en/stable/options/#'+option.id;
var namesMarkdown = $.map(optionNames, function(n) {
return '[`'+n+'`]('+url+') '
}).join(' ')
}).join(' <br> ')
markdown += '| '+namesMarkdown+' '
markdown += '| '+option.description.trim()+' '
+4
View File
@@ -15,6 +15,8 @@ Commit this file, and push to Github - either to your default branch, or to a PR
For more info on this file, check out the [docs](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions).
[`examples/github-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/github-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
# Azure Pipelines [linux/mac/windows] {: #azure-pipelines}
To build Linux, Mac, and Windows wheels on Azure Pipelines, create a `azure-pipelines.yml` file in your repo.
@@ -46,6 +48,8 @@ Commit this file, enable building of your repo on Travis CI, and push.
Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](deliver-to-pypi.md). For more info on `.travis.yml`, check out the [docs](https://docs.travis-ci.com/).
[`examples/travis-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/travis-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
# CircleCI [linux/mac] {: #circleci}
To build Linux and Mac wheels on CircleCI, create a `.circleci/config.yml` file in your repo,
+1 -1
View File
@@ -12,7 +12,7 @@ stack: python 3.7
init:
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
install: python -m pip install cibuildwheel==1.4.2
install: python -m pip install cibuildwheel==1.5.0
build_script: python -m cibuildwheel --output-dir wheelhouse
+3 -3
View File
@@ -5,7 +5,7 @@ jobs:
- task: UsePythonVersion@0
- bash: |
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==1.4.2
pip3 install cibuildwheel==1.5.0
cibuildwheel --output-dir wheelhouse .
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
@@ -16,7 +16,7 @@ jobs:
- task: UsePythonVersion@0
- bash: |
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==1.4.2
pip3 install cibuildwheel==1.5.0
cibuildwheel --output-dir wheelhouse .
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
@@ -29,7 +29,7 @@ jobs:
displayName: Install Visual C++ for Python 2.7
- bash: |
python -m pip install --upgrade pip
pip install cibuildwheel==1.4.2
pip install cibuildwheel==1.5.0
cibuildwheel --output-dir wheelhouse .
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
+2 -2
View File
@@ -11,7 +11,7 @@ jobs:
- run:
name: Build the Linux wheels.
command: |
pip3 install --user cibuildwheel==1.4.2
pip3 install --user cibuildwheel==1.5.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
@@ -25,7 +25,7 @@ jobs:
- run:
name: Build the OS X wheels.
command: |
pip3 install --user cibuildwheel==1.4.2
pip3 install --user cibuildwheel==1.5.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
+81
View File
@@ -0,0 +1,81 @@
name: Build and upload to PyPI
# Build on every branch push, tag push, and pull request change:
on: [push, pull_request]
# Alternatively, to publish when a (published) GitHub Release is created, use the following:
# on:
# push:
# pull_request:
# release:
# types:
# - published
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
name: Install Python
with:
python-version: '3.7'
- name: Install cibuildwheel
run: |
python -m pip install cibuildwheel==1.5.0
- name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows'
run: |
choco install vcpython27 -f -y
- name: Build wheels
run: |
python -m cibuildwheel --output-dir wheelhouse
- uses: actions/upload-artifact@v2
with:
path: ./wheelhouse/*.whl
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
name: Install Python
with:
python-version: '3.7'
- name: Build sdist
run: python setup.py sdist
- uses: actions/upload-artifact@v2
with:
path: dist/*.tar.gz
upload_pypi:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
# upload to PyPI on every tag starting with 'v'
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
# alternatively, to publish when a GitHub Release is created, use the following rule:
# if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v2
with:
name: artifact
path: dist
- uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_password }}
# To test: repository_url: https://test.pypi.org/legacy/
+19 -20
View File
@@ -4,34 +4,33 @@ on: [push, pull_request]
jobs:
build_wheels:
name: Build wheel on ${{ matrix.os }}
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- uses: actions/setup-python@v1
name: Install Python
with:
python-version: '3.7'
- uses: actions/setup-python@v2
name: Install Python
with:
python-version: '3.7'
- name: Install cibuildwheel
run: |
python -m pip install cibuildwheel==1.4.2
- name: Install cibuildwheel
run: |
python -m pip install cibuildwheel==1.5.0
- name: Install Visual C++ for Python 2.7
if: startsWith(matrix.os, 'windows')
run: |
choco install vcpython27 -f -y
- name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows'
run: |
choco install vcpython27 -f -y
- name: Build wheel
run: |
python -m cibuildwheel --output-dir wheelhouse
- name: Build wheels
run: |
python -m cibuildwheel --output-dir wheelhouse
- uses: actions/upload-artifact@v1
with:
name: wheels
path: ./wheelhouse
- uses: actions/upload-artifact@v2
with:
path: ./wheelhouse/*.whl
@@ -25,7 +25,7 @@ env:
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
install:
- python3 -m pip install cibuildwheel==1.4.2
- python3 -m pip install cibuildwheel==1.5.0
script:
# build the wheels, put them into './wheelhouse'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
install:
- python3 -m pip install cibuildwheel==1.4.2
- python3 -m pip install cibuildwheel==1.5.0
script:
# build the wheels, put them into './wheelhouse'
+3 -3
View File
@@ -55,7 +55,7 @@ jobs:
- stage: deploy
name: Build and deploy Linux wheels
services: docker
install: python3 -m pip install cibuildwheel==1.4.2
install: python3 -m pip install cibuildwheel==1.5.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
@@ -65,7 +65,7 @@ jobs:
name: Build and deploy macOS wheels
os: osx
language: shell
install: python3 -m pip install cibuildwheel==1.4.2
install: python3 -m pip install cibuildwheel==1.5.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
@@ -75,7 +75,7 @@ jobs:
name: Build and deploy Windows wheels
os: windows
language: shell
install: python3 -m pip install cibuildwheel==1.4.2
install: python3 -m pip install cibuildwheel==1.5.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
+5 -7
View File
@@ -1,20 +1,18 @@
# -*- coding: utf-8 -*-
import io
import os
from pathlib import Path
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
this_directory = os.path.dirname(__file__)
with io.open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()
this_directory = Path(__file__).parent
long_description = (this_directory / 'README.md').read_text(encoding='utf-8')
setup(
name='cibuildwheel',
version='1.4.2',
install_requires=['bashlex!=0.13'],
version='1.5.0',
install_requires=['bashlex!=0.13', 'toml'],
description="Build Python wheels on CI with minimal configuration.",
long_description=long_description,
long_description_content_type='text/markdown',
+38
View File
@@ -0,0 +1,38 @@
import os
import textwrap
from . import utils
from . import test_projects
project_with_before_build_asserts = test_projects.new_c_project(
setup_py_add=textwrap.dedent(r'''
# assert that the Python version as written to text_info.txt in the CIBW_BEFORE_ALL step
# is the same one as is currently running.
with open("text_info.txt") as f:
stored_text = f.read()
print("## stored text: " + stored_text)
assert stored_text == "sample text 123"
''')
)
def test(tmp_path):
project_dir = tmp_path / 'project'
project_with_before_build_asserts.generate(project_dir)
with open(os.path.join(project_dir, "text_info.txt"), mode='w') as ff:
print("dummy text", file=ff)
# build the wheels
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
# write python version information to a temporary file, this is
# checked in setup.py
'CIBW_BEFORE_ALL': '''python -c "import os;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))"''',
'CIBW_ENVIRONMENT': "TEST_VAL='123'"
})
# also check that we got the right wheels
os.remove(os.path.join(project_dir, "text_info.txt"))
expected_wheels = utils.expected_wheels('spam', '0.1.0')
assert set(actual_wheels) == set(expected_wheels)
+2 -5
View File
@@ -1,4 +1,3 @@
import os
import re
import pytest
import textwrap
@@ -39,11 +38,9 @@ VERSION_REGEX = r'([\w-]+)==([^\s]+)'
def get_versions_from_constraint_file(constraint_file):
with open(constraint_file, encoding='utf8') as f:
constraint_file_text = f.read()
constraint_file_text = constraint_file.read_text(encoding='utf8')
versions = {}
for package, version in re.findall(VERSION_REGEX, constraint_file_text):
versions[package] = version
@@ -73,7 +70,7 @@ def test_pinned_versions(tmp_path, python_version):
constraint_filename = 'constraints.txt'
build_pattern = '[cp]p38-*'
constraint_file = os.path.join(cibuildwheel.util.resources_dir, constraint_filename)
constraint_file = cibuildwheel.util.resources_dir / constraint_filename
constraint_versions = get_versions_from_constraint_file(constraint_file)
for package in ['pip', 'setuptools', 'wheel', 'virtualenv']:
+44
View File
@@ -0,0 +1,44 @@
import textwrap
from . import test_projects
from . import utils
basic_project = test_projects.new_c_project(
setup_py_add=textwrap.dedent(
"""
# Will fail if PEP 518 does work
import requests
assert requests.__version__ == "2.23.0", "Requests found but wrong version ({0})".format(requests.__version__)
# Just making sure environment is still set
import os
if os.environ.get("CIBUILDWHEEL", "0") != "1":
raise Exception("CIBUILDWHEEL environment variable is not set to 1")
"""
)
)
basic_project.files[
"pyproject.toml"
] = """
[build-system]
requires = [
"setuptools>=42",
"wheel",
"requests==2.23.0"
]
build-backend = "setuptools.build_meta"
"""
def test_pep518(tmp_path):
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
# build the wheels
actual_wheels = utils.cibuildwheel_run(project_dir)
# check that the expected wheels are produced
expected_wheels = utils.expected_wheels("spam", "0.1.0")
assert set(actual_wheels) == set(expected_wheels)
+9 -5
View File
@@ -1,5 +1,7 @@
import os
from pathlib import Path
import jinja2
from typing import Union, Dict, Any
@@ -14,6 +16,8 @@ class TestProject:
Write out to the filesystem using `generate`.
'''
__test__ = False # Have pytest ignore this class on `from .test_projects import TestProject`
files: FilesDict
template_context: TemplateContext
@@ -21,12 +25,12 @@ class TestProject:
self.files = {}
self.template_context = {}
def generate(self, path: str):
def generate(self, path: Path):
for filename, content in self.files.items():
file_path = os.path.join(path, filename)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
file_path = path / filename
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, 'w', encoding='utf8') as f:
with file_path.open('w', encoding='utf8') as f:
if isinstance(content, jinja2.Template):
content = content.render(self.template_context)
+2 -2
View File
@@ -1,4 +1,4 @@
import os
from pathlib import Path
import jinja2
@@ -35,7 +35,7 @@ def test(capfd, tmp_path):
project_dir = tmp_path / 'project'
subdir_package_project.generate(project_dir)
package_dir = os.path.join(project_dir, 'src', 'spam')
package_dir = Path('src', 'spam')
# build the wheels
actual_wheels = utils.cibuildwheel_run(project_dir, package_dir=package_dir, add_env={
'CIBW_BEFORE_BUILD': 'python {project}/bin/before_build.py',
+8 -5
View File
@@ -46,12 +46,15 @@ class TestSpam(TestCase):
self.assertNotEqual(0, spam.system('python -c "exit(1)"'))
def test_virtualenv(self):
virtualenv_path = os.environ.get("__CIBW_VIRTUALENV_PATH__")
if not virtualenv_path:
self.fail("No virtualenv path defined in environment variable __CIBW_VIRTUALENV_PATH__")
# sys.prefix is different from sys.base_prefix when running a virtualenv
# See https://docs.python.org/3/library/venv.html, which virtualenv seems
# to honor in recent releases
# Python 2 doesn't have sys.base_prefix by default
if not hasattr(sys, 'base_prefix') or sys.prefix == sys.base_prefix:
self.fail("Not running in a virtualenv")
self.assertTrue(path_contains(virtualenv_path, sys.executable))
self.assertTrue(path_contains(virtualenv_path, spam.__file__))
self.assertTrue(path_contains(sys.prefix, sys.executable))
self.assertTrue(path_contains(sys.prefix, spam.__file__))
def test_uname(self):
if platform.system() == "Windows":
+3 -2
View File
@@ -10,9 +10,10 @@ import shutil
import subprocess
import sys
from contextlib import contextmanager
from pathlib import Path
from tempfile import mkdtemp
IS_WINDOWS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache')
IS_WINDOWS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
IS_WINDOWS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
@@ -66,7 +67,7 @@ def cibuildwheel_run(project_path, package_dir='.', env=None, add_env=None, outp
with TemporaryDirectoryIfNone(output_dir) as _output_dir:
subprocess.check_call(
[sys.executable, '-m', 'cibuildwheel', '--output-dir', str(_output_dir), package_dir],
[sys.executable, '-m', 'cibuildwheel', '--output-dir', str(_output_dir), str(package_dir)],
env=env,
cwd=project_path,
)
+9 -23
View File
@@ -1,30 +1,16 @@
from cibuildwheel.util import DependencyConstraints
import os
from pathlib import Path
def test_defaults():
dependency_constraints = DependencyConstraints.with_defaults()
project_root = os.path.dirname(os.path.dirname(__file__))
resources_dir = os.path.join(project_root, 'cibuildwheel', 'resources')
project_root = Path(__file__).parents[1]
resources_dir = project_root / 'cibuildwheel' / 'resources'
assert os.path.samefile(
dependency_constraints.base_file_path,
os.path.join(resources_dir, 'constraints.txt')
)
assert os.path.samefile(
dependency_constraints.get_for_python_version('3.8'),
os.path.join(resources_dir, 'constraints.txt')
)
assert os.path.samefile(
dependency_constraints.get_for_python_version('3.6'),
os.path.join(resources_dir, 'constraints-python36.txt')
)
assert os.path.samefile(
dependency_constraints.get_for_python_version('3.5'),
os.path.join(resources_dir, 'constraints-python35.txt')
)
assert os.path.samefile(
dependency_constraints.get_for_python_version('2.7'),
os.path.join(resources_dir, 'constraints-python27.txt')
)
assert dependency_constraints.base_file_path.samefile(resources_dir / 'constraints.txt')
assert dependency_constraints.get_for_python_version('3.8').samefile(resources_dir / 'constraints.txt')
assert dependency_constraints.get_for_python_version('3.6').samefile(resources_dir / 'constraints-python36.txt')
assert dependency_constraints.get_for_python_version('3.5').samefile(resources_dir / 'constraints-python35.txt')
assert dependency_constraints.get_for_python_version('2.7').samefile(resources_dir / 'constraints-python27.txt')
+13 -8
View File
@@ -1,6 +1,6 @@
import os
import subprocess
import sys
from pathlib import Path
import pytest
@@ -18,7 +18,7 @@ class ArgsInterceptor:
self.kwargs = kwargs
MOCK_PACKAGE_DIR = 'some_package_dir'
MOCK_PACKAGE_DIR = Path('some_package_dir')
@pytest.fixture(autouse=True)
@@ -31,28 +31,33 @@ def mock_protection(monkeypatch):
def fail_on_call(*args, **kwargs):
raise RuntimeError("This should never be called")
def ignore_call(*args, **kwargs):
pass
monkeypatch.setattr(subprocess, 'Popen', fail_on_call)
monkeypatch.setattr(util, 'download', fail_on_call)
monkeypatch.setattr(windows, 'build', fail_on_call)
monkeypatch.setattr(linux, 'build', fail_on_call)
monkeypatch.setattr(macos, 'build', fail_on_call)
monkeypatch.setattr(Path, 'mkdir', ignore_call)
@pytest.fixture(autouse=True)
def fake_package_dir(monkeypatch):
'''
Monkey-patch enough for the main() function to run
'''
real_os_path_exists = os.path.exists
real_path_exists = Path.exists
def mock_os_path_exists(path):
if path == os.path.join(MOCK_PACKAGE_DIR, 'setup.py'):
def mock_path_exists(path):
if path == MOCK_PACKAGE_DIR / 'setup.py':
return True
else:
return real_os_path_exists(path)
return real_path_exists(path)
monkeypatch.setattr(os.path, 'exists', mock_os_path_exists)
monkeypatch.setattr(sys, 'argv', ['cibuildwheel', MOCK_PACKAGE_DIR])
monkeypatch.setattr(Path, 'exists', mock_path_exists)
monkeypatch.setattr(sys, 'argv', ['cibuildwheel', str(MOCK_PACKAGE_DIR)])
@pytest.fixture(params=['linux', 'macos', 'windows'])
+24 -5
View File
@@ -1,5 +1,6 @@
import sys
from fnmatch import fnmatch
from pathlib import Path
import pytest
@@ -12,9 +13,9 @@ from cibuildwheel.util import BuildSelector
def test_output_dir(platform, intercepted_build_args, monkeypatch):
OUTPUT_DIR = 'some_output_dir'
OUTPUT_DIR = Path('some_output_dir')
monkeypatch.setenv('CIBW_OUTPUT_DIR', OUTPUT_DIR)
monkeypatch.setenv('CIBW_OUTPUT_DIR', str(OUTPUT_DIR))
main()
@@ -24,14 +25,14 @@ def test_output_dir(platform, intercepted_build_args, monkeypatch):
def test_output_dir_default(platform, intercepted_build_args, monkeypatch):
main()
assert intercepted_build_args.args[0].output_dir == 'wheelhouse'
assert intercepted_build_args.args[0].output_dir == Path('wheelhouse')
@pytest.mark.parametrize('also_set_environment', [False, True])
def test_output_dir_argument(also_set_environment, platform, intercepted_build_args, monkeypatch):
OUTPUT_DIR = 'some_output_dir'
OUTPUT_DIR = Path('some_output_dir')
monkeypatch.setattr(sys, 'argv', sys.argv + ['--output-dir', OUTPUT_DIR])
monkeypatch.setattr(sys, 'argv', sys.argv + ['--output-dir', str(OUTPUT_DIR)])
if also_set_environment:
monkeypatch.setenv('CIBW_OUTPUT_DIR', 'not_this_output_dir')
@@ -232,3 +233,21 @@ def test_build_selector_migrations(intercepted_build_args, monkeypatch, option_n
assert intercepted_build_selector.build_patterns == build_selector_patterns
else:
assert intercepted_build_selector.skip_patterns == build_selector_patterns
@pytest.mark.parametrize('before_all', ["", None, 'test text'])
@pytest.mark.parametrize('platform_specific', [False, True])
def test_before_all(before_all, platform_specific, platform, intercepted_build_args, monkeypatch):
if before_all is not None:
if platform_specific:
monkeypatch.setenv('CIBW_BEFORE_ALL_' + platform.upper(), before_all)
monkeypatch.setenv('CIBW_BEFORE_ALL', 'overwritten')
else:
monkeypatch.setenv('CIBW_BEFORE_ALL', before_all)
main()
if before_all is None:
before_all = ""
assert intercepted_build_args.args[0].before_all == before_all