From 9888a6d88fb4ad6b9bc5a9c74ebb57ef52864e42 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 1 Jan 2021 18:31:04 +0100 Subject: [PATCH 1/9] use -i syntax for patch --- cibuildwheel/macos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index a96f0102..de5d7d41 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -109,7 +109,7 @@ def install_pypy(version: str, url: str) -> Path: # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if version == '2.7' else '' patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' - call(['patch', '--force', '-d', installation_path, patch_path]) + call(['patch', '--force', '-d', installation_path, '-i', patch_path]) installation_bin_path = installation_path / 'bin' python_executable = 'pypy3' if version[0] == '3' else 'pypy' From 122a0e62c260b02ab3b566ef0079fe074fcf4810 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 1 Jan 2021 19:37:06 +0100 Subject: [PATCH 2/9] use -p1 --- cibuildwheel/macos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index de5d7d41..2db1fb4c 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -109,7 +109,7 @@ def install_pypy(version: str, url: str) -> Path: # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if version == '2.7' else '' patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' - call(['patch', '--force', '-d', installation_path, '-i', patch_path]) + call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path]) installation_bin_path = installation_path / 'bin' python_executable = 'pypy3' if version[0] == '3' else 'pypy' From d3bcfe431f090f27f61f651389f2f5cbccf0ed26 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 Jan 2021 11:41:05 +0000 Subject: [PATCH 3/9] Merge pull request #506 from Czaki/macos_patch_fix Macos patch fix --- cibuildwheel/macos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index b15cf10c..ec112ee2 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -108,7 +108,7 @@ def install_pypy(version: str, url: str) -> Path: # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if version == '2.7' else '' patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' - call(['patch', '--force', '-d', installation_path, patch_path]) + call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path]) installation_bin_path = installation_path / 'bin' python_executable = 'pypy3' if version[0] == '3' else 'pypy' From 4be9285fc79b4c802d8e5f1b8ab01039ba8f0b9b Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 Jan 2021 11:47:05 +0000 Subject: [PATCH 4/9] Bump version: v1.7.4 --- README.md | 8 +++++++- cibuildwheel/__init__.py | 2 +- docs/faq.md | 4 ++-- docs/setup.md | 2 +- examples/appveyor-minimal.yml | 2 +- examples/azure-pipelines-minimal.yml | 6 +++--- examples/circleci-minimal.yml | 4 ++-- examples/github-deploy.yml | 2 +- examples/github-minimal.yml | 2 +- examples/travis-ci-deploy.yml | 2 +- examples/travis-ci-minimal.yml | 2 +- examples/travis-ci-test-and-deploy.yml | 6 +++--- setup.py | 2 +- 13 files changed, 25 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2bc84a5d..276b15a2 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ jobs: name: Install Python - name: Install cibuildwheel - run: python -m pip install cibuildwheel==1.7.3 + run: python -m pip install cibuildwheel==1.7.4 - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse @@ -270,6 +270,12 @@ Changelog +### 1.7.4 + +_2 January 2021_ + +- 🐛 Fix the PyPy virtualenv patch to work on macOS 10.14 (#506) + ### 1.7.3 _1 January 2021_ diff --git a/cibuildwheel/__init__.py b/cibuildwheel/__init__.py index 6da2111e..043606c7 100644 --- a/cibuildwheel/__init__.py +++ b/cibuildwheel/__init__.py @@ -1 +1 @@ -__version__ = '1.7.3' +__version__ = '1.7.4' diff --git a/docs/faq.md b/docs/faq.md index 58decc59..af1083b2 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -93,7 +93,7 @@ There are two suggested methods for keeping cibuildwheel up to date that instead If you use GitHub Actions for builds, you can use cibuildwheel as an action: ```yaml -uses: joerick/cibuildwheel@v1.7.3 +uses: joerick/cibuildwheel@v1.7.4 ``` This is a composite step that just installs and runs cibuildwheel. You can set command-line options as `with:` parameters, and use `env:` as normal. @@ -119,7 +119,7 @@ The second option, and the only one that supports other CI systems, is using a ` ```bash # requirements-cibw.txt -cibuildwheel==1.7.3 +cibuildwheel==1.7.4 ``` Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `dependabot.yml` file could look like this: diff --git a/docs/setup.md b/docs/setup.md index 7245a9ff..282edde9 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -17,7 +17,7 @@ For more info on this file, check out the [docs](https://help.github.com/en/acti [`examples/github-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/github-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI. -You can also use cibuildwheel directly as an action with `uses: joerick/cibuildwheel@v1.7.3`; this combines the download and run steps into a single action, and command line arguments are available via `with:`. This makes it easy to manage cibuildwheel updates via normal actions update mechanisms like dependabot, see [Automatic updates](faq.md#automatic-updates). +You can also use cibuildwheel directly as an action with `uses: joerick/cibuildwheel@v1.7.4`; this combines the download and run steps into a single action, and command line arguments are available via `with:`. This makes it easy to manage cibuildwheel updates via normal actions update mechanisms like dependabot, see [Automatic updates](faq.md#automatic-updates). # Azure Pipelines [linux/mac/windows] {: #azure-pipelines} diff --git a/examples/appveyor-minimal.yml b/examples/appveyor-minimal.yml index fd490ee2..9d909da7 100644 --- a/examples/appveyor-minimal.yml +++ b/examples/appveyor-minimal.yml @@ -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.7.3 +install: python -m pip install cibuildwheel==1.7.4 build_script: python -m cibuildwheel --output-dir wheelhouse diff --git a/examples/azure-pipelines-minimal.yml b/examples/azure-pipelines-minimal.yml index 8043a861..fd036358 100644 --- a/examples/azure-pipelines-minimal.yml +++ b/examples/azure-pipelines-minimal.yml @@ -6,7 +6,7 @@ jobs: - bash: | set -o errexit python3 -m pip install --upgrade pip - pip3 install cibuildwheel==1.7.3 + pip3 install cibuildwheel==1.7.4 displayName: Install dependencies - bash: cibuildwheel --output-dir wheelhouse . displayName: Build wheels @@ -20,7 +20,7 @@ jobs: - bash: | set -o errexit python3 -m pip install --upgrade pip - python3 -m pip install cibuildwheel==1.7.3 + python3 -m pip install cibuildwheel==1.7.4 displayName: Install dependencies - bash: cibuildwheel --output-dir wheelhouse . displayName: Build wheels @@ -36,7 +36,7 @@ jobs: - bash: | set -o errexit python -m pip install --upgrade pip - pip install cibuildwheel==1.7.3 + pip install cibuildwheel==1.7.4 displayName: Install dependencies - bash: cibuildwheel --output-dir wheelhouse . displayName: Build wheels diff --git a/examples/circleci-minimal.yml b/examples/circleci-minimal.yml index 5e09945d..54481769 100644 --- a/examples/circleci-minimal.yml +++ b/examples/circleci-minimal.yml @@ -11,7 +11,7 @@ jobs: - run: name: Build the Linux wheels. command: | - pip3 install --user cibuildwheel==1.7.3 + pip3 install --user cibuildwheel==1.7.4 cibuildwheel --output-dir wheelhouse - store_artifacts: path: wheelhouse/ @@ -25,7 +25,7 @@ jobs: - run: name: Build the OS X wheels. command: | - pip3 install cibuildwheel==1.7.3 + pip3 install cibuildwheel==1.7.4 cibuildwheel --output-dir wheelhouse - store_artifacts: path: wheelhouse/ diff --git a/examples/github-deploy.yml b/examples/github-deploy.yml index ce936fe8..1931c073 100644 --- a/examples/github-deploy.yml +++ b/examples/github-deploy.yml @@ -28,7 +28,7 @@ jobs: - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.7.3 + python -m pip install cibuildwheel==1.7.4 - name: Install Visual C++ for Python 2.7 if: runner.os == 'Windows' diff --git a/examples/github-minimal.yml b/examples/github-minimal.yml index ad18fbdc..79142dbc 100644 --- a/examples/github-minimal.yml +++ b/examples/github-minimal.yml @@ -20,7 +20,7 @@ jobs: - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.7.3 + python -m pip install cibuildwheel==1.7.4 - name: Install Visual C++ for Python 2.7 if: runner.os == 'Windows' diff --git a/examples/travis-ci-deploy.yml b/examples/travis-ci-deploy.yml index 73299b8b..bcf038d2 100644 --- a/examples/travis-ci-deploy.yml +++ b/examples/travis-ci-deploy.yml @@ -20,7 +20,7 @@ jobs: - ln -s /c/Python38/python.exe /c/Python38/python3.exe install: - - python3 -m pip install cibuildwheel==1.7.3 + - python3 -m pip install cibuildwheel==1.7.4 script: # build the wheels, put them into './wheelhouse' diff --git a/examples/travis-ci-minimal.yml b/examples/travis-ci-minimal.yml index 080b0e5c..34553a2c 100644 --- a/examples/travis-ci-minimal.yml +++ b/examples/travis-ci-minimal.yml @@ -26,7 +26,7 @@ jobs: - ln -s /c/Python38/python.exe /c/Python38/python3.exe install: - - python3 -m pip install cibuildwheel==1.7.3 + - python3 -m pip install cibuildwheel==1.7.4 script: # build the wheels, put them into './wheelhouse' diff --git a/examples/travis-ci-test-and-deploy.yml b/examples/travis-ci-test-and-deploy.yml index 58db2b02..65a706fd 100644 --- a/examples/travis-ci-test-and-deploy.yml +++ b/examples/travis-ci-test-and-deploy.yml @@ -55,7 +55,7 @@ jobs: - stage: deploy name: Build and deploy Linux wheels services: docker - install: python3 -m pip install cibuildwheel==1.7.3 + install: python3 -m pip install cibuildwheel==1.7.4 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine @@ -65,7 +65,7 @@ jobs: name: Build and deploy macOS wheels os: osx language: shell - install: python3 -m pip install cibuildwheel==1.7.3 + install: python3 -m pip install cibuildwheel==1.7.4 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine @@ -75,7 +75,7 @@ jobs: name: Build and deploy Windows wheels os: windows language: shell - install: python3 -m pip install cibuildwheel==1.7.3 + install: python3 -m pip install cibuildwheel==1.7.4 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine diff --git a/setup.py b/setup.py index 5e276555..1a0c6d89 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ long_description = (this_directory / 'README.md').read_text(encoding='utf-8') setup( name='cibuildwheel', - version='1.7.3', + version='1.7.4', install_requires=['bashlex!=0.13', 'toml', 'certifi'], description="Build Python wheels on CI with minimal configuration.", long_description=long_description, From bc8716c188b61e2cc2816a3335f6fe39726c7600 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 2 Jan 2021 11:33:38 -0500 Subject: [PATCH 5/9] refactor: setup.cfg and dev requirements (#504) * refactor: use setup.cfg instead * refactor: use dev extra * fix: restore dev requiremetns --- .circleci/prepare.sh | 2 +- .github/workflows/test.yml | 2 +- .gitlab-ci.yml | 2 +- .readthedocs.yml | 5 +++- .travis.yml | 2 +- appveyor.yml | 2 +- azure-pipelines.yml | 8 ++--- bin/bump_version.py | 2 +- docs/contributing.md | 15 ++++++++++ requirements-dev.txt | 14 +-------- setup.cfg | 61 ++++++++++++++++++++++++++++++++++++++ setup.py | 48 ++---------------------------- 12 files changed, 93 insertions(+), 70 deletions(-) diff --git a/.circleci/prepare.sh b/.circleci/prepare.sh index 7256c8c3..9e18a7de 100644 --- a/.circleci/prepare.sh +++ b/.circleci/prepare.sh @@ -4,6 +4,6 @@ set -o xtrace $PYTHON --version $PYTHON -m pip --version $PYTHON -m virtualenv -p $PYTHON venv -venv/bin/python -m pip install -r requirements-dev.txt +venv/bin/python -m pip install -e ".[dev]" venv/bin/python -m pip freeze venv/bin/python --version diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9d6f7ec..83ee1f9d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,7 @@ jobs: - name: Install dependencies run: | - python -m pip install -r requirements-dev.txt + python -m pip install -e ".[dev]" - name: Install Visual C++ for Python 2.7 if: runner.os == 'Windows' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7398bd3f..4d6cd176 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,5 +11,5 @@ linux: DOCKER_TLS_CERTDIR: "" script: - curl -sSL https://get.docker.com/ | sh - - python -m pip install -r requirements-dev.txt + - python -m pip install -e ".[dev]" - python ./bin/run_tests.py diff --git a/.readthedocs.yml b/.readthedocs.yml index 301901d8..21c669a9 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -8,4 +8,7 @@ mkdocs: python: version: 3.7 install: - - requirements: requirements-dev.txt + - method: pip + path: . + extra_requirements: + - dev diff --git a/.travis.yml b/.travis.yml index 6e4925f8..1a866ea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,6 @@ jobs: # must repeat the s390x job above exactly to match - *linux_s390x_36 -install: $PYTHON -m pip install -r requirements-dev.txt pytest-custom-exit-code +install: $PYTHON -m pip install -e ".[dev]" pytest-custom-exit-code script: $PYTHON ./bin/run_tests.py diff --git a/appveyor.yml b/appveyor.yml index acc69fdf..080908a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ init: $env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code' } -install: python -m pip install -r requirements-dev.txt pytest-custom-exit-code +install: python -m pip install -e ".[dev]" pytest-custom-exit-code # the '-u' flag is required so the output is in the correct order. # See https://github.com/joerick/cibuildwheel/pull/24 for more info. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 74dc215d..b144c2db 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -6,7 +6,7 @@ jobs: inputs: versionSpec: '3.8' - bash: | - python -m pip install -r requirements-dev.txt pytest-azurepipelines + python -m pip install -e ".[dev]" pytest-azurepipelines python ./bin/run_tests.py - job: macos_38 @@ -16,7 +16,7 @@ jobs: inputs: versionSpec: '3.8' - bash: | - python -m pip install -r requirements-dev.txt pytest-azurepipelines + python -m pip install -e ".[dev]" pytest-azurepipelines python ./bin/run_tests.py - job: windows_36 @@ -29,7 +29,7 @@ jobs: - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | - python -m pip install -r requirements-dev.txt pytest-azurepipelines + python -m pip install -e ".[dev]" pytest-azurepipelines python ./bin/run_tests.py - job: windows_38 @@ -42,5 +42,5 @@ jobs: - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | - python -m pip install -r requirements-dev.txt pytest-azurepipelines + python -m pip install -e ".[dev]" pytest-azurepipelines python ./bin/run_tests.py diff --git a/bin/bump_version.py b/bin/bump_version.py index 2330efda..4d9e6c9e 100755 --- a/bin/bump_version.py +++ b/bin/bump_version.py @@ -17,7 +17,7 @@ config = [ ('docs/faq.md', "cibuildwheel@v{}"), ('docs/setup.md', "cibuildwheel@v{}"), ('examples/*', "cibuildwheel=={}"), - ('setup.py', "version='{}'"), + ('setup.cfg', "version = {}"), ] diff --git a/docs/contributing.md b/docs/contributing.md index 98f23237..329a355c 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -32,8 +32,21 @@ So, if we can, I'd like to improve the experience on errors as well. In [this](h Maintainer notes ---------------- +## Local testing + +You should run: + +```python +python3 -m venv venv +. venv/bin/activate +pip install -e .[dev] +``` + +To prepare a development environment. + ## Testing minimal configs + cibuildwheel's _minimal_ example configs can be tested on a simple project on cibuildwheel's existing CI. These should be run whenever the minimal configs change. To test minimal configs, make sure you have a clean git repo, then run the script: @@ -48,6 +61,8 @@ The script then outputs a Markdown table that can be copy/pasted into a PR to mo ## Preparing environments +This has been moved to using docker, so you only need the following instructions if you add `--no-docker` to avoid using docker. + The dependency update script in the next section requires multiple python versions installed. One way to do this is to use `pyenv`: ```bash diff --git a/requirements-dev.txt b/requirements-dev.txt index 304cf212..aefbcb6d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,13 +1 @@ --e . -pytest -pytest-timeout -mkdocs==1.0.4 -mkdocs-include-markdown-plugin==2.1.1 -pymdown-extensions -pip-tools -requests -click -mypy -pyyaml -pygithub -typing-extensions +-e .[dev] diff --git a/setup.cfg b/setup.cfg index 8202be43..66b6ee2d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,64 @@ +[metadata] + +name = cibuildwheel +version = 1.7.4 +description = Build Python wheels on CI with minimal configuration. +long_description = file: README.md +long_description_content_type = text/markdown +author = Joe Rickerby +author_email = joerick@mac.com +url = https://github.com/joerick/cibuildwheel +license = BSD +classifiers = + Intended Audience :: Developers + Natural Language :: English + Programming Language :: Python :: 3 + Development Status :: 5 - Production/Stable + License :: OSI Approved :: BSD License + Programming Language :: Python :: Implementation :: CPython + Topic :: Software Development :: Build Tools +project_urls = + Changelog=https://github.com/joerick/cibuildwheel#changelog + Documentation=https://cibuildwheel.readthedocs.io/ +keywords = ci,wheel,packaging,pypi,travis,appveyor,macos,linux,windows + +[options] +packages = find: +zip_safe = False +include_package_data = True +python_requires = >=3.6 +install_requires = + bashlex!=0.13 + toml + certifi + +[options.package_data] +cibuildwheel = resources/* + +[options.extras_require] +dev = + click + mkdocs-include-markdown-plugin==2.1.1 + mkdocs==1.0.4 + mypy + pip-tools + pygithub + pymdown-extensions + pytest + pytest-timeout + pyyaml + requests + typing-extensions + +[options.packages.find] +include = + cibuildwheel + +[options.entry_points] +console_scripts = + cibuildwheel = cibuildwheel.__main__:main + + [flake8] ignore = E501,W503,E741,E226,B950 select = C,E,F,W,B,B9 diff --git a/setup.py b/setup.py index 1a0c6d89..b694e6e4 100644 --- a/setup.py +++ b/setup.py @@ -1,49 +1,5 @@ # -*- coding: utf-8 -*- -from pathlib import Path -try: - from setuptools import setup -except ImportError: - from distutils.core import setup +from setuptools import setup -this_directory = Path(__file__).parent -long_description = (this_directory / 'README.md').read_text(encoding='utf-8') - -setup( - name='cibuildwheel', - version='1.7.4', - 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', - author="Joe Rickerby", - author_email='joerick@mac.com', - url='https://github.com/joerick/cibuildwheel', - project_urls={ - 'Changelog': 'https://github.com/joerick/cibuildwheel#changelog', - 'Documentation': 'https://cibuildwheel.readthedocs.io/', - }, - packages=['cibuildwheel', ], - license="BSD", - zip_safe=False, - package_data={ - 'cibuildwheel': ['resources/*'], - }, - # Supported python versions - python_requires='>=3.6', - keywords='ci wheel packaging pypi travis appveyor macos linux windows', - classifiers=[ - 'Intended Audience :: Developers', - 'Natural Language :: English', - 'Programming Language :: Python :: 3', - 'Development Status :: 5 - Production/Stable', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: Implementation :: CPython', - 'Topic :: Software Development :: Build Tools', - ], - entry_points={ - 'console_scripts': [ - 'cibuildwheel = cibuildwheel.__main__:main', - ], - }, -) +setup() From 2a73fee411374af98651dbe4ff9385e3785324ab Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 2 Jan 2021 14:32:55 -0500 Subject: [PATCH 6/9] fix: enable and fix full type checking (#509) * fix: enable and fix fully type checking * chore: pre-commit autoupdate * refactor: pull types out to file --- .pre-commit-config.yaml | 8 +-- cibuildwheel/bashlex_eval.py | 6 +-- cibuildwheel/docker_container.py | 31 +++++++++--- cibuildwheel/environment.py | 2 +- cibuildwheel/linux.py | 8 +-- cibuildwheel/logger.py | 86 +++++++++++++------------------- cibuildwheel/macos.py | 10 ++-- cibuildwheel/py.typed | 0 cibuildwheel/typing.py | 11 ++++ cibuildwheel/util.py | 7 +-- cibuildwheel/windows.py | 10 ++-- setup.cfg | 18 +++++-- 12 files changed, 110 insertions(+), 87 deletions(-) create mode 100644 cibuildwheel/py.typed create mode 100644 cibuildwheel/typing.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index effe9037..a88fe59a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ repos: - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.3 + rev: 3.8.4 hooks: - id: flake8 exclude: cibuildwheel/resources/ additional_dependencies: [flake8-bugbear] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v3.4.0 hooks: - id: check-case-conflict - id: check-merge-conflict @@ -18,8 +18,8 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.782 + rev: v0.790 hooks: - id: mypy - files: ^(cibuildwheel/|test/|bin/projects.py) + files: ^(cibuildwheel/|test/|bin/projects.py|unit_test/) pass_filenames: false diff --git a/cibuildwheel/bashlex_eval.py b/cibuildwheel/bashlex_eval.py index 2c61bc54..26fe1f5b 100644 --- a/cibuildwheel/bashlex_eval.py +++ b/cibuildwheel/bashlex_eval.py @@ -1,7 +1,7 @@ import subprocess from typing import Callable, Dict, List, NamedTuple, Optional, Sequence -import bashlex # type: ignore +import bashlex # a function that takes a command and the environment, and returns the result EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str] @@ -50,7 +50,7 @@ def evaluate_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: - value = node.word + value: str = node.word for part in node.parts: part_string = context.input[part.pos[0]:part.pos[1]] @@ -95,7 +95,7 @@ def evaluate_nodes_as_compound_command(nodes: Sequence[bashlex.ast.node], contex return result -def evaluate_nodes_as_simple_command(nodes: List[bashlex.ast.node], context: NodeExecutionContext): +def evaluate_nodes_as_simple_command(nodes: List[bashlex.ast.node], context: NodeExecutionContext) -> str: command = [evaluate_node(part, context=context) for part in nodes] return context.executor(command, context.environment) diff --git a/cibuildwheel/docker_container.py b/cibuildwheel/docker_container.py index d127d01d..fb7f8d25 100644 --- a/cibuildwheel/docker_container.py +++ b/cibuildwheel/docker_container.py @@ -5,9 +5,11 @@ import shlex import subprocess import sys import uuid -from os import PathLike from pathlib import Path, PurePath -from typing import IO, Dict, List, Optional, Sequence, Union +from typing import cast, IO, Dict, List, Optional, Sequence, Type +from types import TracebackType + +from .typing import PathOrStr, PopenBytes class DockerContainer: @@ -23,14 +25,15 @@ class DockerContainer: ''' UTILITY_PYTHON = '/opt/python/cp38-cp38/bin/python' - process: subprocess.Popen + process: PopenBytes bash_stdin: IO[bytes] bash_stdout: IO[bytes] - def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[Union[str, PathLike]] = None): + def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[PathOrStr] = None): self.docker_image = docker_image self.simulate_32_bit = simulate_32_bit self.cwd = cwd + self.name: Optional[str] = None def __enter__(self) -> 'DockerContainer': self.name = f'cibuildwheel-{uuid.uuid4()}' @@ -68,11 +71,18 @@ class DockerContainer: return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> None: + self.bash_stdin.close() self.process.terminate() self.process.wait() + assert isinstance(self.name, str) + subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL) self.name = None @@ -117,8 +127,12 @@ class DockerContainer: return [PurePath(p) for p in path_strs] - def call(self, args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None, - capture_output=False, cwd: Optional[Union[str, PathLike]] = None) -> str: + def call( + self, + args: Sequence[PathOrStr], + env: Optional[Dict[str, str]] = None, + capture_output: bool = False, + cwd: Optional[PathOrStr] = None) -> str: chdir = f'cd {cwd}' if cwd else '' env_assignments = ' '.join(f'{shlex.quote(k)}={shlex.quote(v)}' @@ -178,11 +192,12 @@ class DockerContainer: return output def get_environment(self) -> Dict[str, str]: - return json.loads(self.call([ + env = json.loads(self.call([ self.UTILITY_PYTHON, '-c', 'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)' ], capture_output=True)) + return cast(Dict[str, str], env) def environment_executor(self, command: List[str], environment: Dict[str, str]) -> str: # used as an EnvironmentExecutor to evaluate commands and capture output diff --git a/cibuildwheel/environment.py b/cibuildwheel/environment.py index 5ecd8c68..fd2a824c 100644 --- a/cibuildwheel/environment.py +++ b/cibuildwheel/environment.py @@ -1,4 +1,4 @@ -import bashlex # type: ignore +import bashlex from typing import Dict, List, Mapping, Optional diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 6a553ef7..4118fd79 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -1,9 +1,8 @@ import subprocess import sys import textwrap -from os import PathLike from pathlib import Path, PurePath -from typing import List, NamedTuple, Union +from typing import List, NamedTuple from .docker_container import DockerContainer from .logger import log @@ -11,6 +10,7 @@ from .util import ( Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, get_build_verbosity_extra_flags, prepare_command, ) +from .typing import PathOrStr class PythonConfiguration(NamedTuple): @@ -19,7 +19,7 @@ class PythonConfiguration(NamedTuple): path_str: str @property - def path(self): + def path(self) -> PurePath: return PurePath(self.path_str) @@ -125,7 +125,7 @@ def build(options: BuildOptions) -> None: for config in platform_configs: log.build_start(config.identifier) - dependency_constraint_flags: List[Union[str, PathLike]] = [] + dependency_constraint_flags: List[PathOrStr] = [] if config.identifier.startswith("pp"): # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if config.version == '2.7' else '' diff --git a/cibuildwheel/logger.py b/cibuildwheel/logger.py index a8289e76..68baf298 100644 --- a/cibuildwheel/logger.py +++ b/cibuildwheel/logger.py @@ -3,7 +3,7 @@ import os import re import sys import time -from typing import Optional, Union +from typing import Optional, Union, AnyStr, IO from cibuildwheel.util import CIProvider, detect_ci_provider @@ -35,7 +35,7 @@ class Logger: step_start_time: Optional[float] = None active_fold_group_name: Optional[str] = None - def __init__(self): + def __init__(self) -> None: 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 @@ -65,7 +65,7 @@ class Logger: self.fold_mode = 'disabled' self.colors_enabled = file_supports_color(sys.stdout) - def build_start(self, identifier: str): + def build_start(self, identifier: str) -> None: self.step_end() c = self.colors description = build_description_from_identifier(identifier) @@ -77,7 +77,7 @@ class Logger: self.build_start_time = time.time() self.active_build_identifier = identifier - def build_end(self): + def build_end(self) -> None: assert self.build_start_time is not None assert self.active_build_identifier is not None self.step_end() @@ -91,12 +91,12 @@ class Logger: self.build_start_time = None self.active_build_identifier = None - def step(self, step_description: str): + def step(self, step_description: str) -> None: self.step_end() self.step_start_time = time.time() self._start_fold_group(step_description) - def step_end(self, success=True): + def step_end(self, success: bool = True) -> None: if self.step_start_time is not None: self._end_fold_group() c = self.colors @@ -109,7 +109,7 @@ class Logger: self.step_start_time = None - def error(self, error: Union[Exception, str]): + def error(self, error: Union[BaseException, str]) -> None: self.step_end(success=False) print() @@ -119,7 +119,7 @@ class Logger: c = self.colors print(f'{c.bright_red}Error{c.end} {error}') - def _start_fold_group(self, name: str): + def _start_fold_group(self, name: str) -> None: self._end_fold_group() self.active_fold_group_name = name fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0] @@ -129,7 +129,7 @@ class Logger: print() sys.stdout.flush() - def _end_fold_group(self): + def _end_fold_group(self) -> None: 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) @@ -137,7 +137,7 @@ class Logger: sys.stdout.flush() self.active_fold_group_name = None - def _fold_group_identifier(self, name: str): + def _fold_group_identifier(self, name: str) -> str: ''' Travis doesn't like fold groups identifiers that have spaces in. This method converts them to ascii identifiers @@ -152,21 +152,21 @@ class Logger: return identifier.lower()[:20] @property - def colors(self): + def colors(self) -> "Colors": if self.colors_enabled: - return Colors.enabled + return Colors(enabled=True) else: - return Colors.disabled + return Colors(enabled=False) @property - def symbols(self): + def symbols(self) -> "Symbols": if self.unicode_enabled: - return Symbols.unicode + return Symbols(unicode=True) else: - return Symbols.ascii + return Symbols(unicode=False) -def build_description_from_identifier(identifier: str): +def build_description_from_identifier(identifier: str) -> str: python_identifier, _, platform_identifier = identifier.partition('-') build_description = '' @@ -192,45 +192,31 @@ def build_description_from_identifier(identifier: str): 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' + def __init__(self, *, enabled: bool) -> None: + self.red = '\033[31m' if enabled else '' + self.green = '\033[32m' if enabled else '' + self.yellow = '\033[33m' if enabled else '' + self.blue = '\033[34m' if enabled else '' + self.cyan = '\033[36m' if enabled else '' + self.bright_red = '\033[91m' if enabled else '' + self.bright_green = '\033[92m' if enabled else '' + self.white = '\033[37m\033[97m' if enabled else '' - bg_grey = '\033[48;5;235m' + self.bg_grey = '\033[48;5;235m' if enabled else '' - bold = '\033[1m' - faint = '\033[2m' + self.bold = '\033[1m' if enabled else '' + self.faint = '\033[2m' if enabled else '' - end = '\033[0m' - - class Disabled: - def __getattr__(self, attr: str) -> str: - return '' - - enabled = Enabled() - disabled = Disabled() + self.end = '\033[0m' if enabled else '' class Symbols: - class Unicode: - done = '✓' - error = '✕' - - class Ascii: - done = 'done' - error = 'failed' - - unicode = Unicode() - ascii = Ascii() + def __init__(self, *, unicode: bool) -> None: + self.done = '✓' if unicode else 'done' + self.error = '✕' if unicode else 'failed' -def file_supports_color(file_obj): +def file_supports_color(file_obj: IO[AnyStr]) -> bool: """ Returns True if the running system's terminal supports color. """ @@ -242,11 +228,11 @@ def file_supports_color(file_obj): return (supported_platform and is_a_tty) -def file_is_a_tty(file_obj): +def file_is_a_tty(file_obj: IO[AnyStr]) -> bool: return hasattr(file_obj, 'isatty') and file_obj.isatty() -def file_supports_unicode(file_obj): +def file_supports_unicode(file_obj: IO[AnyStr]) -> bool: encoding = getattr(file_obj, 'encoding', None) if not encoding: return False diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 2db1fb4c..0845851c 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -5,18 +5,18 @@ import subprocess import sys import tempfile import textwrap -from os import PathLike from pathlib import Path -from typing import Dict, List, NamedTuple, Optional, Sequence, Union +from typing import Dict, List, NamedTuple, Optional, Sequence from .environment import ParsedEnvironment from .logger import log from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, download, get_build_verbosity_extra_flags, get_pip_script, install_certifi_script, prepare_command) +from .typing import PathOrStr -def call(args: Union[str, Sequence[Union[str, PathLike]]], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int: +def call(args: Sequence[PathOrStr], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int: # print the command executing for the logs if shell: print(f'+ {args}') @@ -120,7 +120,7 @@ def install_pypy(version: str, url: str) -> Path: def setup_python(python_configuration: PythonConfiguration, - dependency_constraint_flags: Sequence[Union[str, PathLike]], + dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment) -> Dict[str, str]: implementation_id = python_configuration.identifier.split("-")[0] log.step(f'Installing Python {implementation_id}...') @@ -209,7 +209,7 @@ def build(options: BuildOptions) -> None: for config in python_configurations: log.build_start(config.identifier) - dependency_constraint_flags: Sequence[Union[str, PathLike]] = [] + dependency_constraint_flags: Sequence[PathOrStr] = [] if options.dependency_constraints: dependency_constraint_flags = [ '-c', options.dependency_constraints.get_for_python_version(config.version) diff --git a/cibuildwheel/py.typed b/cibuildwheel/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/cibuildwheel/typing.py b/cibuildwheel/typing.py new file mode 100644 index 00000000..a3ffcfbc --- /dev/null +++ b/cibuildwheel/typing.py @@ -0,0 +1,11 @@ +from typing import Union, TYPE_CHECKING +import os +import subprocess + + +if TYPE_CHECKING: + PopenBytes = subprocess.Popen[bytes] + PathOrStr = Union[str, os.PathLike[str]] +else: + PopenBytes = subprocess.Popen + PathOrStr = Union[str, "os.PathLike[str]"] diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 70eaa44d..960b9896 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -8,14 +8,15 @@ from enum import Enum from fnmatch import fnmatch from pathlib import Path from time import sleep -from typing import Dict, List, NamedTuple, Optional, Union +from typing import Dict, List, NamedTuple, Optional import certifi from .environment import ParsedEnvironment +from .typing import PathOrStr -def prepare_command(command: str, **kwargs: Union[str, os.PathLike]) -> str: +def prepare_command(command: str, **kwargs: PathOrStr) -> str: ''' Preprocesses a command by expanding variables like {python}. @@ -119,7 +120,7 @@ class DependencyConstraints: else: return self.base_file_path - def __repr__(self): + def __repr__(self) -> str: return f'{self.__class__.__name__}{self.base_file_path!r})' diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 3abb61dd..3e977e4b 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -4,9 +4,8 @@ import subprocess import sys import tempfile import textwrap -from os import PathLike from pathlib import Path -from typing import Dict, List, NamedTuple, Optional, Sequence, Union +from typing import Dict, List, NamedTuple, Optional, Sequence from zipfile import ZipFile import toml @@ -16,12 +15,13 @@ from .logger import log from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, download, get_build_verbosity_extra_flags, get_pip_script, prepare_command) +from .typing import PathOrStr IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists() IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' -def call(args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None, +def call(args: Sequence[PathOrStr], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None) -> None: print('+ ' + ' '.join(str(a) for a in args)) # we use shell=True here, even though we don't need a shell due to a bug @@ -109,7 +109,7 @@ def install_pypy(version: str, arch: str, url: str) -> Path: return installation_path -def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[Union[str, PathLike]], environment: ParsedEnvironment) -> Dict[str, str]: +def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment) -> Dict[str, str]: nuget = Path('C:\\cibw\\nuget.exe') if not nuget.exists(): log.step('Downloading nuget...') @@ -225,7 +225,7 @@ def build(options: BuildOptions) -> None: for config in python_configurations: log.build_start(config.identifier) - dependency_constraint_flags: Sequence[Union[str, PathLike]] = [] + dependency_constraint_flags: Sequence[PathOrStr] = [] if options.dependency_constraints: dependency_constraint_flags = [ '-c', options.dependency_constraints.get_for_python_version(config.version) diff --git a/setup.cfg b/setup.cfg index 66b6ee2d..05d0ba2e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -79,12 +79,14 @@ junit_family=xunit2 [mypy] python_version = 3.6 -files = cibuildwheel,test - +files = cibuildwheel,test,unit_test warn_unused_configs = True warn_redundant_casts = True -[mypy-cibuildwheel] +[mypy-test.*] +check_untyped_defs = True + +[mypy-cibuildwheel.*,unit_test.*] disallow_any_generics = True disallow_subclassing_any = True disallow_untyped_calls = True @@ -98,5 +100,13 @@ warn_return_any = True no_implicit_reexport = True strict_equality = True -[mypy-pytest,setuptools] +[mypy-setuptools.*] +ignore_missing_imports = True + +# Ignored for pre-commit to speed up check +# Not ignored if manually running and pytest installed +[mypy-pytest.*] +ignore_missing_imports = True + +[mypy-bashlex.*] ignore_missing_imports = True From 7e80e4b0b600b5d13448be32296a9b0d97b3206e Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 2 Jan 2021 10:07:54 -0500 Subject: [PATCH 7/9] style: pyupgrade --- .pre-commit-config.yaml | 6 ++++++ bin/bump_version.py | 4 ++-- setup.py | 2 -- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a88fe59a..9e9695f6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,3 +23,9 @@ repos: - id: mypy files: ^(cibuildwheel/|test/|bin/projects.py|unit_test/) pass_filenames: false + +- repo: https://github.com/asottile/pyupgrade + rev: v2.7.4 + hooks: + - id: pyupgrade + args: ["--py36-plus"] diff --git a/bin/bump_version.py b/bin/bump_version.py index 4d9e6c9e..34b534ce 100755 --- a/bin/bump_version.py +++ b/bin/bump_version.py @@ -81,7 +81,7 @@ def bump_version(): ) if not found_at_least_one_file_needing_update: - print('error: Didn’t find any occurences of “{}” in “{}”'.format(find_pattern, path_pattern)) + print(f'error: Didn’t find any occurences of “{find_pattern}” in “{path_pattern}”') exit(1) print() @@ -94,7 +94,7 @@ def bump_version(): red="\u001b[31m", green="\u001b[32m", off="\u001b[0m" )) - print('Then commit, and tag as v{}'.format(new_version)) + print(f'Then commit, and tag as v{new_version}') answer = input('Proceed? [y/N] ').strip() diff --git a/setup.py b/setup.py index b694e6e4..60684932 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from setuptools import setup setup() From e9423a0d7f3da38c13592742632eb891f9574769 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 2 Jan 2021 19:04:47 -0500 Subject: [PATCH 8/9] style: reorder checks --- .pre-commit-config.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e9695f6..7a90bf34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,4 @@ repos: -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 - hooks: - - id: flake8 - exclude: cibuildwheel/resources/ - additional_dependencies: [flake8-bugbear] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.4.0 @@ -29,3 +23,10 @@ repos: hooks: - id: pyupgrade args: ["--py36-plus"] + +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.4 + hooks: + - id: flake8 + exclude: cibuildwheel/resources/ + additional_dependencies: [flake8-bugbear] From 42616735cf2e27585c0ae2ee45dda93b57612e2c Mon Sep 17 00:00:00 2001 From: mayeut Date: Mon, 4 Jan 2021 06:14:55 +0000 Subject: [PATCH 9/9] Update dependencies --- .../resources/pinned_docker_images.cfg | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cibuildwheel/resources/pinned_docker_images.cfg b/cibuildwheel/resources/pinned_docker_images.cfg index 9f46370d..6aa7d846 100644 --- a/cibuildwheel/resources/pinned_docker_images.cfg +++ b/cibuildwheel/resources/pinned_docker_images.cfg @@ -1,22 +1,22 @@ [x86_64] -manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-30-e2b3664 -manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-30-3161d69 -manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-30-68d3257 +manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-31-84e1e23 +manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-31-4928808 +manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-31-56195b3 [i686] -manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-30-e2b3664 -manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-30-3161d69 -manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-30-68d3257 +manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-31-84e1e23 +manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-31-4928808 +manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-31-56195b3 [pypy_x86_64] manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-12-11-f1e0e80 [aarch64] -manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-30-68d3257 +manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-31-56195b3 [ppc64le] -manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-30-68d3257 +manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-31-56195b3 [s390x] -manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-30-68d3257 +manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-31-56195b3