Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed8a9533c5 | ||
|
|
e439544a1d | ||
|
|
4d0db00d79 | ||
|
|
b4fe1aa257 | ||
|
|
194818ecf7 | ||
|
|
fb2c6e2e89 | ||
|
|
8dff764b23 | ||
|
|
b020f9d3e5 | ||
|
|
095c094420 | ||
|
|
d83daa3958 | ||
|
|
4f4dae27fb | ||
|
|
c76ee0b39b | ||
|
|
c217d5963d | ||
|
|
84a4b0518f | ||
|
|
dbb65f94bd | ||
|
|
2e165c3e7a | ||
|
|
4ac5feb6bb | ||
|
|
6974680571 | ||
|
|
5dd2f56eab | ||
|
|
78b6f86305 | ||
|
|
677e51d137 | ||
|
|
f9a5ec84d9 | ||
|
|
044a5dab37 | ||
|
|
00a217d4a6 | ||
|
|
318e768292 | ||
|
|
9bfd0f7956 | ||
|
|
eae34832ec | ||
|
|
3ac943b754 | ||
|
|
b3bb527584 | ||
|
|
c166426b50 | ||
|
|
bf011b51f9 | ||
|
|
abbe91cf86 | ||
|
|
d1ba5b8419 | ||
|
|
64a093756c | ||
|
|
49077c2a36 | ||
|
|
e94274db07 | ||
|
|
3c77465100 | ||
|
|
0f459d378c | ||
|
|
0fb2ead6fb | ||
|
|
dcf703c67e | ||
|
|
edbbdb6861 | ||
|
|
54877b96e3 | ||
|
|
e0f2f8fdac | ||
|
|
c065e3ce2d | ||
|
|
27bda4fa64 | ||
|
|
5665b61cbf | ||
|
|
4c035a441b | ||
|
|
ba01ec546e | ||
|
|
b9cf466cd8 | ||
|
|
6413732187 | ||
|
|
10c244d827 | ||
|
|
bfd9bb482b | ||
|
|
c2a7cdf98a | ||
|
|
f8a4fbe42d | ||
|
|
95fecc2d58 | ||
|
|
ece358f29d | ||
|
|
6f3fcf8b12 | ||
|
|
c67de74e28 | ||
|
|
2f4ed1fafc | ||
|
|
05d7c142e9 | ||
|
|
e84c6b2de0 | ||
|
|
a93cee1a30 | ||
|
|
d3f57bbb22 | ||
|
|
a50be4d820 | ||
|
|
b8a41130c3 | ||
|
|
9d731cd440 | ||
|
|
309222cca3 | ||
|
|
fe6eadc1f2 | ||
|
|
91906b2aea | ||
|
|
0760c330cf | ||
|
|
d054b45ecf | ||
|
|
8606c4771e | ||
|
|
4c94e7ef20 | ||
|
|
c56448eba7 | ||
|
|
ebe632eff0 | ||
|
|
a732525084 | ||
|
|
e8aef6962a | ||
|
|
fba3248163 | ||
|
|
113350b7fb | ||
|
|
54858bbd64 | ||
|
|
0227b9d941 | ||
|
|
df71e028a9 | ||
|
|
8e2381bfb1 | ||
|
|
3d59c56584 | ||
|
|
57d38efd4d | ||
|
|
1f830a3626 | ||
|
|
1ab1130fe1 | ||
|
|
931f8e106e | ||
|
|
8b8d6d749c | ||
|
|
38297e6663 | ||
|
|
246aa0848e | ||
|
|
7914432a68 | ||
|
|
5e99d962f5 | ||
|
|
df04fa5ac3 | ||
|
|
8e38132000 | ||
|
|
8108deacfe | ||
|
|
c9ea0251fe | ||
|
|
fbbc295901 | ||
|
|
888da8274c | ||
|
|
06b6823637 | ||
|
|
2f9ee793f0 | ||
|
|
75c6e6a0a4 | ||
|
|
c5bbfb3cc6 | ||
|
|
53ee55bad7 | ||
|
|
225342c777 | ||
|
|
8808add708 | ||
|
|
fa4a0cbd33 | ||
|
|
4a736cdcb1 | ||
|
|
4b402e0593 | ||
|
|
4eff3bc7a8 | ||
|
|
0a32e3bc0e | ||
|
|
b22001b26d | ||
|
|
39b94b7dec | ||
|
|
152483bcb4 | ||
|
|
f51c8dc1e3 | ||
|
|
45c723cdea | ||
|
|
dac4006083 | ||
|
|
f48a84d92f | ||
|
|
38e7b5a91d | ||
|
|
beda0e5ce8 | ||
|
|
957a4fb8e1 | ||
|
|
7e4b44b6ee | ||
|
|
a494f9bbe5 | ||
|
|
946306b21d | ||
|
|
0191496fc9 | ||
|
|
4ec28cb37e | ||
|
|
136adebf09 | ||
|
|
461aa35f99 | ||
|
|
d12e54af41 | ||
|
|
336c80b694 | ||
|
|
7dcd6826a4 | ||
|
|
c89b74604d | ||
|
|
3e7a665b11 | ||
|
|
734377b5f5 |
@@ -3,7 +3,7 @@ version: 2
|
||||
jobs:
|
||||
osx-python3.6:
|
||||
macos:
|
||||
xcode: 10.2.1
|
||||
xcode: 9.4.1
|
||||
environment:
|
||||
PYTHON: python3
|
||||
steps:
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push: {}
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
workflow_dispatch:
|
||||
# allow manual runs on branches without a PR
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
@@ -16,9 +20,6 @@ jobs:
|
||||
- uses: pre-commit/action@v2.0.0
|
||||
|
||||
test:
|
||||
# skip branch builds on joerick/cibuildwheel, but always build `master` and pull requests
|
||||
if: github.repository != 'joerick/cibuildwheel' || github.ref == 'refs/heads/master' || github.event_name == 'pull_request'
|
||||
|
||||
name: Test cibuildwheel on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -36,10 +37,21 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -r requirements-dev.txt
|
||||
|
||||
- name: Install Visual C++ for Python 2.7
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
choco install vcpython27 -f -y
|
||||
|
||||
- name: Get PR labels
|
||||
id: pr-labels
|
||||
uses: joerick/pr-labels-action@v1.0.6
|
||||
|
||||
- name: Sample build
|
||||
if: contains(steps.pr-labels.outputs.labels, ' ci-sample-build ')
|
||||
run: |
|
||||
python bin/sample_build.py
|
||||
|
||||
- name: Test cibuildwheel
|
||||
run: |
|
||||
python ./bin/run_tests.py
|
||||
|
||||
@@ -13,7 +13,7 @@ repos:
|
||||
- id: check-merge-conflict
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
exclude: cibuildwheel/resources/pinned_docker_images.cfg
|
||||
exclude: (cibuildwheel/resources/pinned_docker_images.cfg)|(.svg$)
|
||||
- id: mixed-line-ending
|
||||
- id: trailing-whitespace
|
||||
|
||||
@@ -21,5 +21,5 @@ repos:
|
||||
rev: v0.782
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: cibuildwheel/|test/
|
||||
files: ^(cibuildwheel/|test/|bin/projects.py)
|
||||
pass_filenames: false
|
||||
|
||||
@@ -28,7 +28,6 @@ jobs:
|
||||
|
||||
- name: macOS | x86_64 | Python 3.x
|
||||
os: osx
|
||||
osx_image: xcode10.2
|
||||
env:
|
||||
- PYTHON=python3
|
||||
- PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
|
||||
|
||||
@@ -9,7 +9,7 @@ cibuildwheel
|
||||
|
||||
Python wheels are great. Building them across **Mac, Linux, Windows**, on **multiple versions of Python**, is not.
|
||||
|
||||
`cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports Azure Pipelines, Travis CI, AppVeyor, GitHub Actions and CircleCI - and it builds and tests your wheels across all of your platforms.
|
||||
`cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, and CircleCI - and it builds and tests your wheels across all of your platforms.
|
||||
|
||||
|
||||
What does it do?
|
||||
@@ -23,9 +23,9 @@ What does it do?
|
||||
| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| PyPy 2.7 v7.3.2 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.6 v7.3.2 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.7 (alpha) v7.3.2 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 2.7 v7.3.3 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.6 v7.3.3 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.7 (beta) v7.3.3 | ✅ | | ✅ | ✅ | | | | |
|
||||
|
||||
<sup>¹ Not supported on Travis</sup><br>
|
||||
<sup>² Only supported on Travis</sup><br>
|
||||
@@ -40,14 +40,16 @@ Usage
|
||||
|
||||
`cibuildwheel` currently works on **Travis CI**, **Azure Pipelines**, **AppVeyor**, **GitHub Actions**, **CircleCI**, and **Gitlab CI**. Check the table below for supported platforms on each service:
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
|-----------------|-------|-------|---------|
|
||||
| Azure Pipelines | ✅ | ✅ | ✅ |
|
||||
| Travis CI | ✅ | ✅ | ✅ |
|
||||
| AppVeyor | ✅ | ✅ | ✅ |
|
||||
| GitHub Actions | ✅ | ✅ | ✅ |
|
||||
| CircleCI | ✅ | ✅ | |
|
||||
| Gitlab CI | ✅ | | |
|
||||
| | Linux | macOS | Windows | Linux ARM |
|
||||
|-----------------|-------|-------|---------|--------------|
|
||||
| Azure Pipelines | ✅ | ✅ | ✅ | ✴️¹ |
|
||||
| Travis CI | ✅ | ✅ | ✅ | ✅ |
|
||||
| AppVeyor | ✅ | ✅ | ✅ | |
|
||||
| GitHub Actions | ✅ | ✅ | ✅ | ✴️¹ |
|
||||
| CircleCI | ✅ | ✅ | | |
|
||||
| Gitlab CI | ✅ | | | |
|
||||
|
||||
<sup>¹ Requires a "third-party build host"; expected to work with cibuildwheel but not directly tested by our CI.</sup><br>
|
||||
|
||||
`cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like those mentioned above are ideal.
|
||||
|
||||
@@ -56,51 +58,41 @@ Usage
|
||||
Example setup
|
||||
-------------
|
||||
|
||||
To build manylinux, macOS, and Windows wheels on Travis CI and upload them to PyPI whenever you tag a version, you could use this `.travis.yml`:
|
||||
To build manylinux, macOS, and Windows wheels on Github Actions, you could use this `.github/workflows/wheels.yml`:
|
||||
|
||||
```yaml
|
||||
language: python
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# perform a linux build
|
||||
- services: docker
|
||||
# and a mac build
|
||||
- os: osx
|
||||
# PyPy 7.3.2 needs macOS >= 10.14
|
||||
osx_image: xcode10.2
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python --version 3.8.0
|
||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
# make sure it's on PATH as 'python3'
|
||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
||||
build_wheels:
|
||||
name: Build wheels on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, windows-2019, macOS-10.15]
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=__token__
|
||||
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.6.3
|
||||
- uses: actions/setup-python@v2
|
||||
name: Install Python
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
- python3 -m cibuildwheel --output-dir wheelhouse
|
||||
- name: Install cibuildwheel
|
||||
run: python -m pip install cibuildwheel==1.7.2
|
||||
|
||||
after_success:
|
||||
# if the release was tagged, upload them to PyPI
|
||||
- |
|
||||
if [[ $TRAVIS_TAG ]]; then
|
||||
python3 -m pip install twine
|
||||
python3 -m twine upload wheelhouse/*.whl
|
||||
fi
|
||||
- name: Build wheels
|
||||
run: python -m cibuildwheel --output-dir wheelhouse
|
||||
env:
|
||||
CIBW_SKIP: "cp27-* pp27-*" # skip Python 2.7 wheels
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: ./wheelhouse/*.whl
|
||||
```
|
||||
|
||||
For more information, including how to build on GitHub Actions, Appveyor, Azure Pipelines, or CircleCI, check out the [documentation](https://cibuildwheel.readthedocs.org) and the [examples](https://github.com/joerick/cibuildwheel/tree/master/examples).
|
||||
For more information, including building on Python 2, PyPI deployment, and the use of other CI services like Travis CI, Appveyor, Azure Pipelines, or CircleCI, check out the [documentation](https://cibuildwheel.readthedocs.org) and the [examples](https://github.com/joerick/cibuildwheel/tree/master/examples).
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -125,31 +117,136 @@ Options
|
||||
Working examples
|
||||
----------------
|
||||
|
||||
<!--working-examples-start-->
|
||||
|
||||
Here are some repos that use cibuildwheel.
|
||||
|
||||
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext) - A simple C extension, without external dependencies, built on Travis CI/Appveyor.
|
||||
- [websockets](https://github.com/aaugustin/websockets)
|
||||
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth)
|
||||
- [python-admesh](https://github.com/admesh/python-admesh)
|
||||
- [pybase64](https://github.com/mayeut/pybase64)
|
||||
- [KDEpy](https://github.com/tommyod/KDEpy)
|
||||
- [AutoPy](https://github.com/autopilot-rs/autopy)
|
||||
- [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz)
|
||||
- [TgCrypto](https://github.com/pyrogram/tgcrypto)
|
||||
- [Twisted](https://github.com/twisted/twisted)
|
||||
- [gmic-py](https://github.com/dtschump/gmic-py)
|
||||
- [creme](https://github.com/creme-ml/creme)
|
||||
- [PyAV](https://github.com/PyAV-Org/PyAV)
|
||||
- [aiortc](https://github.com/aiortc/aiortc)
|
||||
- [aioquic](https://github.com/aiortc/aioquic)
|
||||
- [pikepdf](https://github.com/pikepdf/pikepdf)
|
||||
- [fathon](https://github.com/stfbnc/fathon)
|
||||
- [etebase-py](https://github.com/etesync/etebase-py) - Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed, built on Travis CI.
|
||||
<!-- START bin/projects.py -->
|
||||
|
||||
> Add your repo here! Send a PR.
|
||||
<!-- this section is generated by bin/projects.py. Don't edit it directly, instead, edit docs/data/projects.yml -->
|
||||
|
||||
| Name | CI | OS | Notes |
|
||||
|-----------------------------------|----|----|:------|
|
||||
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
||||
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
||||
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
|
||||
| [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. |
|
||||
| [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. |
|
||||
| [pyzmq][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython and CFFI. |
|
||||
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
|
||||
| [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. |
|
||||
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
|
||||
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
|
||||
| [PyAV][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Pythonic bindings for FFmpeg's libraries. |
|
||||
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
|
||||
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
|
||||
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
||||
| [pikepdf][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by qpdf |
|
||||
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
|
||||
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] ![appveyor icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
|
||||
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
|
||||
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
|
||||
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
|
||||
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
|
||||
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
|
||||
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
|
||||
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
|
||||
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
|
||||
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
||||
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
|
||||
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
|
||||
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
|
||||
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
|
||||
| [pyinstrument_cext][] | ![travisci icon][] ![appveyor icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A simple C extension, without external dependencies |
|
||||
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
|
||||
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
|
||||
|
||||
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
||||
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
||||
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
|
||||
[scikit-image]: https://github.com/scikit-image/scikit-image
|
||||
[websockets]: https://github.com/aaugustin/websockets
|
||||
[pyzmq]: https://github.com/zeromq/pyzmq
|
||||
[aiortc]: https://github.com/aiortc/aiortc
|
||||
[h5py]: https://github.com/h5py/h5py
|
||||
[coverage.py]: https://github.com/nedbat/coveragepy
|
||||
[River]: https://github.com/online-ml/river
|
||||
[PyAV]: https://github.com/PyAV-Org/PyAV
|
||||
[google neuroglancer]: https://github.com/google/neuroglancer
|
||||
[aioquic]: https://github.com/aiortc/aioquic
|
||||
[AutoPy]: https://github.com/autopilot-rs/autopy
|
||||
[pikepdf]: https://github.com/pikepdf/pikepdf
|
||||
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
|
||||
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
|
||||
[KDEpy]: https://github.com/tommyod/KDEpy
|
||||
[pybind11 python_example]: https://github.com/pybind/python_example
|
||||
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
|
||||
[iminuit]: https://github.com/scikit-hep/iminuit
|
||||
[jq.py]: https://github.com/mwilliamson/jq.py
|
||||
[bx-python]: https://github.com/bxlab/bx-python
|
||||
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
|
||||
[pybase64]: https://github.com/mayeut/pybase64
|
||||
[TgCrypto]: https://github.com/pyrogram/tgcrypto
|
||||
[etebase-py]: https://github.com/etesync/etebase-py
|
||||
[pyjet]: https://github.com/scikit-hep/pyjet
|
||||
[numpythia]: https://github.com/scikit-hep/numpythia
|
||||
[fathon]: https://github.com/stfbnc/fathon
|
||||
[pyinstrument_cext]: https://github.com/joerick/pyinstrument_cext
|
||||
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
|
||||
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
|
||||
|
||||
[appveyor icon]: docs/data/readme_icons/appveyor.svg
|
||||
[github icon]: docs/data/readme_icons/github.svg
|
||||
[azurepipelines icon]: docs/data/readme_icons/azurepipelines.svg
|
||||
[circleci icon]: docs/data/readme_icons/circleci.svg
|
||||
[gitlab icon]: docs/data/readme_icons/gitlab.svg
|
||||
[travisci icon]: docs/data/readme_icons/travisci.svg
|
||||
[windows icon]: docs/data/readme_icons/windows.svg
|
||||
[apple icon]: docs/data/readme_icons/apple.svg
|
||||
[linux icon]: docs/data/readme_icons/linux.svg
|
||||
|
||||
<!-- scikit-learn: 43359, last pushed 0 days ago -->
|
||||
<!-- Matplotlib: 12734, last pushed 0 days ago -->
|
||||
<!-- twisted-iocpsupport: 4107, last pushed 0 days ago -->
|
||||
<!-- scikit-image: 4085, last pushed 0 days ago -->
|
||||
<!-- websockets: 3065, last pushed 0 days ago -->
|
||||
<!-- pyzmq: 2655, last pushed 9 days ago -->
|
||||
<!-- aiortc: 2058, last pushed 10 days ago -->
|
||||
<!-- h5py: 1451, last pushed 1 days ago -->
|
||||
<!-- coverage.py: 1429, last pushed 3 days ago -->
|
||||
<!-- River: 1174, last pushed 0 days ago -->
|
||||
<!-- PyAV: 1107, last pushed 2 days ago -->
|
||||
<!-- google neuroglancer: 545, last pushed 2 days ago -->
|
||||
<!-- aioquic: 543, last pushed 38 days ago -->
|
||||
<!-- AutoPy: 503, last pushed 94 days ago -->
|
||||
<!-- pikepdf: 477, last pushed 3 days ago -->
|
||||
<!-- Parselmouth: 429, last pushed 15 days ago -->
|
||||
<!-- python-rapidjson: 406, last pushed 2 days ago -->
|
||||
<!-- KDEpy: 224, last pushed 12 days ago -->
|
||||
<!-- pybind11 python_example: 219, last pushed 32 days ago -->
|
||||
<!-- pybind11 cmake_example: 217, last pushed 16 days ago -->
|
||||
<!-- iminuit: 164, last pushed 3 days ago -->
|
||||
<!-- jq.py: 137, last pushed 62 days ago -->
|
||||
<!-- bx-python: 95, last pushed 75 days ago -->
|
||||
<!-- boost-histogram: 60, last pushed 0 days ago -->
|
||||
<!-- pybase64: 52, last pushed 2 days ago -->
|
||||
<!-- TgCrypto: 48, last pushed 24 days ago -->
|
||||
<!-- etebase-py: 39, last pushed 0 days ago -->
|
||||
<!-- pyjet: 27, last pushed 17 days ago -->
|
||||
<!-- numpythia: 23, last pushed 16 days ago -->
|
||||
<!-- fathon: 17, last pushed 49 days ago -->
|
||||
<!-- pyinstrument_cext: 9, last pushed 17 days ago -->
|
||||
<!-- xmlstarlet: 7, last pushed 5 days ago -->
|
||||
<!-- pybind11 scikit_build_example: 1, last pushed 30 days ago -->
|
||||
|
||||
<!-- END bin/projects.py -->
|
||||
|
||||
> Add your repo here! Send a PR, adding your information to `docs/data/projects.yml`.
|
||||
>
|
||||
> <sup>I'd like to include notes here to indicate why an example might be interesting to cibuildwheel users - the styles/technologies/techniques used in each. Please include that in future additions!</sup>
|
||||
|
||||
<!--working-examples-end-->
|
||||
|
||||
Legal note
|
||||
----------
|
||||
|
||||
@@ -162,6 +259,42 @@ This is similar to static linking, so it might have some licence implications. C
|
||||
Changelog
|
||||
=========
|
||||
|
||||
<!--changelog-start-->
|
||||
|
||||
### 1.7.2
|
||||
|
||||
_21 December 2020_
|
||||
|
||||
- 🛠 Update dependencies, notably wheel==0.36.2 and pip==20.3.3, and CPython to
|
||||
their latest bugfix releases (#489)
|
||||
- 📚 Switch to a Github example in the README (#479)
|
||||
- 📚 Create Working Examples table, with many projects that use cibuildwheel (#474)
|
||||
- 📚 Import Working Examples table and Changelog to docs
|
||||
|
||||
### 1.7.1
|
||||
|
||||
_3 December 2020_
|
||||
|
||||
- 🛠 Update manylinux2010 image to resolve issues with 'yum' repositories
|
||||
(#472)
|
||||
|
||||
### 1.7.0
|
||||
|
||||
_26 November 2020_
|
||||
|
||||
- ✨ New logging format, that uses 'fold groups' in CI services that support
|
||||
it. (#458)
|
||||
- 🛠 Update PyPy to 7.3.3 (#460)
|
||||
- 🐛 Fix a bug where CIBW_BEFORE_ALL runs with a very old version of Python on
|
||||
Linux. (#464)
|
||||
|
||||
### 1.6.4
|
||||
|
||||
_31 October 2020_
|
||||
|
||||
- 🐛 Fix crash on Appveyor during nuget install due to old system CA
|
||||
certificates. We now use certifi's CA certs to download files. (#455)
|
||||
|
||||
### 1.6.3
|
||||
|
||||
_12 October 2020_
|
||||
@@ -545,6 +678,8 @@ _31 March 2017_
|
||||
|
||||
- 🌟 First public release!
|
||||
|
||||
<!--changelog-end-->
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
@@ -578,4 +713,4 @@ See also
|
||||
|
||||
If you'd like to keep wheel building separate from the package itself, check out [astrofrog/autowheel](https://github.com/astrofrog/autowheel). It builds packages using cibuildwheel from source distributions on PyPI.
|
||||
|
||||
If `cibuildwheel` is too limited for your needs, consider [matthew-brett/multibuild](http://github.com/matthew-brett/multibuild). `multibuild` is a toolbox for building a wheel on various platforms. It can do a lot more than this project - it's used to build SciPy!
|
||||
Another very similar tool to consider is [matthew-brett/multibuild](http://github.com/matthew-brett/multibuild). `multibuild` is a shell script toolbox for building a wheel on various platforms. It is used as a basis to build some of the big data science tools, like SciPy.
|
||||
|
||||
@@ -20,6 +20,25 @@ config = [
|
||||
|
||||
@click.command()
|
||||
def bump_version():
|
||||
current_version = cibuildwheel.__version__
|
||||
|
||||
try:
|
||||
commit_date_str = subprocess.run([
|
||||
'git',
|
||||
'show', '-s', '--pretty=format:%ci',
|
||||
f'v{current_version}^{{commit}}'
|
||||
], check=True, capture_output=True, encoding='utf8').stdout
|
||||
commit_date_parts = commit_date_str.split(' ')
|
||||
|
||||
url = 'https://github.com/joerick/cibuildwheel/pulls?' + urllib.parse.urlencode({
|
||||
'q': f'is:pr merged:>{commit_date_parts[0]}T{commit_date_parts[1]}{commit_date_parts[2]}',
|
||||
})
|
||||
print(f'PRs merged since last release:\n {url}')
|
||||
print()
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(e)
|
||||
print('Failed to get previous version tag information.')
|
||||
|
||||
git_changes_result = subprocess.run(['git diff-index --quiet HEAD --'], shell=True)
|
||||
repo_has_uncommitted_changes = git_changes_result.returncode != 0
|
||||
|
||||
@@ -27,7 +46,6 @@ def bump_version():
|
||||
print('error: Uncommitted changes detected.')
|
||||
exit(1)
|
||||
|
||||
current_version = cibuildwheel.__version__
|
||||
print( 'Current version:', current_version) # noqa
|
||||
new_version = input(' New version: ').strip()
|
||||
|
||||
@@ -90,23 +108,6 @@ def bump_version():
|
||||
print('commit, do that now.')
|
||||
print()
|
||||
|
||||
try:
|
||||
commit_date_str = subprocess.run([
|
||||
'git',
|
||||
'show', '-s', '--pretty=format:%ci',
|
||||
f'v{current_version}^{{commit}}'
|
||||
], check=True, capture_output=True, encoding='utf8').stdout
|
||||
commit_date_parts = commit_date_str.split(' ')
|
||||
|
||||
url = 'https://github.com/joerick/cibuildwheel/pulls?' + urllib.parse.urlencode({
|
||||
'q': f'is:pr merged:>{commit_date_parts[0]}T{commit_date_parts[1]}{commit_date_parts[2]}',
|
||||
})
|
||||
print(f'PRs merged since last release:\n {url}')
|
||||
print()
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(e)
|
||||
print('Failed to get previous version tag information.')
|
||||
|
||||
while input('Type "done" to continue: ').strip().lower() != 'done':
|
||||
pass
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Convert a yaml project list into a nice table.
|
||||
|
||||
Suggested usage:
|
||||
|
||||
./bin/projects.py docs/data/projects.yml --online --auth $GITHUB_API_TOKEN --readme README.md
|
||||
git diff
|
||||
"""
|
||||
|
||||
import builtins
|
||||
import functools
|
||||
from datetime import datetime
|
||||
from io import StringIO
|
||||
from typing import Dict, Any, List, Optional, TextIO
|
||||
|
||||
import click
|
||||
import yaml
|
||||
from github import Github
|
||||
import urllib.request
|
||||
import xml.dom.minidom
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ICONS = (
|
||||
"appveyor",
|
||||
"github",
|
||||
"azurepipelines",
|
||||
"circleci",
|
||||
"gitlab",
|
||||
"travisci",
|
||||
"windows",
|
||||
"apple",
|
||||
"linux",
|
||||
)
|
||||
|
||||
|
||||
class Project:
|
||||
NAME: int = 0
|
||||
|
||||
def __init__(self, config: Dict[str, Any], github: Optional[Github] = None):
|
||||
try:
|
||||
self.name: str = config["name"]
|
||||
self.gh: str = config["gh"]
|
||||
except KeyError:
|
||||
print("Invalid config, needs at least gh and name!", config)
|
||||
raise
|
||||
|
||||
self.stars_repo: str = config.get("stars", self.gh)
|
||||
self.notes: str = config.get("notes", "")
|
||||
self.ci: List[str] = config.get("ci", [])
|
||||
self.os: List[str] = config.get("os", [])
|
||||
|
||||
self.online = github is not None
|
||||
if github is not None:
|
||||
repo = github.get_repo(self.stars_repo)
|
||||
self.num_stars = repo.stargazers_count
|
||||
self.pushed_at = repo.pushed_at
|
||||
if not self.notes:
|
||||
notes = repo.description
|
||||
if repo.description:
|
||||
self.notes = notes
|
||||
else:
|
||||
self.num_stars = 0
|
||||
self.pushed_at = datetime.utcnow()
|
||||
|
||||
name_len = len(self.name) + 4
|
||||
self.__class__.NAME = max(self.__class__.NAME, name_len)
|
||||
|
||||
def __lt__(self, other: "Project") -> bool:
|
||||
if self.online:
|
||||
return self.num_stars < other.num_stars
|
||||
else:
|
||||
return self.name < other.name
|
||||
|
||||
@classmethod
|
||||
def header(cls) -> str:
|
||||
return (
|
||||
f"| {'Name':{cls.NAME}} | CI | OS | Notes |\n"
|
||||
f"|{'':-^{cls.NAME+2 }}|----|----|:------|"
|
||||
)
|
||||
|
||||
@property
|
||||
def namelink(self) -> str:
|
||||
return f"[{self.name}][]"
|
||||
|
||||
@property
|
||||
def starslink(self) -> str:
|
||||
return f"![{self.name} stars][]"
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return f"https://github.com/{self.gh}"
|
||||
|
||||
@property
|
||||
def ci_icons(self) -> str:
|
||||
return " ".join(f"![{icon} icon][]" for icon in self.ci)
|
||||
|
||||
@property
|
||||
def os_icons(self) -> str:
|
||||
return " ".join(f"![{icon} icon][]" for icon in self.os)
|
||||
|
||||
def table_row(self) -> str:
|
||||
notes = self.notes.replace('\n', ' ')
|
||||
return f"| {self.namelink: <{self.NAME}} | {self.ci_icons} | {self.os_icons} | {notes} |"
|
||||
|
||||
def links(self) -> str:
|
||||
return f"[{self.name}]: {self.url}"
|
||||
|
||||
def info(self) -> str:
|
||||
days = (datetime.utcnow() - self.pushed_at).days
|
||||
return f"<!-- {self.name}: {self.num_stars}, last pushed {days} days ago -->"
|
||||
|
||||
|
||||
def fetch_icon(icon_name: str) -> None:
|
||||
url = f'https://cdn.jsdelivr.net/npm/simple-icons@v4/icons/{icon_name}.svg'
|
||||
with urllib.request.urlopen(url) as f:
|
||||
original_svg_data = f.read()
|
||||
|
||||
document = xml.dom.minidom.parseString(original_svg_data)
|
||||
svgElement = document.documentElement
|
||||
assert svgElement.nodeName == 'svg'
|
||||
svgElement.setAttribute('width', '16px')
|
||||
svgElement.setAttribute('fill', '#606060')
|
||||
|
||||
icon_path = path_for_icon(icon_name)
|
||||
icon_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(path_for_icon(icon_name), 'w') as f:
|
||||
f.write(svgElement.toxml())
|
||||
|
||||
|
||||
def path_for_icon(icon_name: str) -> Path:
|
||||
return Path('.') / 'docs' / 'data' / 'readme_icons' / f'{icon_name}.svg'
|
||||
|
||||
|
||||
def str_projects(
|
||||
config: List[Dict[str, Any]], *, online: bool = True, auth: Optional[str] = None
|
||||
) -> str:
|
||||
io = StringIO()
|
||||
print = functools.partial(builtins.print, file=io)
|
||||
|
||||
if online:
|
||||
for icon in ICONS:
|
||||
fetch_icon(icon)
|
||||
|
||||
github = Github(auth) if online else None
|
||||
|
||||
projects = sorted((Project(item, github) for item in config), reverse=online)
|
||||
|
||||
print(Project.header())
|
||||
for project in projects:
|
||||
print(project.table_row())
|
||||
|
||||
print()
|
||||
for project in projects:
|
||||
print(project.links())
|
||||
|
||||
print()
|
||||
for icon in ICONS:
|
||||
print(f"[{icon} icon]: {path_for_icon(icon).as_posix()}")
|
||||
|
||||
print()
|
||||
for project in projects:
|
||||
print(project.info())
|
||||
|
||||
return io.getvalue()
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("input", type=click.File("r"))
|
||||
@click.option("--online/--no-online", default=True, help="Get info from GitHub")
|
||||
@click.option("--auth", help="GitHub authentication token")
|
||||
@click.option("--readme", type=click.File("r+"), help="Modify a readme file if given")
|
||||
def projects(
|
||||
input: TextIO, online: bool, auth: Optional[str], readme: Optional[TextIO]
|
||||
) -> None:
|
||||
config = yaml.safe_load(input)
|
||||
output = str_projects(config, online=online, auth=auth)
|
||||
|
||||
if readme is None:
|
||||
print(output)
|
||||
else:
|
||||
text = readme.read()
|
||||
start_str = "<!-- START bin/projects.py -->\n"
|
||||
start = text.find(start_str)
|
||||
end = text.find("<!-- END bin/projects.py -->\n")
|
||||
generated_note = f'<!-- this section is generated by bin/projects.py. Don\'t edit it directly, instead, edit {input.name} -->'
|
||||
new_text = f"{text[:start + len(start_str)]}\n{generated_note}\n\n{output}\n{text[end:]}"
|
||||
|
||||
readme.seek(0)
|
||||
readme.write(new_text)
|
||||
readme.truncate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
projects()
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import argparse
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
if __name__ == '__main__':
|
||||
# move cwd to the project root
|
||||
os.chdir(Path(__file__).resolve().parents[1])
|
||||
|
||||
parser = argparse.ArgumentParser(description='Runs a sample build')
|
||||
parser.add_argument('project_python_path', nargs='?', default='test.test_0_basic.basic_project')
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
project_dir = tempfile.mkdtemp()
|
||||
subprocess.run([
|
||||
sys.executable, '-m', 'test.test_projects',
|
||||
options.project_python_path, project_dir
|
||||
], check=True)
|
||||
|
||||
exit(subprocess.run(['cibuildwheel'], cwd=project_dir).returncode)
|
||||
@@ -1 +1 @@
|
||||
__version__ = '1.6.3'
|
||||
__version__ = '1.7.2'
|
||||
|
||||
@@ -21,6 +21,7 @@ from cibuildwheel.util import (
|
||||
BuildSelector,
|
||||
DependencyConstraints,
|
||||
Unbuffered,
|
||||
detect_ci_provider,
|
||||
resources_dir,
|
||||
)
|
||||
|
||||
@@ -47,12 +48,6 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None
|
||||
return os.environ.get(option_name, default)
|
||||
|
||||
|
||||
def strtobool(val: str) -> bool:
|
||||
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build wheels for all the platforms.',
|
||||
@@ -96,13 +91,14 @@ def main() -> None:
|
||||
if args.platform != 'auto':
|
||||
platform = args.platform
|
||||
else:
|
||||
ci = strtobool(os.environ.get('CI', 'false')) or 'BITRISE_BUILD_NUMBER' in os.environ or 'AZURE_HTTP_USER_AGENT' in os.environ or 'GITHUB_WORKFLOW' in os.environ
|
||||
if not ci:
|
||||
print('cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server, '
|
||||
'Travis CI, AppVeyor, Azure Pipelines, GitHub Actions and CircleCI are supported. You '
|
||||
'can run on your development machine or other CI providers using the --platform argument. '
|
||||
'Check --help output for more information.',
|
||||
file=sys.stderr)
|
||||
ci_provider = detect_ci_provider()
|
||||
if ci_provider is None:
|
||||
print(textwrap.dedent('''
|
||||
cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server;
|
||||
Travis CI, AppVeyor, Azure Pipelines, GitHub Actions, CircleCI, and Gitlab are
|
||||
supported. You can run on your development machine or other CI providers using the
|
||||
--platform argument. Check --help output for more information.
|
||||
'''), file=sys.stderr)
|
||||
exit(2)
|
||||
if sys.platform.startswith('linux'):
|
||||
platform = 'linux'
|
||||
|
||||
@@ -73,7 +73,7 @@ class DockerContainer:
|
||||
self.process.terminate()
|
||||
self.process.wait()
|
||||
|
||||
subprocess.run(['docker', 'rm', '--force', '-v', self.name])
|
||||
subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL)
|
||||
self.name = None
|
||||
|
||||
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
|
||||
|
||||
@@ -7,6 +7,7 @@ from pathlib import Path, PurePath
|
||||
from typing import List, NamedTuple, Union
|
||||
|
||||
from .docker_container import DockerContainer
|
||||
from .logger import log
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
|
||||
get_build_verbosity_extra_flags, prepare_command)
|
||||
|
||||
@@ -83,7 +84,7 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
|
||||
def build(options: BuildOptions) -> None:
|
||||
try:
|
||||
subprocess.check_call(['docker', '--version'])
|
||||
subprocess.check_output(['docker', '--version'])
|
||||
except Exception:
|
||||
print('cibuildwheel: Docker not found. Docker is required to run Linux builds. '
|
||||
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
|
||||
@@ -117,18 +118,25 @@ def build(options: BuildOptions) -> None:
|
||||
continue
|
||||
|
||||
try:
|
||||
log.step(f'Starting Docker image {docker_image}...')
|
||||
with DockerContainer(docker_image, simulate_32_bit=platform_tag.endswith('i686'), cwd=container_project_path) as docker:
|
||||
|
||||
log.step('Copying project into Docker...')
|
||||
docker.copy_into(Path.cwd(), container_project_path)
|
||||
|
||||
if options.before_all:
|
||||
log.step('Running before_all...')
|
||||
|
||||
env = docker.get_environment()
|
||||
env['PATH'] = f'/opt/python/cp38-cp38:{env["PATH"]}'
|
||||
env['PATH'] = f'/opt/python/cp38-cp38/bin:{env["PATH"]}'
|
||||
env = options.environment.as_dictionary(env, executor=docker.environment_executor)
|
||||
|
||||
before_all_prepared = prepare_command(options.before_all, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', before_all_prepared], env=env)
|
||||
|
||||
for config in platform_configs:
|
||||
log.build_start(config.identifier)
|
||||
|
||||
dependency_constraint_flags: List[Union[str, PathLike]] = []
|
||||
|
||||
if options.dependency_constraints:
|
||||
@@ -138,6 +146,8 @@ def build(options: BuildOptions) -> None:
|
||||
docker.copy_into(constraints_file, container_constraints_file)
|
||||
dependency_constraint_flags = ['-c', container_constraints_file]
|
||||
|
||||
log.step('Setting up build environment...')
|
||||
|
||||
env = docker.get_environment()
|
||||
|
||||
# put this config's python top of the list
|
||||
@@ -158,9 +168,12 @@ def build(options: BuildOptions) -> None:
|
||||
exit(1)
|
||||
|
||||
if options.before_build:
|
||||
log.step('Running before_build...')
|
||||
before_build_prepared = prepare_command(options.before_build, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', before_build_prepared], env=env)
|
||||
|
||||
log.step('Building wheel...')
|
||||
|
||||
temp_dir = PurePath('/tmp/cibuildwheel')
|
||||
built_wheel_dir = temp_dir / 'built_wheel'
|
||||
docker.call(['rm', '-rf', built_wheel_dir])
|
||||
@@ -184,6 +197,7 @@ def build(options: BuildOptions) -> None:
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
if options.repair_command:
|
||||
log.step('Repairing wheel...')
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
docker.call(['sh', '-c', repair_command_prepared], env=env)
|
||||
else:
|
||||
@@ -192,6 +206,8 @@ def build(options: BuildOptions) -> None:
|
||||
repaired_wheels = docker.glob(repaired_wheel_dir, '*.whl')
|
||||
|
||||
if options.test_command:
|
||||
log.step('Testing wheel...')
|
||||
|
||||
# set up a virtual environment to install and test from, to make sure
|
||||
# there are no dependencies that were pulled in at build time.
|
||||
docker.call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
|
||||
@@ -230,10 +246,14 @@ def build(options: BuildOptions) -> None:
|
||||
docker.call(['mkdir', '-p', container_output_dir])
|
||||
docker.call(['mv', *repaired_wheels, container_output_dir])
|
||||
|
||||
log.build_end()
|
||||
|
||||
log.step('Copying wheels back to host...')
|
||||
# copy the output back into the host
|
||||
docker.copy_out(container_output_dir, options.output_dir)
|
||||
log.step_end()
|
||||
except subprocess.CalledProcessError as error:
|
||||
print(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
|
||||
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
|
||||
troubleshoot(options.package_dir, error)
|
||||
exit(1)
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import codecs
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional, Union
|
||||
|
||||
from cibuildwheel.util import CIProvider, detect_ci_provider
|
||||
|
||||
DEFAULT_FOLD_PATTERN = ('{name}', '')
|
||||
FOLD_PATTERNS = {
|
||||
'azure': ('##[group]{name}', '##[endgroup]'),
|
||||
'travis': ('travis_fold:start:{identifier}\n{name}', 'travis_fold:end:{identifier}'),
|
||||
'github': ('::group::{name}', '::endgroup::{name}'),
|
||||
}
|
||||
|
||||
PLATFORM_IDENTIFIER_DESCIPTIONS = {
|
||||
'manylinux_x86_64': 'manylinux x86_64',
|
||||
'manylinux_i686': 'manylinux i686',
|
||||
'manylinux_aarch64': 'manylinux aarch64',
|
||||
'manylinux_ppc64le': 'manylinux ppc64le',
|
||||
'manylinux_s390x': 'manylinux s390x',
|
||||
'win32': 'Windows 32bit',
|
||||
'win_amd64': 'Windows 64bit',
|
||||
'macosx_x86_64': 'macOS x86_64',
|
||||
}
|
||||
|
||||
|
||||
class Logger:
|
||||
fold_mode: str
|
||||
colors_enabled: bool
|
||||
unicode_enabled: bool
|
||||
active_build_identifier: Optional[str] = None
|
||||
build_start_time: Optional[float] = None
|
||||
step_start_time: Optional[float] = None
|
||||
active_fold_group_name: Optional[str] = None
|
||||
|
||||
def __init__(self):
|
||||
if sys.platform == 'win32' and hasattr(sys.stdout, 'reconfigure'):
|
||||
# the encoding on Windows can be a 1-byte charmap, but all CIs
|
||||
# support utf8, so we hardcode that
|
||||
sys.stdout.reconfigure(encoding='utf8')
|
||||
|
||||
self.unicode_enabled = file_supports_unicode(sys.stdout)
|
||||
|
||||
ci_provider = detect_ci_provider()
|
||||
|
||||
if ci_provider == CIProvider.azure_pipelines:
|
||||
self.fold_mode = 'azure'
|
||||
self.colors_enabled = True
|
||||
|
||||
elif ci_provider == CIProvider.github_actions:
|
||||
self.fold_mode = 'github'
|
||||
self.colors_enabled = True
|
||||
|
||||
elif ci_provider == CIProvider.travis_ci:
|
||||
self.fold_mode = 'travis'
|
||||
self.colors_enabled = True
|
||||
|
||||
elif ci_provider == CIProvider.appveyor:
|
||||
self.fold_mode = 'disabled'
|
||||
self.colors_enabled = True
|
||||
|
||||
else:
|
||||
self.fold_mode = 'disabled'
|
||||
self.colors_enabled = file_supports_color(sys.stdout)
|
||||
|
||||
def build_start(self, identifier: str):
|
||||
self.step_end()
|
||||
c = self.colors
|
||||
description = build_description_from_identifier(identifier)
|
||||
print()
|
||||
print(f'{c.bold}{c.blue}Building {identifier} wheel{c.end}')
|
||||
print(f'{description}')
|
||||
print()
|
||||
|
||||
self.build_start_time = time.time()
|
||||
self.active_build_identifier = identifier
|
||||
|
||||
def build_end(self):
|
||||
assert self.build_start_time is not None
|
||||
assert self.active_build_identifier is not None
|
||||
self.step_end()
|
||||
|
||||
c = self.colors
|
||||
s = self.symbols
|
||||
duration = time.time() - self.build_start_time
|
||||
|
||||
print()
|
||||
print(f'{c.green}{s.done} {c.end}{self.active_build_identifier} finished in {duration:.2f}s')
|
||||
self.build_start_time = None
|
||||
self.active_build_identifier = None
|
||||
|
||||
def step(self, step_description: str):
|
||||
self.step_end()
|
||||
self.step_start_time = time.time()
|
||||
self._start_fold_group(step_description)
|
||||
|
||||
def step_end(self, success=True):
|
||||
if self.step_start_time is not None:
|
||||
self._end_fold_group()
|
||||
c = self.colors
|
||||
s = self.symbols
|
||||
duration = time.time() - self.step_start_time
|
||||
if success:
|
||||
print(f'{c.green}{s.done} {c.end}{duration:.2f}s'.rjust(78))
|
||||
else:
|
||||
print(f'{c.red}{s.error} {c.end}{duration:.2f}s'.rjust(78))
|
||||
|
||||
self.step_start_time = None
|
||||
|
||||
def error(self, error: Union[Exception, str]):
|
||||
self.step_end(success=False)
|
||||
print()
|
||||
|
||||
if self.fold_mode == 'github':
|
||||
print(f'::error::{error}')
|
||||
else:
|
||||
c = self.colors
|
||||
print(f'{c.bright_red}Error{c.end} {error}')
|
||||
|
||||
def _start_fold_group(self, name: str):
|
||||
self._end_fold_group()
|
||||
self.active_fold_group_name = name
|
||||
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0]
|
||||
identifier = self._fold_group_identifier(name)
|
||||
|
||||
print(fold_start_pattern.format(name=self.active_fold_group_name, identifier=identifier))
|
||||
print()
|
||||
sys.stdout.flush()
|
||||
|
||||
def _end_fold_group(self):
|
||||
if self.active_fold_group_name:
|
||||
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[1]
|
||||
identifier = self._fold_group_identifier(self.active_fold_group_name)
|
||||
print(fold_start_pattern.format(name=self.active_fold_group_name, identifier=identifier))
|
||||
sys.stdout.flush()
|
||||
self.active_fold_group_name = None
|
||||
|
||||
def _fold_group_identifier(self, name: str):
|
||||
'''
|
||||
Travis doesn't like fold groups identifiers that have spaces in. This
|
||||
method converts them to ascii identifiers
|
||||
'''
|
||||
# whitespace to underscores
|
||||
identifier = re.sub(r'\s+', '_', name)
|
||||
# remove non-alphanum
|
||||
identifier = re.sub(r'[^A-Za-z\d_]+', '', identifier)
|
||||
# trim underscores
|
||||
identifier = identifier.strip('_')
|
||||
# lowercase, shorten
|
||||
return identifier.lower()[:20]
|
||||
|
||||
@property
|
||||
def colors(self):
|
||||
if self.colors_enabled:
|
||||
return Colors.enabled
|
||||
else:
|
||||
return Colors.disabled
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
if self.unicode_enabled:
|
||||
return Symbols.unicode
|
||||
else:
|
||||
return Symbols.ascii
|
||||
|
||||
|
||||
def build_description_from_identifier(identifier: str):
|
||||
python_identifier, _, platform_identifier = identifier.partition('-')
|
||||
|
||||
build_description = ''
|
||||
|
||||
python_interpreter = python_identifier[0:2]
|
||||
python_version = python_identifier[2:4]
|
||||
|
||||
if python_interpreter == 'cp':
|
||||
build_description += 'CPython'
|
||||
elif python_interpreter == 'pp':
|
||||
build_description += 'PyPy'
|
||||
else:
|
||||
raise Exception('unknown python')
|
||||
|
||||
build_description += f' {python_version[0]}.{python_version[1]} '
|
||||
|
||||
try:
|
||||
build_description += PLATFORM_IDENTIFIER_DESCIPTIONS[platform_identifier]
|
||||
except KeyError as e:
|
||||
raise Exception('unknown platform') from e
|
||||
|
||||
return build_description
|
||||
|
||||
|
||||
class Colors:
|
||||
class Enabled:
|
||||
red = '\033[31m'
|
||||
green = '\033[32m'
|
||||
yellow = '\033[33m'
|
||||
blue = '\033[34m'
|
||||
cyan = '\033[36m'
|
||||
bright_red = '\033[91m'
|
||||
bright_green = '\033[92m'
|
||||
white = '\033[37m\033[97m'
|
||||
|
||||
bg_grey = '\033[48;5;235m'
|
||||
|
||||
bold = '\033[1m'
|
||||
faint = '\033[2m'
|
||||
|
||||
end = '\033[0m'
|
||||
|
||||
class Disabled:
|
||||
def __getattr__(self, attr: str) -> str:
|
||||
return ''
|
||||
|
||||
enabled = Enabled()
|
||||
disabled = Disabled()
|
||||
|
||||
|
||||
class Symbols:
|
||||
class Unicode:
|
||||
done = '✓'
|
||||
error = '✕'
|
||||
|
||||
class Ascii:
|
||||
done = 'done'
|
||||
error = 'failed'
|
||||
|
||||
unicode = Unicode()
|
||||
ascii = Ascii()
|
||||
|
||||
|
||||
def file_supports_color(file_obj):
|
||||
"""
|
||||
Returns True if the running system's terminal supports color.
|
||||
"""
|
||||
plat = sys.platform
|
||||
supported_platform = (plat != 'win32' or 'ANSICON' in os.environ)
|
||||
|
||||
is_a_tty = file_is_a_tty(file_obj)
|
||||
|
||||
return (supported_platform and is_a_tty)
|
||||
|
||||
|
||||
def file_is_a_tty(file_obj):
|
||||
return hasattr(file_obj, 'isatty') and file_obj.isatty()
|
||||
|
||||
|
||||
def file_supports_unicode(file_obj):
|
||||
encoding = getattr(file_obj, 'encoding', None)
|
||||
if not encoding:
|
||||
return False
|
||||
|
||||
codec_info = codecs.lookup(encoding)
|
||||
|
||||
return ('utf' in codec_info.name)
|
||||
|
||||
|
||||
'''
|
||||
Global instance of the Logger.
|
||||
'''
|
||||
# (there's only one stdout per-process, so a global instance is justified)
|
||||
log = Logger()
|
||||
@@ -9,9 +9,10 @@ from pathlib import Path
|
||||
from typing import Dict, List, NamedTuple, Optional, Sequence, Union
|
||||
|
||||
from .environment import ParsedEnvironment
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
|
||||
get_build_verbosity_extra_flags, get_pip_script,
|
||||
prepare_command, install_certifi_script)
|
||||
from .logger import log
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
|
||||
download, get_build_verbosity_extra_flags, get_pip_script,
|
||||
install_certifi_script, prepare_command)
|
||||
|
||||
|
||||
def call(args: Union[str, Sequence[Union[str, PathLike]]], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int:
|
||||
@@ -36,13 +37,13 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
PythonConfiguration(version='2.7', identifier='cp27-macosx_x86_64', url='https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-macosx_x86_64', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-macosx_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.8/python-3.7.8-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.4/python-3.8.4-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.0/python-3.9.0-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.6/python-3.8.6-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg'),
|
||||
# PyPy
|
||||
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.2-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.2-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.2-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
|
||||
]
|
||||
|
||||
# skip builds as required
|
||||
@@ -116,13 +117,18 @@ def install_pypy(version: str, url: str) -> Path:
|
||||
def setup_python(python_configuration: PythonConfiguration,
|
||||
dependency_constraint_flags: Sequence[Union[str, PathLike]],
|
||||
environment: ParsedEnvironment) -> Dict[str, str]:
|
||||
if python_configuration.identifier.startswith('cp'):
|
||||
implementation_id = python_configuration.identifier.split("-")[0]
|
||||
log.step(f'Installing Python {implementation_id}...')
|
||||
|
||||
if implementation_id.startswith('cp'):
|
||||
installation_bin_path = install_cpython(python_configuration.version, python_configuration.url)
|
||||
elif python_configuration.identifier.startswith('pp'):
|
||||
elif implementation_id.startswith('pp'):
|
||||
installation_bin_path = install_pypy(python_configuration.version, python_configuration.url)
|
||||
else:
|
||||
raise ValueError("Unknown Python implementation")
|
||||
|
||||
log.step('Setting up build environment...')
|
||||
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = os.pathsep.join([
|
||||
str(SYMLINKS_DIR),
|
||||
@@ -156,7 +162,6 @@ def setup_python(python_configuration: PythonConfiguration,
|
||||
if which_pip != '/tmp/cibw_bin/pip':
|
||||
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)
|
||||
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate', *dependency_constraint_flags], env=env)
|
||||
|
||||
# Set MACOSX_DEPLOYMENT_TARGET to 10.9, if the user didn't set it.
|
||||
# CPython 3.5 defaults to 10.6, and pypy defaults to 10.7, causing
|
||||
@@ -170,6 +175,9 @@ def setup_python(python_configuration: PythonConfiguration,
|
||||
# https://github.com/python/cpython/blob/a5ed2fe0eedefa1649aa93ee74a0bafc8e628a10/Lib/_osx_support.py#L260
|
||||
env.setdefault('ARCHFLAGS', '-arch x86_64')
|
||||
|
||||
log.step('Installing build tools...')
|
||||
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate', *dependency_constraint_flags], env=env)
|
||||
|
||||
return env
|
||||
|
||||
|
||||
@@ -178,102 +186,111 @@ def build(options: BuildOptions) -> None:
|
||||
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)
|
||||
try:
|
||||
if options.before_all:
|
||||
log.step('Running 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)
|
||||
python_configurations = get_python_configurations(options.build_selector)
|
||||
|
||||
for config in python_configurations:
|
||||
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
|
||||
if options.dependency_constraints:
|
||||
dependency_constraint_flags = [
|
||||
'-c', options.dependency_constraints.get_for_python_version(config.version)
|
||||
]
|
||||
for config in python_configurations:
|
||||
log.build_start(config.identifier)
|
||||
|
||||
env = setup_python(config, dependency_constraint_flags, options.environment)
|
||||
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
|
||||
if options.dependency_constraints:
|
||||
dependency_constraint_flags = [
|
||||
'-c', options.dependency_constraints.get_for_python_version(config.version)
|
||||
]
|
||||
|
||||
# run the before_build command
|
||||
if options.before_build:
|
||||
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
|
||||
call(before_build_prepared, env=env, shell=True)
|
||||
env = setup_python(config, dependency_constraint_flags, options.environment)
|
||||
|
||||
# build the wheel
|
||||
if built_wheel_dir.exists():
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
built_wheel_dir.mkdir(parents=True)
|
||||
if options.before_build:
|
||||
log.step('Running before_build...')
|
||||
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
|
||||
call(before_build_prepared, env=env, shell=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',
|
||||
options.package_dir.resolve(),
|
||||
'-w', built_wheel_dir,
|
||||
'--no-deps',
|
||||
*get_build_verbosity_extra_flags(options.build_verbosity)
|
||||
], env=env)
|
||||
log.step('Building wheel...')
|
||||
if built_wheel_dir.exists():
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
built_wheel_dir.mkdir(parents=True)
|
||||
|
||||
built_wheel = next(built_wheel_dir.glob('*.whl'))
|
||||
# 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',
|
||||
options.package_dir.resolve(),
|
||||
'-w', built_wheel_dir,
|
||||
'--no-deps',
|
||||
*get_build_verbosity_extra_flags(options.build_verbosity)
|
||||
], env=env)
|
||||
|
||||
# repair the wheel
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
built_wheel = next(built_wheel_dir.glob('*.whl'))
|
||||
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
|
||||
if options.repair_command:
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
call(repair_command_prepared, env=env, shell=True)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
if options.repair_command:
|
||||
log.step('Repairing wheel...')
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
call(repair_command_prepared, env=env, shell=True)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
|
||||
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 = Path(tempfile.mkdtemp())
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
|
||||
# Use --no-download to ensure determinism by using seed libraries
|
||||
# built into virtualenv
|
||||
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
|
||||
if options.test_command:
|
||||
log.step('Testing wheel...')
|
||||
# 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 = Path(tempfile.mkdtemp())
|
||||
|
||||
virtualenv_env = env.copy()
|
||||
virtualenv_env['PATH'] = os.pathsep.join([
|
||||
str(venv_dir / 'bin'),
|
||||
virtualenv_env['PATH'],
|
||||
])
|
||||
# Use --no-download to ensure determinism by using seed libraries
|
||||
# built into virtualenv
|
||||
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
|
||||
|
||||
# check that we are using the Python from the virtual environment
|
||||
call(['which', 'python'], env=virtualenv_env)
|
||||
virtualenv_env = env.copy()
|
||||
virtualenv_env['PATH'] = os.pathsep.join([
|
||||
str(venv_dir / 'bin'),
|
||||
virtualenv_env['PATH'],
|
||||
])
|
||||
|
||||
if options.before_test:
|
||||
before_test_prepared = prepare_command(options.before_test, project='.', package=options.package_dir)
|
||||
call(before_test_prepared, env=virtualenv_env, shell=True)
|
||||
# check that we are using the Python from the virtual environment
|
||||
call(['which', 'python'], env=virtualenv_env)
|
||||
|
||||
# install the wheel
|
||||
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
|
||||
if options.before_test:
|
||||
before_test_prepared = prepare_command(options.before_test, project='.', package=options.package_dir)
|
||||
call(before_test_prepared, env=virtualenv_env, shell=True)
|
||||
|
||||
# test the wheel
|
||||
if options.test_requires:
|
||||
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
|
||||
# install the wheel
|
||||
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
|
||||
|
||||
# run the tests from $HOME, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
test_command_prepared = prepare_command(
|
||||
options.test_command,
|
||||
project=Path('.').resolve(),
|
||||
package=options.package_dir.resolve()
|
||||
)
|
||||
call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
|
||||
# test the wheel
|
||||
if options.test_requires:
|
||||
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
|
||||
|
||||
# clean up
|
||||
shutil.rmtree(venv_dir)
|
||||
# run the tests from $HOME, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
test_command_prepared = prepare_command(
|
||||
options.test_command,
|
||||
project=Path('.').resolve(),
|
||||
package=options.package_dir.resolve()
|
||||
)
|
||||
call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
|
||||
|
||||
# we're all done here; move it to output (overwrite existing)
|
||||
shutil.move(str(repaired_wheel), options.output_dir)
|
||||
# clean up
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# we're all done here; move it to output (overwrite existing)
|
||||
shutil.move(str(repaired_wheel), options.output_dir)
|
||||
log.build_end()
|
||||
except subprocess.CalledProcessError as error:
|
||||
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
|
||||
exit(1)
|
||||
|
||||
@@ -10,17 +10,17 @@ contextlib2==0.6.0.post1 # via importlib-metadata, importlib-resources
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==2.0.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
importlib-metadata==2.1.1 # via virtualenv
|
||||
importlib-resources==3.3.0 # via virtualenv
|
||||
pathlib2==2.3.5 # via importlib-metadata, importlib-resources, virtualenv
|
||||
scandir==1.10.0 # via pathlib2
|
||||
singledispatch==3.4.0.3 # via importlib-resources
|
||||
six==1.15.0 # via pathlib2, virtualenv
|
||||
typing==3.7.4.3 # via importlib-resources
|
||||
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.36.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==1.2.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.3.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==44.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -8,13 +8,13 @@ appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==2.0.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
importlib-metadata==2.1.1 # via virtualenv
|
||||
importlib-resources==3.2.1 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.36.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==1.2.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.3.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.2 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -8,13 +8,14 @@ appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==2.0.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
importlib-metadata==3.3.0 # via virtualenv
|
||||
importlib-resources==3.3.0 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.3.0 # via importlib-metadata, importlib-resources
|
||||
typing-extensions==3.7.4.3 # via importlib-metadata
|
||||
virtualenv==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.36.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.4.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.3.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==51.0.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -8,12 +8,13 @@ appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==2.0.0 # via virtualenv
|
||||
importlib-metadata==3.3.0 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.3.0 # via importlib-metadata
|
||||
typing-extensions==3.7.4.3 # via importlib-metadata
|
||||
virtualenv==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.36.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.4.0 # via importlib-metadata
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.3.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==51.0.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -9,9 +9,9 @@ delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.36.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.3.3 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==51.0.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
[x86_64]
|
||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-10-06-c4a4a7c
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-10-06-786a931
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-10-06-b2ca7a1
|
||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-18-c48c073
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-19-8df9e2d
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-18-cb453dc
|
||||
|
||||
[i686]
|
||||
manylinux1 = quay.io/pypa/manylinux1_i686:2020-10-06-c4a4a7c
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-10-06-786a931
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-10-06-b2ca7a1
|
||||
manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-18-c48c073
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-19-8df9e2d
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-18-cb453dc
|
||||
|
||||
[pypy_x86_64]
|
||||
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-09-26-8f210b5
|
||||
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-12-11-f1e0e80
|
||||
|
||||
[aarch64]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-10-06-b2ca7a1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-18-cb453dc
|
||||
|
||||
[ppc64le]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-10-06-b2ca7a1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-18-cb453dc
|
||||
|
||||
[s390x]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-10-06-b2ca7a1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-18-cb453dc
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import os
|
||||
import ssl
|
||||
import textwrap
|
||||
import urllib.request
|
||||
from enum import Enum
|
||||
from fnmatch import fnmatch
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
|
||||
from typing import Dict, List, NamedTuple, Optional, Union
|
||||
|
||||
import certifi
|
||||
|
||||
from .environment import ParsedEnvironment
|
||||
|
||||
|
||||
@@ -40,7 +43,10 @@ class BuildSelector:
|
||||
return match_any(self.build_patterns) and not match_any(self.skip_patterns)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'BuildSelector({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
|
||||
if not self.skip_patterns:
|
||||
return f'BuildSelector({" ".join(self.build_patterns)!r})'
|
||||
else:
|
||||
return f'BuildSelector({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
|
||||
|
||||
|
||||
# Taken from https://stackoverflow.com/a/107717
|
||||
@@ -66,10 +72,14 @@ def download(url: str, dest: Path) -> None:
|
||||
if not dest_dir.exists():
|
||||
dest_dir.mkdir(parents=True)
|
||||
|
||||
# we've had issues when relying on the host OS' CA certificates on Windows,
|
||||
# so we use certifi (this sounds odd but requests also does this by default)
|
||||
cafile = os.environ.get('SSL_CERT_FILE', certifi.where())
|
||||
context = ssl.create_default_context(cafile=cafile)
|
||||
repeat_num = 3
|
||||
for i in range(repeat_num):
|
||||
try:
|
||||
response = urllib.request.urlopen(url)
|
||||
response = urllib.request.urlopen(url, context=context)
|
||||
except Exception:
|
||||
if i == repeat_num - 1:
|
||||
raise
|
||||
@@ -107,8 +117,8 @@ class DependencyConstraints:
|
||||
else:
|
||||
return self.base_file_path
|
||||
|
||||
def __str__(self):
|
||||
return f"File '{self.base_file_path}'"
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}{self.base_file_path!r})'
|
||||
|
||||
|
||||
class BuildOptions(NamedTuple):
|
||||
@@ -146,3 +156,38 @@ class NonPlatformWheelError(Exception):
|
||||
''')
|
||||
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
def strtobool(val: str) -> bool:
|
||||
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class CIProvider(str, Enum):
|
||||
travis_ci = 'travis'
|
||||
appveyor = 'appveyor'
|
||||
circle_ci = 'circle_ci'
|
||||
azure_pipelines = 'azure_pipelines'
|
||||
github_actions = 'github_actions'
|
||||
gitlab = 'gitlab'
|
||||
other = 'other'
|
||||
|
||||
|
||||
def detect_ci_provider() -> Optional[CIProvider]:
|
||||
if 'TRAVIS' in os.environ:
|
||||
return CIProvider.travis_ci
|
||||
elif 'APPVEYOR' in os.environ:
|
||||
return CIProvider.appveyor
|
||||
elif 'CIRCLECI' in os.environ:
|
||||
return CIProvider.circle_ci
|
||||
elif 'AZURE_HTTP_USER_AGENT' in os.environ:
|
||||
return CIProvider.azure_pipelines
|
||||
elif 'GITHUB_ACTIONS' in os.environ:
|
||||
return CIProvider.github_actions
|
||||
elif 'GITLAB_CI' in os.environ:
|
||||
return CIProvider.gitlab
|
||||
elif strtobool(os.environ.get('CI', 'false')):
|
||||
return CIProvider.other
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -7,11 +7,13 @@ from os import PathLike
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, NamedTuple, Optional, Sequence, Union
|
||||
from zipfile import ZipFile
|
||||
|
||||
import toml
|
||||
|
||||
from .environment import ParsedEnvironment
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
|
||||
get_build_verbosity_extra_flags, get_pip_script,
|
||||
from .logger import log
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
|
||||
download, get_build_verbosity_extra_flags, get_pip_script,
|
||||
prepare_command)
|
||||
|
||||
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
|
||||
@@ -54,16 +56,16 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
PythonConfiguration(version='3.5.4', arch='64', identifier='cp35-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.6.8', arch='32', identifier='cp36-win32', url=None),
|
||||
PythonConfiguration(version='3.6.8', arch='64', identifier='cp36-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.7.8', arch='32', identifier='cp37-win32', url=None),
|
||||
PythonConfiguration(version='3.7.8', arch='64', identifier='cp37-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.8.4', arch='32', identifier='cp38-win32', url=None),
|
||||
PythonConfiguration(version='3.8.4', arch='64', identifier='cp38-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.9.0', arch='32', identifier='cp39-win32', url=None),
|
||||
PythonConfiguration(version='3.9.0', arch='64', identifier='cp39-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.7.9', arch='32', identifier='cp37-win32', url=None),
|
||||
PythonConfiguration(version='3.7.9', arch='64', identifier='cp37-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.8.6', arch='32', identifier='cp38-win32', url=None),
|
||||
PythonConfiguration(version='3.8.6', arch='64', identifier='cp38-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.9.1', arch='32', identifier='cp39-win32', url=None),
|
||||
PythonConfiguration(version='3.9.1', arch='64', identifier='cp39-win_amd64', url=None),
|
||||
# PyPy
|
||||
PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.2-win32.zip'),
|
||||
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.2-win32.zip'),
|
||||
PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.2-win32.zip'),
|
||||
PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip'),
|
||||
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip'),
|
||||
PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip'),
|
||||
]
|
||||
|
||||
if IS_RUNNING_ON_TRAVIS:
|
||||
@@ -109,11 +111,15 @@ def install_pypy(version: str, arch: str, url: str) -> Path:
|
||||
def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[Union[str, PathLike]], environment: ParsedEnvironment) -> Dict[str, str]:
|
||||
nuget = Path('C:\\cibw\\nuget.exe')
|
||||
if not nuget.exists():
|
||||
log.step('Downloading nuget...')
|
||||
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
|
||||
|
||||
if python_configuration.identifier.startswith('cp'):
|
||||
implementation_id = python_configuration.identifier.split("-")[0]
|
||||
log.step(f'Installing Python {implementation_id}...')
|
||||
|
||||
if implementation_id.startswith('cp'):
|
||||
installation_path = install_cpython(python_configuration.version, python_configuration.arch, nuget)
|
||||
elif python_configuration.identifier.startswith('pp'):
|
||||
elif implementation_id.startswith('pp'):
|
||||
assert python_configuration.url is not None
|
||||
installation_path = install_pypy(python_configuration.version, python_configuration.arch, python_configuration.url)
|
||||
else:
|
||||
@@ -121,6 +127,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
|
||||
|
||||
assert (installation_path / 'python.exe').exists()
|
||||
|
||||
log.step('Setting up build environment...')
|
||||
|
||||
# set up PATH and environment variables for run_with_env
|
||||
env = os.environ.copy()
|
||||
env['PYTHON_VERSION'] = python_configuration.version
|
||||
@@ -151,7 +159,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
|
||||
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)
|
||||
|
||||
# prepare the Python environment
|
||||
log.step('Installing build tools...')
|
||||
|
||||
call(['python', '-m', 'pip', 'install', '--upgrade', 'pip', *dependency_constraint_flags], env=env)
|
||||
call(['pip', '--version'], env=env)
|
||||
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', *dependency_constraint_flags], env=env)
|
||||
@@ -182,6 +191,7 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
|
||||
)
|
||||
|
||||
if requirements:
|
||||
log.step('Performing PEP518 workaround...')
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
reqfile = Path(d) / "requirements.txt"
|
||||
with reqfile.open("w") as f:
|
||||
@@ -195,114 +205,122 @@ def build(options: BuildOptions) -> None:
|
||||
built_wheel_dir = temp_dir / 'built_wheel'
|
||||
repaired_wheel_dir = temp_dir / 'repaired_wheel'
|
||||
|
||||
# install nuget as best way to provide python
|
||||
nuget = Path('C:\\cibw\\nuget.exe')
|
||||
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
|
||||
try:
|
||||
if options.before_all:
|
||||
log.step('Running 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)
|
||||
|
||||
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)
|
||||
|
||||
python_configurations = get_python_configurations(options.build_selector)
|
||||
for config in python_configurations:
|
||||
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
|
||||
if options.dependency_constraints:
|
||||
dependency_constraint_flags = [
|
||||
'-c', options.dependency_constraints.get_for_python_version(config.version)
|
||||
]
|
||||
for config in python_configurations:
|
||||
log.build_start(config.identifier)
|
||||
|
||||
# install Python
|
||||
env = setup_python(config, dependency_constraint_flags, options.environment)
|
||||
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
|
||||
if options.dependency_constraints:
|
||||
dependency_constraint_flags = [
|
||||
'-c', options.dependency_constraints.get_for_python_version(config.version)
|
||||
]
|
||||
|
||||
# run the before_build command
|
||||
if options.before_build:
|
||||
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
|
||||
shell(before_build_prepared, env=env)
|
||||
# install Python
|
||||
env = setup_python(config, dependency_constraint_flags, options.environment)
|
||||
|
||||
# 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)
|
||||
# run the before_build command
|
||||
if options.before_build:
|
||||
log.step('Running before_build...')
|
||||
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
|
||||
shell(before_build_prepared, env=env)
|
||||
|
||||
# build the wheel
|
||||
if built_wheel_dir.exists():
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
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',
|
||||
options.package_dir.resolve(),
|
||||
'-w', built_wheel_dir,
|
||||
'--no-deps',
|
||||
*get_build_verbosity_extra_flags(options.build_verbosity)
|
||||
], 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)
|
||||
|
||||
built_wheel = next(built_wheel_dir.glob('*.whl'))
|
||||
log.step('Building wheel...')
|
||||
if built_wheel_dir.exists():
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
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',
|
||||
options.package_dir.resolve(),
|
||||
'-w', built_wheel_dir,
|
||||
'--no-deps',
|
||||
*get_build_verbosity_extra_flags(options.build_verbosity)
|
||||
], env=env)
|
||||
|
||||
# repair the wheel
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
built_wheel = next(built_wheel_dir.glob('*.whl'))
|
||||
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
# repair the wheel
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
|
||||
if options.repair_command:
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
shell(repair_command_prepared, env=env)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
if options.repair_command:
|
||||
log.step('Repairing wheel...')
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
shell(repair_command_prepared, env=env)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
|
||||
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 = Path(tempfile.mkdtemp())
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
|
||||
# Use --no-download to ensure determinism by using seed libraries
|
||||
# built into virtualenv
|
||||
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
|
||||
if options.test_command:
|
||||
log.step('Testing wheel...')
|
||||
# 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 = Path(tempfile.mkdtemp())
|
||||
|
||||
virtualenv_env = env.copy()
|
||||
virtualenv_env['PATH'] = os.pathsep.join([
|
||||
str(venv_dir / 'Scripts'),
|
||||
virtualenv_env['PATH'],
|
||||
])
|
||||
# Use --no-download to ensure determinism by using seed libraries
|
||||
# built into virtualenv
|
||||
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
|
||||
|
||||
# check that we are using the Python from the virtual environment
|
||||
call(['which', 'python'], env=virtualenv_env)
|
||||
virtualenv_env = env.copy()
|
||||
virtualenv_env['PATH'] = os.pathsep.join([
|
||||
str(venv_dir / 'Scripts'),
|
||||
virtualenv_env['PATH'],
|
||||
])
|
||||
|
||||
if options.before_test:
|
||||
before_test_prepared = prepare_command(
|
||||
options.before_test,
|
||||
project='.',
|
||||
package=options.package_dir
|
||||
# check that we are using the Python from the virtual environment
|
||||
call(['which', 'python'], env=virtualenv_env)
|
||||
|
||||
if options.before_test:
|
||||
before_test_prepared = prepare_command(
|
||||
options.before_test,
|
||||
project='.',
|
||||
package=options.package_dir
|
||||
)
|
||||
shell(before_test_prepared, env=virtualenv_env)
|
||||
|
||||
# install the wheel
|
||||
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
|
||||
|
||||
# test the wheel
|
||||
if options.test_requires:
|
||||
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
|
||||
|
||||
# run the tests from c:\, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
test_command_prepared = prepare_command(
|
||||
options.test_command,
|
||||
project=Path('.').resolve(),
|
||||
package=options.package_dir.resolve()
|
||||
)
|
||||
shell(before_test_prepared, env=virtualenv_env)
|
||||
shell(test_command_prepared, cwd='c:\\', env=virtualenv_env)
|
||||
|
||||
# install the wheel
|
||||
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
|
||||
# clean up
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# test the wheel
|
||||
if options.test_requires:
|
||||
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
|
||||
|
||||
# run the tests from c:\, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
test_command_prepared = prepare_command(
|
||||
options.test_command,
|
||||
project=Path('.').resolve(),
|
||||
package=options.package_dir.resolve()
|
||||
)
|
||||
shell(test_command_prepared, cwd='c:\\', env=virtualenv_env)
|
||||
|
||||
# clean up
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# we're all done here; move it to output (remove if already exists)
|
||||
shutil.move(str(repaired_wheel), options.output_dir)
|
||||
# we're all done here; move it to output (remove if already exists)
|
||||
shutil.move(str(repaired_wheel), options.output_dir)
|
||||
log.build_end()
|
||||
except subprocess.CalledProcessError as error:
|
||||
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
|
||||
exit(1)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Changelog
|
||||
---
|
||||
|
||||
{%
|
||||
include-markdown "../README.md"
|
||||
start="<!--changelog-start-->"
|
||||
end="<!--changelog-end-->"
|
||||
%}
|
||||
|
||||
<script>
|
||||
// undo the scrollTop that the theme did on this page, as there are loads
|
||||
// of toc entries and it's disorientating.
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
$('.wy-nav-side').scrollTop(0)
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,215 @@
|
||||
# Fields:
|
||||
# name: required, printed name
|
||||
# gh: Github repo (eventually a url: could be added for non-github projects)
|
||||
# stars: Github repo (optional, if different from package, such as for Twisted)
|
||||
# os: Operating system list, [windows, apple, linux] (optional)
|
||||
# ci: [appveyor, github, azurepipelines, circleci, gitlab, travisci] (optional)
|
||||
# notes: (text, optional)
|
||||
|
||||
- name: Matplotlib
|
||||
gh: matplotlib/matplotlib
|
||||
notes: The venerable Matplotlib, a Python library with C++ portions
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pyinstrument_cext
|
||||
gh: joerick/pyinstrument_cext
|
||||
ci: [travisci, appveyor]
|
||||
os: [windows, apple, linux]
|
||||
notes: A simple C extension, without external dependencies
|
||||
|
||||
- name: websockets
|
||||
gh: aaugustin/websockets
|
||||
ci: [travisci]
|
||||
ci_config: .travis.yml
|
||||
os: [apple, linux]
|
||||
notes: |
|
||||
Library for building WebSocket servers and clients. Mostly written in
|
||||
Python, with a small C 'speedups' extension module.
|
||||
|
||||
- name: Parselmouth
|
||||
gh: YannickJadoul/Parselmouth
|
||||
notes: A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels.
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
# Seems to be defunct
|
||||
# - name: python-admesh
|
||||
# gh: admesh/python-admesh
|
||||
|
||||
- name: pybase64
|
||||
gh: mayeut/pybase64
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
|
||||
- name: KDEpy
|
||||
gh: tommyod/KDEpy
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: AutoPy
|
||||
gh: autopilot-rs/autopy
|
||||
ci: [travisci]
|
||||
os: [windows, apple, linux]
|
||||
notes: Includes a Windows Travis build.
|
||||
|
||||
# Seems to be defunct
|
||||
# - name: apriltags2-ethz
|
||||
# gh: safijari/apriltags2_ethz
|
||||
|
||||
- name: TgCrypto
|
||||
gh: pyrogram/tgcrypto
|
||||
ci: [travisci]
|
||||
os: [windows, apple, linux]
|
||||
notes: Includes a Windows Travis build.
|
||||
|
||||
- name: twisted-iocpsupport
|
||||
gh: twisted/twisted-iocpsupport
|
||||
stars: twisted/twisted
|
||||
notes: A submodule of Twisted that hooks into native C APIs using Cython.
|
||||
ci: [github]
|
||||
os: [windows]
|
||||
|
||||
# cibuildwheel moved to backup folder
|
||||
# - name: gmic-py
|
||||
# gh: myselfhimself/gmic-py
|
||||
|
||||
- name: River
|
||||
gh: online-ml/river
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: PyAV
|
||||
gh: PyAV-Org/PyAV
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
notes: Pythonic bindings for FFmpeg's libraries.
|
||||
|
||||
- name: aiortc
|
||||
gh: aiortc/aiortc
|
||||
ci: [github]
|
||||
os: [apple, linux]
|
||||
notes: WebRTC and ORTC implementation for Python using asyncio.
|
||||
|
||||
- name: aioquic
|
||||
gh: aiortc/aioquic
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pikepdf
|
||||
gh: pikepdf/pikepdf
|
||||
ci: [azurepipelines]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: fathon
|
||||
gh: stfbnc/fathon
|
||||
ci: [travisci]
|
||||
os: [apple, linux]
|
||||
|
||||
- name: etebase-py
|
||||
gh: etesync/etebase-py
|
||||
notes: Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed.
|
||||
ci: [travisci]
|
||||
os: [linux]
|
||||
|
||||
- name: xmlstarlet
|
||||
gh: dimitern/xmlstarlet
|
||||
notes: Python 3.6+ CFFI bindings with true MSVC build.
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: bx-python
|
||||
gh: bxlab/bx-python
|
||||
notes: A library that includes Cython extensions.
|
||||
ci: [travisci]
|
||||
os: [apple, linux]
|
||||
|
||||
- name: coverage.py
|
||||
gh: nedbat/coveragepy
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
notes: The coverage tool for Python
|
||||
|
||||
- name: scikit-learn
|
||||
gh: scikit-learn/scikit-learn
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
ci_config: .github/workflows/wheels.yml
|
||||
notes: |
|
||||
The machine learning library. A complex but clean config using many of
|
||||
cibuildwheel's features to build a large project with Cython and C++
|
||||
extensions.
|
||||
|
||||
- name: scikit-image
|
||||
gh: scikit-image/scikit-image
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
ci_config: .github/workflows/cibuildwheel.yml
|
||||
notes: |
|
||||
Image processing library. Uses cibuildwheel to build and test a project
|
||||
that uses Cython with platform-native code.
|
||||
|
||||
- name: google neuroglancer
|
||||
gh: google/neuroglancer
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: h5py
|
||||
gh: h5py/h5py
|
||||
ci: [azurepipelines]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pyzmq
|
||||
gh: zeromq/pyzmq
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
ci_config: .github/workflows/wheels.yml
|
||||
notes: |
|
||||
Python bindings for zeromq, the networking library. Uses Cython and CFFI.
|
||||
|
||||
- name: python-rapidjson
|
||||
gh: python-rapidjson/python-rapidjson
|
||||
ci: [travisci, gitlab, appveyor]
|
||||
os: [windows, linux]
|
||||
|
||||
- name: jq.py
|
||||
gh: mwilliamson/jq.py
|
||||
ci: [travisci]
|
||||
os: [apple, linux]
|
||||
|
||||
- name: pybind11 python_example
|
||||
gh: pybind/python_example
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pybind11 cmake_example
|
||||
gh: pybind/cmake_example
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pybind11 scikit_build_example
|
||||
gh: pybind/scikit_build_example
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: iminuit
|
||||
gh: scikit-hep/iminuit
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: pyjet
|
||||
gh: scikit-hep/pyjet
|
||||
ci: [github]
|
||||
os: [windows, apple, linux]
|
||||
|
||||
- name: numpythia
|
||||
gh: scikit-hep/numpythia
|
||||
ci: [github]
|
||||
os: [apple, linux]
|
||||
|
||||
- name: boost-histogram
|
||||
gh: scikit-hep/boost-histogram
|
||||
ci: [github, travisci]
|
||||
os: [windows, apple, linux]
|
||||
notes: Supports full range of wheels, including PyPy and alternate archs.
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>Apple icon</title><path d="M7.078 23.55c-.473-.316-.893-.703-1.244-1.15-.383-.463-.738-.95-1.064-1.454-.766-1.12-1.365-2.345-1.78-3.636-.5-1.502-.743-2.94-.743-4.347 0-1.57.34-2.94 1.002-4.09.49-.9 1.22-1.653 2.1-2.182.85-.53 1.84-.82 2.84-.84.35 0 .73.05 1.13.15.29.08.64.21 1.07.37.55.21.85.34.95.37.32.12.59.17.8.17.16 0 .39-.05.645-.13.145-.05.42-.14.81-.31.386-.14.692-.26.935-.35.37-.11.728-.21 1.05-.26.39-.06.777-.08 1.148-.05.71.05 1.36.2 1.94.42 1.02.41 1.843 1.05 2.457 1.96-.26.16-.5.346-.725.55-.487.43-.9.94-1.23 1.505-.43.77-.65 1.64-.644 2.52.015 1.083.29 2.035.84 2.86.387.6.904 1.114 1.534 1.536.31.21.582.355.84.45-.12.375-.252.74-.405 1.1-.347.807-.76 1.58-1.25 2.31-.432.63-.772 1.1-1.03 1.41-.402.48-.79.84-1.18 1.097-.43.285-.935.436-1.452.436-.35.015-.7-.03-1.034-.127-.29-.095-.576-.202-.856-.323-.293-.134-.596-.248-.905-.34-.38-.1-.77-.148-1.164-.147-.4 0-.79.05-1.16.145-.31.088-.61.196-.907.325-.42.175-.695.29-.855.34-.324.096-.656.154-.99.175-.52 0-1.004-.15-1.486-.45zm6.854-18.46c-.68.34-1.326.484-1.973.436-.1-.646 0-1.31.27-2.037.24-.62.56-1.18 1-1.68.46-.52 1.01-.95 1.63-1.26.66-.34 1.29-.52 1.89-.55.08.68 0 1.35-.25 2.07-.228.64-.568 1.23-1 1.76-.435.52-.975.95-1.586 1.26z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>AppVeyor icon</title><path d="M 12,0 C 18.6,0 24,5.4 24,12 24,18.6 18.6,24 12,24 5.4,24 0,18.6 0,12 0,5.4 5.4,0 12,0 Z m 2.94,14.34 C 16.26,12.66 16.08,10.26 14.4,9 12.78,7.74 10.38,8.04 9,9.72 7.68,11.4 7.86,13.8 9.54,15.06 c 1.68,1.26 4.08,0.96 5.4,-0.72 z m -6.42,7.8 c 0.72,0.3 2.28,0.6 3.06,0.6 l 5.22,-7.56 c 1.68,-2.52 1.26,-5.94 -1.08,-7.8 -2.1,-1.68 -5.04,-1.62 -7.14,0 l -7.26,5.58 c 0.18,1.92 0.72,2.88 0.72,2.94 l 4.14,-4.5 c -0.3,1.98 0.42,4.02 2.1,5.28 1.44,1.14 3.18,1.44 4.86,1.08 z"/></svg>
|
||||
|
After Width: | Height: | Size: 613 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>Azure Pipelines icon</title><path d="M1.8 18H0v6h6v-1.8H1.8zM23 0h-8.93a2 2 0 0 0-1.67.89L9 5.99H1a1 1 0 0 0-1 1v5.5l3.5 3.61 1.2-1.29 1.5 1.5L5 17.53l1.48 1.48 1.22-1.22 1.5 1.51L8 20.5l3.5 3.5H17a1 1 0 0 0 1-1v-8l5.11-3.4A2 2 0 0 0 24 9.92V1a1 1 0 0 0-1-1zm-5 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></svg>
|
||||
|
After Width: | Height: | Size: 407 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>CircleCI icon</title><path d="M8.963 12c0-1.584 1.284-2.855 2.855-2.855 1.572 0 2.856 1.284 2.856 2.855 0 1.572-1.284 2.856-2.856 2.856-1.57 0-2.855-1.284-2.855-2.856zm2.855-12C6.215 0 1.522 3.84.19 9.025c-.01.036-.01.07-.01.12 0 .313.252.576.575.576H5.59c.23 0 .433-.13.517-.333.997-2.16 3.18-3.672 5.712-3.672 3.466 0 6.286 2.82 6.286 6.287 0 3.47-2.82 6.29-6.29 6.29-2.53 0-4.714-1.5-5.71-3.673-.097-.19-.29-.336-.517-.336H.755c-.312 0-.575.253-.575.576 0 .037.014.072.014.12C1.514 20.16 6.214 24 11.818 24c6.624 0 12-5.375 12-12 0-6.623-5.376-12-12-12z"/></svg>
|
||||
|
After Width: | Height: | Size: 671 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>GitHub icon</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
After Width: | Height: | Size: 855 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>GitLab icon</title><path d="M4.845.904c-.435 0-.82.28-.955.692C2.639 5.449 1.246 9.728.07 13.335a1.437 1.437 0 00.522 1.607l11.071 8.045c.2.145.472.144.67-.004l11.073-8.04a1.436 1.436 0 00.522-1.61c-1.285-3.942-2.683-8.256-3.817-11.746a1.004 1.004 0 00-.957-.684.987.987 0 00-.949.69l-2.405 7.408H8.203l-2.41-7.408a.987.987 0 00-.942-.69h-.006zm-.006 1.42l2.173 6.678H2.675zm14.326 0l2.168 6.678h-4.341zm-10.593 7.81h6.862c-1.142 3.52-2.288 7.04-3.434 10.559L8.572 10.135zm-5.514.005h4.321l3.086 9.5zm13.567 0h4.325c-2.467 3.17-4.95 6.328-7.411 9.502 1.028-3.167 2.059-6.334 3.086-9.502zM2.1 10.762l6.977 8.947-7.817-5.682a.305.305 0 01-.112-.341zm19.798 0l.952 2.922a.305.305 0 01-.11.341v.002l-7.82 5.68.026-.035z"/></svg>
|
||||
|
After Width: | Height: | Size: 830 B |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" width="16px" fill="#606060"><title>Windows icon</title><path d="M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.4H10.949M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-12.9-1.801"/></svg>
|
||||
|
After Width: | Height: | Size: 256 B |
@@ -29,7 +29,6 @@ h1, h2, h3, h4, h5, h6 {
|
||||
border-bottom: 1px solid #e1e4e5;
|
||||
margin-bottom: 0.8em;
|
||||
padding-bottom: 0.2em;
|
||||
|
||||
}
|
||||
|
||||
.rst-content blockquote {
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Home
|
||||
---
|
||||
|
||||
{%
|
||||
includemarkdown "../README.md"
|
||||
include-markdown "../README.md"
|
||||
start="<!--intro-start-->"
|
||||
end="<!--intro-end-->"
|
||||
%}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import cgi
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import mkdocs
|
||||
|
||||
INCLUDE_TAG_REGEX = re.compile(
|
||||
r'''
|
||||
{% # opening tag
|
||||
\s*
|
||||
include # directive name
|
||||
\s+
|
||||
"(?P<filename>[^"]+)" # "filename"
|
||||
\s*
|
||||
%} # closing tag
|
||||
''',
|
||||
flags=re.VERBOSE,
|
||||
)
|
||||
|
||||
INCLUDEMARKDOWN_TAG_REGEX = re.compile(
|
||||
r'''
|
||||
{% # opening tag
|
||||
\s*
|
||||
includemarkdown # directive name
|
||||
\s+
|
||||
"(?P<filename>[^"]+)" # "filename"
|
||||
(?:\s+start="(?P<start>[^"]+)")? # optional start expression
|
||||
(?:\s+end="(?P<end>[^"]+)")? # optional end expression
|
||||
\s*
|
||||
%} # closing tag
|
||||
''',
|
||||
flags=re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
class ImportMarkdownPlugin(mkdocs.plugins.BasePlugin):
|
||||
def on_page_markdown(self, markdown, page, **kwargs):
|
||||
page_src_path = page.file.abs_src_path
|
||||
|
||||
def found_include_tag(match):
|
||||
filename = match.group('filename')
|
||||
|
||||
file_path_abs = Path(page_src_path).parent / filename
|
||||
|
||||
if not file_path_abs.exists():
|
||||
raise ValueError('file not found', filename)
|
||||
|
||||
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'):
|
||||
text_to_include = text_to_include[:-1]
|
||||
|
||||
return text_to_include
|
||||
|
||||
def found_includemarkdown_tag(match):
|
||||
filename = match.group('filename')
|
||||
start = match.group('start')
|
||||
end = match.group('end')
|
||||
|
||||
file_path_abs = Path(page_src_path).parent / filename
|
||||
|
||||
if not file_path_abs.exists():
|
||||
raise ValueError('file not found', filename)
|
||||
|
||||
text_to_include = file_path_abs.read_text(encoding='utf8')
|
||||
|
||||
if start:
|
||||
_, _, text_to_include = text_to_include.partition(start)
|
||||
|
||||
if end:
|
||||
text_to_include, _, _ = text_to_include.partition(end)
|
||||
|
||||
return (
|
||||
'<!-- BEGIN INCLUDE %s %s %s -->\n' % (
|
||||
filename, cgi.escape(start or ''), cgi.escape(end or '')
|
||||
)
|
||||
+ text_to_include
|
||||
+ '\n<!-- END INCLUDE -->'
|
||||
)
|
||||
|
||||
markdown = re.sub(INCLUDE_TAG_REGEX, found_include_tag, markdown)
|
||||
markdown = re.sub(INCLUDEMARKDOWN_TAG_REGEX, found_includemarkdown_tag, markdown)
|
||||
return markdown
|
||||
@@ -1,15 +0,0 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='mkdocs_include_markdown_plugin',
|
||||
version='1.0',
|
||||
author='Joe Rickerby',
|
||||
license='Apache 2',
|
||||
packages=['mkdocs_include_markdown_plugin'],
|
||||
entry_points={
|
||||
'mkdocs.plugins': [
|
||||
'importmarkdown = mkdocs_include_markdown_plugin.plugin:ImportMarkdownPlugin',
|
||||
]
|
||||
},
|
||||
zip_safe=False
|
||||
)
|
||||
@@ -87,9 +87,9 @@ When setting the options, you can use shell-style globbing syntax (as per [`fnma
|
||||
| Python 3.7 | cp37-macosx_x86_64 | cp37-manylinux_x86_64 | cp37-manylinux_i686 | cp37-win_amd64 | cp37-win32 | cp37-manylinux_aarch64 | cp37-manylinux_ppc64le | cp37-manylinux_s390x |
|
||||
| Python 3.8 | cp38-macosx_x86_64 | cp38-manylinux_x86_64 | cp38-manylinux_i686 | cp38-win_amd64 | cp38-win32 | cp38-manylinux_aarch64 | cp38-manylinux_ppc64le | cp38-manylinux_s390x |
|
||||
| Python 3.9 | cp39-macosx_x86_64 | cp39-manylinux_x86_64 | cp39-manylinux_i686 | cp39-win_amd64 | cp39-win32 | cp39-manylinux_aarch64 | cp39-manylinux_ppc64le | cp39-manylinux_s390x |
|
||||
| PyPy 2.7 v7.3.2 | pp27-macosx_x86_64 | pp27-manylinux_x86_64 | | | pp27-win32 | | | |
|
||||
| PyPy 3.6 v7.3.2 | pp36-macosx_x86_64 | pp36-manylinux_x86_64 | | | pp36-win32 | | | |
|
||||
| PyPy 3.7 (alpha) v7.3.2 | pp37-macosx_x86_64 | pp37-manylinux_x86_64 | | | pp37-win32 | | | |
|
||||
| PyPy 2.7 v7.3.3 | pp27-macosx_x86_64 | pp27-manylinux_x86_64 | | | pp27-win32 | | | |
|
||||
| PyPy 3.6 v7.3.3 | pp36-macosx_x86_64 | pp36-manylinux_x86_64 | | | pp36-win32 | | | |
|
||||
| PyPy 3.7 (beta) v7.3.3 | pp37-macosx_x86_64 | pp37-manylinux_x86_64 | | | pp37-win32 | | | |
|
||||
|
||||
|
||||
The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to `cibuildwheel`.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: Working examples
|
||||
---
|
||||
|
||||
{%
|
||||
include-markdown "../README.md"
|
||||
start="<!--working-examples-start-->"
|
||||
end="<!--working-examples-end-->"
|
||||
%}
|
||||
|
||||
<style>
|
||||
.wy-nav-content {
|
||||
/* this table benefits from a wider page */
|
||||
max-width: 1000px;
|
||||
}
|
||||
.rst-content .section table img {
|
||||
/* make the icons darker on this page */
|
||||
filter: brightness(0.5);
|
||||
}
|
||||
</style>
|
||||
@@ -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.6.3
|
||||
install: python -m pip install cibuildwheel==1.7.2
|
||||
|
||||
build_script: python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
|
||||
@@ -4,9 +4,12 @@ jobs:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install cibuildwheel==1.6.3
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
pip3 install cibuildwheel==1.7.2
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
|
||||
@@ -15,11 +18,14 @@ jobs:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install cibuildwheel==1.6.3
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
python3 -m pip install cibuildwheel==1.7.2
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
inputs: {pathtoPublish: wheelhouse}
|
||||
|
||||
- job: windows
|
||||
pool: {vmImage: 'vs2017-win2016'}
|
||||
@@ -28,8 +34,11 @@ jobs:
|
||||
- script: choco install vcpython27 -f -y
|
||||
displayName: Install Visual C++ for Python 2.7
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==1.6.3
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
pip install cibuildwheel==1.7.2
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the Linux wheels.
|
||||
command: |
|
||||
pip3 install --user cibuildwheel==1.6.3
|
||||
pip3 install --user cibuildwheel==1.7.2
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
@@ -19,14 +19,13 @@ jobs:
|
||||
osx-wheels:
|
||||
working_directory: ~/osx-wheels
|
||||
macos:
|
||||
# PyPy 7.3.2 needs macOS >= 10.14
|
||||
xcode: 10.2.1
|
||||
xcode: 10.0.0
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build the OS X wheels.
|
||||
command: |
|
||||
pip3 install cibuildwheel==1.6.3
|
||||
pip3 install cibuildwheel==1.7.2
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: |
|
||||
python -m pip install cibuildwheel==1.6.3
|
||||
python -m pip install cibuildwheel==1.7.2
|
||||
|
||||
- name: Install Visual C++ for Python 2.7
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: |
|
||||
python -m pip install cibuildwheel==1.6.3
|
||||
python -m pip install cibuildwheel==1.7.2
|
||||
|
||||
- name: Install Visual C++ for Python 2.7
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -9,8 +9,6 @@ jobs:
|
||||
- services: docker
|
||||
# and a mac build
|
||||
- os: osx
|
||||
# PyPy 7.3.2 needs macOS >= 10.14
|
||||
osx_image: xcode10.2
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
@@ -21,22 +19,18 @@ jobs:
|
||||
# make sure it's on PATH as 'python3'
|
||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=__token__
|
||||
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.6.3
|
||||
- python3 -m pip install cibuildwheel==1.7.2
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
- python3 -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
after_success:
|
||||
# if the release was tagged, upload them to PyPI
|
||||
- |
|
||||
if [[ $TRAVIS_TAG ]]; then
|
||||
python3 -m pip install twine
|
||||
python3 -m twine upload wheelhouse/*.whl
|
||||
fi
|
||||
deploy:
|
||||
provider: pypi
|
||||
username: "__token__"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
password:
|
||||
secure: "" # Set to an encrypted API token. See https://docs.travis-ci.com/user/deployment/pypi/
|
||||
|
||||
@@ -15,8 +15,6 @@ jobs:
|
||||
arch: s390x
|
||||
# and a mac build
|
||||
- os: osx
|
||||
# PyPy 7.3.2 needs macOS >= 10.14
|
||||
osx_image: xcode10.2
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
@@ -28,7 +26,7 @@ jobs:
|
||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.6.3
|
||||
- python3 -m pip install cibuildwheel==1.7.2
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- stage: deploy
|
||||
name: Build and deploy Linux wheels
|
||||
services: docker
|
||||
install: python3 -m pip install cibuildwheel==1.6.3
|
||||
install: python3 -m pip install cibuildwheel==1.7.2
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
@@ -64,10 +64,8 @@ jobs:
|
||||
- stage: deploy
|
||||
name: Build and deploy macOS wheels
|
||||
os: osx
|
||||
# PyPy 7.3.2 needs macOS >= 10.14
|
||||
osx_image: xcode10.2
|
||||
language: shell
|
||||
install: python3 -m pip install cibuildwheel==1.6.3
|
||||
install: python3 -m pip install cibuildwheel==1.7.2
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
@@ -77,7 +75,7 @@ jobs:
|
||||
name: Build and deploy Windows wheels
|
||||
os: windows
|
||||
language: shell
|
||||
install: python3 -m pip install cibuildwheel==1.6.3
|
||||
install: python3 -m pip install cibuildwheel==1.7.2
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
|
||||
@@ -20,7 +20,9 @@ nav:
|
||||
- deliver-to-pypi.md
|
||||
- cpp_standards.md
|
||||
- faq.md
|
||||
- working-examples.md
|
||||
- contributing.md
|
||||
- changelog.md
|
||||
|
||||
markdown_extensions:
|
||||
- fenced_code
|
||||
@@ -32,4 +34,4 @@ markdown_extensions:
|
||||
repo_url_shortener: True
|
||||
|
||||
plugins:
|
||||
- importmarkdown
|
||||
- include-markdown
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
-e .
|
||||
-e ./docs/mkdocs_include_markdown_plugin
|
||||
pytest
|
||||
mkdocs==1.0.4
|
||||
mkdocs-include-markdown-plugin==2.1.1
|
||||
pymdown-extensions
|
||||
pip-tools
|
||||
requests
|
||||
click
|
||||
mypy
|
||||
pyyaml
|
||||
pygithub
|
||||
typing-extensions
|
||||
|
||||
@@ -11,8 +11,8 @@ long_description = (this_directory / 'README.md').read_text(encoding='utf-8')
|
||||
|
||||
setup(
|
||||
name='cibuildwheel',
|
||||
version='1.6.3',
|
||||
install_requires=['bashlex!=0.13', 'toml'],
|
||||
version='1.7.2',
|
||||
install_requires=['bashlex!=0.13', 'toml', 'certifi'],
|
||||
description="Build Python wheels on CI with minimal configuration.",
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import textwrap
|
||||
import platform
|
||||
from . import test_projects
|
||||
from . import utils
|
||||
import textwrap
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.logger import Logger
|
||||
from . import test_projects, utils
|
||||
|
||||
basic_project = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent('''
|
||||
@@ -25,6 +27,22 @@ def test(tmp_path):
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason='to keep test output clean')
|
||||
def test_sample_build(tmp_path, capfd):
|
||||
project_dir = tmp_path / 'project'
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
# build the wheels, and let the output passthrough to the caller, so
|
||||
# we can see how it looks
|
||||
with capfd.disabled():
|
||||
logger = Logger()
|
||||
logger.step('test_sample_build')
|
||||
try:
|
||||
utils.cibuildwheel_run(project_dir)
|
||||
finally:
|
||||
logger.step_end()
|
||||
|
||||
|
||||
def test_build_identifiers(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
@@ -26,10 +26,12 @@ def test(tmp_path):
|
||||
print("dummy text", file=ff)
|
||||
|
||||
# build the wheels
|
||||
before_all_command = '''python -c "import os;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))"'''
|
||||
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_BEFORE_ALL': before_all_command,
|
||||
'CIBW_BEFORE_ALL_LINUX': before_all_command + ''' && python -c "import sys; assert sys.version_info >= (3, 6)"''',
|
||||
'CIBW_ENVIRONMENT': "TEST_VAL='123'"
|
||||
})
|
||||
|
||||
|
||||
@@ -11,27 +11,34 @@ def main():
|
||||
prog="python -m test.test_projects",
|
||||
description='Generate a test project to check it out'
|
||||
)
|
||||
parser.add_argument('--open', action='store_true', help='''
|
||||
Open the generated project in a file explorer
|
||||
''')
|
||||
parser.add_argument('PROJECT', help='''
|
||||
Python path to a project object. E.g. test.test_0_basic.basic_project
|
||||
''')
|
||||
parser.add_argument('OUTPUT', nargs='?', help='''
|
||||
Path to output dir. If no dir is passed, a tempdir will be generated.
|
||||
''')
|
||||
options = parser.parse_args()
|
||||
|
||||
module, _, name = options.PROJECT.rpartition('.')
|
||||
|
||||
project = getattr(importlib.import_module(module), name)
|
||||
|
||||
project_dir = Path(tempfile.mkdtemp())
|
||||
project_dir = Path(options.OUTPUT or tempfile.mkdtemp())
|
||||
project.generate(project_dir)
|
||||
|
||||
print('Project generated at', project_dir)
|
||||
print()
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
subprocess.check_call(['open', '--', project_dir])
|
||||
elif sys.platform == 'linux2':
|
||||
subprocess.check_call(['xdg-open', '--', project_dir])
|
||||
elif sys.platform == 'win32':
|
||||
subprocess.check_call(['explorer', project_dir])
|
||||
if options.open:
|
||||
if sys.platform == 'darwin':
|
||||
subprocess.check_call(['open', '--', project_dir])
|
||||
elif sys.platform == 'linux2':
|
||||
subprocess.check_call(['xdg-open', '--', project_dir])
|
||||
elif sys.platform == 'win32':
|
||||
subprocess.check_call(['explorer', project_dir])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -103,15 +103,26 @@ def test_extras_require(tmp_path):
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
project_with_a_failing_test = test_projects.new_c_project()
|
||||
project_with_a_failing_test.files['test/spam_test.py'] = r'''
|
||||
from unittest import TestCase
|
||||
|
||||
class TestSpam(TestCase):
|
||||
def test_something(self):
|
||||
self.fail('this test is supposed to fail')
|
||||
'''
|
||||
|
||||
|
||||
def test_failing_test(tmp_path):
|
||||
"""Ensure a failing test causes cibuildwheel to error out and exit"""
|
||||
project_dir = tmp_path / 'project'
|
||||
output_dir = tmp_path / 'output'
|
||||
project_with_a_test.generate(project_dir)
|
||||
project_with_a_failing_test.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir, output_dir=output_dir, add_env={
|
||||
'CIBW_TEST_COMMAND': 'false',
|
||||
'CIBW_TEST_REQUIRES': 'nose',
|
||||
'CIBW_TEST_COMMAND': 'nosetests {project}/test',
|
||||
# manylinux1 has a version of bash that's been shown to have
|
||||
# problems with this, so let's check that.
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1',
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import certifi
|
||||
import pytest
|
||||
import ssl
|
||||
|
||||
from cibuildwheel.util import download
|
||||
|
||||
|
||||
DOWNLOAD_URL = 'https://raw.githubusercontent.com/joerick/cibuildwheel/v1.6.3/requirements-dev.txt'
|
||||
|
||||
|
||||
def test_download(monkeypatch, tmp_path):
|
||||
monkeypatch.delenv('SSL_CERT_FILE', raising=False)
|
||||
dest = tmp_path / 'file.txt'
|
||||
download(DOWNLOAD_URL, dest)
|
||||
assert len(dest.read_bytes()) == 134
|
||||
|
||||
|
||||
def test_download_good_ssl_cert_file(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv('SSL_CERT_FILE', certifi.where())
|
||||
dest = tmp_path / 'file.txt'
|
||||
download(DOWNLOAD_URL, dest)
|
||||
assert len(dest.read_bytes()) == 134
|
||||
|
||||
|
||||
def test_download_bad_ssl_cert_file(monkeypatch, tmp_path):
|
||||
bad_cafile = tmp_path / 'ca.pem'
|
||||
bad_cafile.write_text('bad certificates')
|
||||
monkeypatch.setenv('SSL_CERT_FILE', str(bad_cafile))
|
||||
dest = tmp_path / 'file.txt'
|
||||
with pytest.raises(ssl.SSLError):
|
||||
download(DOWNLOAD_URL, dest)
|
||||
@@ -11,7 +11,11 @@ def test_unknown_platform_non_ci(monkeypatch, capsys):
|
||||
monkeypatch.delenv('CI', raising=False)
|
||||
monkeypatch.delenv('BITRISE_BUILD_NUMBER', raising=False)
|
||||
monkeypatch.delenv('AZURE_HTTP_USER_AGENT', raising=False)
|
||||
monkeypatch.delenv('GITHUB_WORKFLOW', raising=False)
|
||||
monkeypatch.delenv('TRAVIS', raising=False)
|
||||
monkeypatch.delenv('APPVEYOR', raising=False)
|
||||
monkeypatch.delenv('GITHUB_ACTIONS', raising=False)
|
||||
monkeypatch.delenv('GITLAB_CI', raising=False)
|
||||
monkeypatch.delenv('CIRCLECI', raising=False)
|
||||
monkeypatch.delenv('CIBW_PLATFORM', raising=False)
|
||||
|
||||
with pytest.raises(SystemExit) as exit:
|
||||
|
||||