Skip to content

Fix Python 3.13

Fix Python 3.13 #291

Workflow file for this run

# Generated from:
# https://github.com/zopefoundation/meta/tree/master/config/c-code
###
# Initially copied from
# https://github.com/actions/starter-workflows/blob/main/ci/python-package.yml
# And later based on the version jamadden updated at
# gevent/gevent, and then at zodb/relstorage and zodb/perfmetrics
#
# Original comment follows.
###
###
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
###
###
# Important notes on GitHub actions:
#
# - We only get 2,000 free minutes a month (private repos)
# - We only get 500MB of artifact storage
# - Cache storage is limited to 7 days and 5GB.
# - macOS minutes are 10x as expensive as Linux minutes
# - windows minutes are twice as expensive.
#
# So keep those workflows light. Note: Currently, they seem to be free
# and unlimited for open source projects. But for how long...
#
# In December 2020, github only supports x86/64. If we wanted to test
# on other architectures, we can use docker emulation, but there's no
# native support. It works, but is slow.
#
# Another major downside: You can't just re-run the job for one part
# of the matrix. So if there's a transient test failure that hit, say, 3.8,
# to get a clean run every version of Python runs again. That's bad.
# https://github.community/t/ability-to-rerun-just-a-single-job-in-a-workflow/17234/65
name: tests
# Triggers the workflow on push or pull request events and periodically
on:
push:
pull_request:
schedule:
- cron: '0 12 * * 0' # run once a week on Sunday
# Allow to run this workflow manually from the Actions tab
workflow_dispatch:
env:
# Weirdly, this has to be a top-level key, not ``defaults.env``
PYTHONHASHSEED: 8675309
PYTHONUNBUFFERED: 1
PYTHONDONTWRITEBYTECODE: 1
PYTHONDEVMODE: 1
PYTHONFAULTHANDLER: 1
ZOPE_INTERFACE_STRICT_IRO: 1
PIP_UPGRADE_STRATEGY: eager
# Don't get warnings about Python 2 support being deprecated. We
# know. The env var works for pip 20.
PIP_NO_PYTHON_VERSION_WARNING: 1
PIP_NO_WARN_SCRIPT_LOCATION: 1
CFLAGS: -O3 -pipe
CXXFLAGS: -O3 -pipe
# Uploading built wheels for releases.
# TWINE_PASSWORD is encrypted and stored directly in the
# github repo settings.
TWINE_USERNAME: __token__
###
# caching
# This is where we'd set up ccache, but this compiles so fast its not worth it.
###
jobs:
# Because sharing code/steps is so hard, and because it can be
# extremely valuable to be able to get binary wheels without
# uploading to PyPI and even if there is some failure, (e.g., for
# other people to test/debug), the strategy is to divide the process
# into several different jobs. The first builds and saves the binary
# wheels. It has dependent jobs that download and install the wheel
# to run tests, build docs, and perform linting. Building the
# manylinux wheels is an independent set of jobs.
#
# This division is time-saving for projects that take awhile to
# build, but somewhat less of a clear-cut win given how quick this
# is to compile (at least at this writing).
build-package:
# Sigh. Note that the matrix must be kept in sync
# with `test`, and `docs` must use a subset.
runs-on: ${{ matrix.os }}
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
strategy:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13.0-alpha - 3.13.0"
os: [ubuntu-20.04, macos-11]
steps:
- name: checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
###
# Caching.
# This actually *restores* a cache and schedules a cleanup action
# to save the cache. So it must come before the thing we want to use
# the cache.
###
- name: Get pip cache dir
id: pip-cache
run: |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v4
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install Build Dependencies (3.13.0-alpha - 3.13.0)
if: matrix.python-version == '3.13.0-alpha - 3.13.0'
run: |
pip install -U pip
pip install -U setuptools wheel twine
# cffi will probably have no public release until a Python 3.13 beta
# or even RC release, see https://github.com/python-cffi/cffi/issues/23
echo "cffi @ git+https://github.com/python-cffi/cffi.git@954cab4f889fb019a7f90df153ee1be501495f58" > cffi_constraint.txt
PIP_CONSTRAINT=$PWD/cffi_constraint.txt pip install cffi
- name: Install Build Dependencies
if: matrix.python-version != '3.13.0-alpha - 3.13.0'
run: |
pip install -U pip
pip install -U setuptools wheel twine cffi
- name: Build AccessControl (macOS x86_64, Python 3.8+)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
env:
MACOSX_DEPLOYMENT_TARGET: 10.9
_PYTHON_HOST_PLATFORM: macosx-10.9-x86_64
ARCHFLAGS: -arch x86_64
run: |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult).
python setup.py build_ext -i
python setup.py bdist_wheel
- name: Build AccessControl (macOS arm64, Python 3.8+)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
env:
MACOSX_DEPLOYMENT_TARGET: 11.0
_PYTHON_HOST_PLATFORM: macosx-11.0-arm64
ARCHFLAGS: -arch arm64
run: |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult).
python setup.py build_ext -i
python setup.py bdist_wheel
- name: Build AccessControl (all other versions)
if: >
!startsWith(runner.os, 'Mac')
|| startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7'
run: |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult).
python setup.py build_ext -i
python setup.py bdist_wheel
- name: Install AccessControl and dependencies (3.13.0-alpha - 3.13.0)
if: matrix.python-version == '3.13.0-alpha - 3.13.0'
run: |
# Install to collect dependencies into the (pip) cache.
# cffi will probably have no public release until a Python 3.13 beta
# or even RC release, see https://github.com/python-cffi/cffi/issues/23
echo "cffi @ git+https://github.com/python-cffi/cffi.git@954cab4f889fb019a7f90df153ee1be501495f58" > cffi_constraint.txt
# Use "--pre" here because dependencies with support for this future
# Python release may only be available as pre-releases
PIP_CONSTRAINT=$PWD/cffi_constraint.txt pip install --pre .[test]
- name: Install AccessControl and dependencies
if: matrix.python-version != '3.13.0-alpha - 3.13.0'
run: |
# Install to collect dependencies into the (pip) cache.
pip install .[test]
- name: Check AccessControl build
run: |
ls -l dist
twine check dist/*
- name: Upload AccessControl wheel (macOS x86_64)
if: >
startsWith(runner.os, 'Mac')
uses: actions/upload-artifact@v4
with:
name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/*x86_64.whl
- name: Upload AccessControl wheel (macOS arm64)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
uses: actions/upload-artifact@v4
with:
# The arm64 wheel is uploaded with a different name just so it can be
# manually downloaded when desired. The wheel itself *cannot* be tested
# on the GHA runner, which uses x86_64 architecture.
name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}-arm64.whl
path: dist/*arm64.whl
- name: Upload AccessControl wheel (all other platforms)
if: >
!startsWith(runner.os, 'Mac')
uses: actions/upload-artifact@v4
with:
name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/*whl
- name: Publish package to PyPI (mac)
# We cannot 'uses: pypa/[email protected]' because
# that's apparently a container action, and those don't run on
# the Mac.
if: >
github.event_name == 'push'
&& startsWith(github.ref, 'refs/tags')
&& startsWith(runner.os, 'Mac')
&& !startsWith(matrix.python-version, 'pypy')
&& !startsWith(matrix.python-version, '3.13.0-alpha - 3.13.0')
env:
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
run: |
twine upload --skip-existing dist/*
test:
needs: build-package
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13.0-alpha - 3.13.0"
os: [ubuntu-20.04, macos-11]
steps:
- name: checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
###
# Caching.
# This actually *restores* a cache and schedules a cleanup action
# to save the cache. So it must come before the thing we want to use
# the cache.
###
- name: Get pip cache dir
id: pip-cache
run: |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v4
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}
restore-keys: |
${{ runner.os }}-pip-
- name: Download AccessControl wheel
uses: actions/download-artifact@v4
with:
name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/
- name: Install AccessControl 3.13.0-alpha - 3.13.0
if: ${{ startsWith(matrix.python-version, '3.13.0-alpha - 3.13.0') }}
run: |
pip install -U wheel setuptools
# cffi will probably have no public release until a beta or even RC
# version of Python 3.13, see https://github.com/python-cffi/cffi/issues/23
echo 'cffi @ git+https://github.com/python-cffi/cffi.git@954cab4f889fb019a7f90df153ee1be501495f58 ; platform_python_implementation == "CPython"' > cffi_constraint.txt
# coverage has a wheel on PyPI for a future python version which is
# not ABI compatible with the current one, so build it from sdist:
pip install -U --no-binary :all: coverage
# Unzip into src/ so that testrunner can find the .so files
# when we ask it to load tests from that directory. This
# might also save some build time?
unzip -n dist/AccessControl-*whl -d src
# Use "--pre" here because dependencies with support for this future
# Python release may only be available as pre-releases
PIP_CONSTRAINT=$PWD/cffi_constraint.txt pip install --pre -U -e .[test]
- name: Install AccessControl
if: ${{ !startsWith(matrix.python-version, '3.13.0-alpha - 3.13.0') }}
run: |
pip install -U wheel setuptools
pip install -U coverage
pip install -U 'cffi; platform_python_implementation == "CPython"'
# Unzip into src/ so that testrunner can find the .so files
# when we ask it to load tests from that directory. This
# might also save some build time?
unzip -n dist/AccessControl-*whl -d src
pip install -U -e .[test]
- name: Run tests with C extensions
if: ${{ !startsWith(matrix.python-version, 'pypy') }}
run: |
python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress
- name: Run tests without C extensions
run:
# coverage makes PyPy run about 3x slower!
PURE_PYTHON=1 python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress
- name: Report Coverage
run: |
coverage combine
coverage report -i
- name: Submit to Coveralls
# This is a container action, which only runs on Linux.
if: ${{ startsWith(runner.os, 'Linux') }}
uses: AndreMiras/coveralls-python-action@develop
with:
parallel: true
coveralls_finish:
needs: test
runs-on: ubuntu-20.04
steps:
- name: Coveralls Finished
uses: AndreMiras/coveralls-python-action@develop
with:
parallel-finished: true
lint:
needs: build-package
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.9"]
os: [ubuntu-20.04]
steps:
- name: checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
###
# Caching.
# This actually *restores* a cache and schedules a cleanup action
# to save the cache. So it must come before the thing we want to use
# the cache.
###
- name: Get pip cache dir
id: pip-cache
run: |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v4
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}
restore-keys: |
${{ runner.os }}-pip-
- name: Download AccessControl wheel
uses: actions/download-artifact@v4
with:
name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/
- name: Install AccessControl
run: |
pip install -U pip
pip install -U wheel
pip install -U `ls dist/AccessControl-*`[test]
- name: Lint
# We only need to do this on one version, and it should be Python 3, because
# pylint has stopped updating for Python 2.
# TODO: Pick a linter and configuration and make this step right.
run: |
pip install -U pylint
# python -m pylint --limit-inference-results=1 --rcfile=.pylintrc AccessControl -f parseable -r n
manylinux:
runs-on: ubuntu-20.04
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
# We use a regular Python matrix entry to share as much code as possible.
strategy:
matrix:
python-version: ["3.9"]
image: [manylinux2014_x86_64, manylinux2014_i686, manylinux2014_aarch64]
steps:
- name: checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
###
# Caching.
# This actually *restores* a cache and schedules a cleanup action
# to save the cache. So it must come before the thing we want to use
# the cache.
###
- name: Get pip cache dir
id: pip-cache
run: |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v4
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip_manylinux-${{ matrix.image }}-${{ matrix.python-version }}
restore-keys: |
${{ runner.os }}-pip-
- name: Update pip
run: pip install -U pip
- name: Build AccessControl (x86_64)
if: matrix.image == 'manylinux2014_x86_64'
# An alternate way to do this is to run the container directly with a uses:
# and then the script runs inside it. That may work better with caching.
# See https://github.com/pyca/bcrypt/blob/f6b5ee2eda76d077c531362ac65e16f045cf1f29/.github/workflows/wheel-builder.yml
env:
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
run: |
bash .manylinux.sh
- name: Build AccessControl (i686)
if: matrix.image == 'manylinux2014_i686'
env:
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
PRE_CMD: linux32
run: |
bash .manylinux.sh
- name: Build AccessControl (aarch64)
if: matrix.image == 'manylinux2014_aarch64'
env:
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
run: |
# First we must enable emulation
docker run --rm --privileged hypriot/qemu-register
bash .manylinux.sh
- name: Upload AccessControl wheels
uses: actions/upload-artifact@v4
with:
path: wheelhouse/*whl
name: manylinux_${{ matrix.image }}_wheels.zip
- name: Restore pip cache permissions
run: sudo chown -R $(whoami) ${{ steps.pip-cache.outputs.dir }}
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
if: >
github.event_name == 'push'
&& startsWith(github.ref, 'refs/tags')
with:
user: __token__
password: ${{ secrets.TWINE_PASSWORD }}
skip_existing: true
packages_dir: wheelhouse/