python/cpython
23 workflows · maturity 83% · 14 patterns · GitHub ↗
Practices
✓ Matrix✓ Permissions✓ Security scan○ AI review✓ Cache✓ Concurrency✓ Reusable workflows
Detected patterns
Security dimensions
Tools: github/codeql-action/upload-sarif
Workflows (23)
add-issue-header .github/workflows/add-issue-header.yml
View raw YAML
name: Add issue header
# Automatically edits an issue's descriptions with a header,
# one of:
#
# - Bug report
# - Crash report
# - Feature or enhancement
on:
issues:
types:
# Only ever run once
- opened
jobs:
add-header:
runs-on: ubuntu-latest
permissions:
issues: write
timeout-minutes: 5
steps:
- uses: actions/github-script@v8
with:
# language=JavaScript
script: |
// https://devguide.python.org/triage/labels/#type-labels
const HEADERS = new Map([
['type-bug', 'Bug report'],
['type-crash', 'Crash report'],
['type-feature', 'Feature or enhancement'],
]);
let issue_data = await github.rest.issues.get({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
}).then(issue => issue.data);
let header = '';
for (const label_data of issue_data.labels) {
const label_name = (typeof label_data === 'string') ? label_data : label_data.name;
if (HEADERS.has(label_name)) {
header = HEADERS.get(label_name);
break;
}
}
if (header !== '') {
console.log(`Setting new header: ${header}`);
await github.rest.issues.update({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `# ${header}\n\n${issue_data.body.replaceAll('\r', '')}`
});
}
build matrix perms .github/workflows/build.yml
View raw YAML
name: Tests
on:
workflow_dispatch:
push:
branches:
- 'main'
- '3.*'
pull_request:
branches:
- 'main'
- '3.*'
permissions:
contents: read
concurrency:
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency
# 'group' must be a key uniquely representing a PR or push event.
# github.workflow is the workflow name
# github.actor is the user invoking the workflow
# github.head_ref is the source branch of the PR or otherwise blank
# github.run_id is a unique number for the current run
group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
build-context:
name: Change detection
# To use boolean outputs from this job, parse them as JSON.
# Here's some examples:
#
# if: fromJSON(needs.build-context.outputs.run-docs)
#
# ${{
# fromJSON(needs.build-context.outputs.run-tests)
# && 'truthy-branch'
# || 'falsy-branch'
# }}
#
uses: ./.github/workflows/reusable-context.yml
check-docs:
name: Docs
needs: build-context
if: fromJSON(needs.build-context.outputs.run-docs)
uses: ./.github/workflows/reusable-docs.yml
check-autoconf-regen:
name: 'Check if Autoconf files are up to date'
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
runs-on: ubuntu-24.04
container:
image: ghcr.io/python/autoconf:2025.01.02.12581854023
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
steps:
- name: Install Git
run: |
apt update && apt install git -yq
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- uses: actions/checkout@v6
with:
fetch-depth: 1
persist-credentials: false
- name: Check Autoconf and aclocal versions
run: |
grep "Generated by GNU Autoconf 2.72" configure
grep "aclocal 1.16.5" aclocal.m4
grep -q "runstatedir" configure
grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4
- name: Regenerate autoconf files
# Same command used by Tools/build/regen-configure.sh ($AUTORECONF)
run: autoreconf -ivf -Werror
- name: Check for changes
run: |
git add -u
changes=$(git status --porcelain)
# Check for changes in regenerated files
if test -n "$changes"; then
echo "Generated files not up to date."
echo "Perhaps you forgot to run make regen-configure ;)"
echo "configure files must be regenerated with a specific version of autoconf."
echo "$changes"
echo ""
git diff --staged || true
exit 1
fi
check-generated-files:
name: 'Check if generated files are up to date'
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
runs-on: ubuntu-24.04
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure CPython
run: |
# Build Python with the libpython dynamic library
./configure --config-cache --with-pydebug --enable-shared
- name: Build CPython
run: |
make -j4 regen-all
make regen-stdlib-module-names regen-sbom
- name: Check for changes
run: |
git add -u
changes=$(git status --porcelain)
# Check for changes in regenerated files
if test -n "$changes"; then
echo "Generated files not up to date."
echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)"
echo "configure files must be regenerated with a specific version of autoconf."
echo "$changes"
echo ""
git diff --staged || true
exit 1
fi
- name: Check exported libpython symbols
run: make smelly
- name: Check limited ABI symbols
run: make check-limited-abi
- name: Check for unsupported C global variables
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
run: make check-c-globals
check-c-api-docs:
name: C API Docs
needs: build-context
if: >-
needs.build-context.outputs.run-tests == 'true'
|| needs.build-context.outputs.run-docs == 'true'
uses: ./.github/workflows/reusable-check-c-api-docs.yml
build-windows:
name: >-
Windows
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
needs: build-context
if: fromJSON(needs.build-context.outputs.run-windows-tests)
strategy:
fail-fast: false
matrix:
arch:
- x64
- Win32
- arm64
free-threading:
- false
- true
exclude:
# Skip Win32 on free-threaded builds
- { arch: Win32, free-threading: true }
uses: ./.github/workflows/reusable-windows.yml
with:
arch: ${{ matrix.arch }}
free-threading: ${{ matrix.free-threading }}
build-windows-msi:
# ${{ '' } is a hack to nest jobs under the same sidebar category.
name: Windows MSI${{ '' }} # zizmor: ignore[obfuscation]
needs: build-context
if: fromJSON(needs.build-context.outputs.run-windows-msi)
strategy:
fail-fast: false
matrix:
arch:
- x86
- x64
- arm64
uses: ./.github/workflows/reusable-windows-msi.yml
with:
arch: ${{ matrix.arch }}
build-macos:
name: >-
macOS
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
needs: build-context
if: needs.build-context.outputs.run-macos == 'true'
strategy:
fail-fast: false
matrix:
# macos-26 is Apple Silicon, macos-26-intel is Intel.
# macos-26-intel only runs tests against the GIL-enabled CPython.
os:
- macos-26
- macos-26-intel
free-threading:
- false
- true
exclude:
- os: macos-26-intel
free-threading: true
uses: ./.github/workflows/reusable-macos.yml
with:
free-threading: ${{ matrix.free-threading }}
os: ${{ matrix.os }}
build-ubuntu:
name: >-
Ubuntu
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
${{ fromJSON(matrix.bolt) && '(bolt)' || '' }}
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
strategy:
fail-fast: false
matrix:
bolt:
- false
- true
free-threading:
- false
- true
os:
- ubuntu-24.04
- ubuntu-24.04-arm
exclude:
# Do not test BOLT with free-threading, to conserve resources
- bolt: true
free-threading: true
# BOLT currently crashes during instrumentation on aarch64
- os: ubuntu-24.04-arm
bolt: true
include:
# Enable CPU-intensive tests on ARM (default build only)
- os: ubuntu-24.04-arm
bolt: false
free-threading: false
test-opts: '-u cpu'
uses: ./.github/workflows/reusable-ubuntu.yml
with:
bolt-optimizations: ${{ matrix.bolt }}
free-threading: ${{ matrix.free-threading }}
os: ${{ matrix.os }}
test-opts: ${{ matrix.test-opts || '' }}
build-ubuntu-ssltests:
name: 'Ubuntu SSL tests'
runs-on: ${{ matrix.os }}
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
ssllib:
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
## OpenSSL
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
# supported by important vendors such as AWS-LC.
- { name: openssl, version: 1.1.1w }
- { name: openssl, version: 3.0.19 }
- { name: openssl, version: 3.3.6 }
- { name: openssl, version: 3.4.4 }
- { name: openssl, version: 3.5.5 }
- { name: openssl, version: 3.6.1 }
## AWS-LC
- { name: aws-lc, version: 1.68.0 }
env:
SSLLIB_VER: ${{ matrix.ssllib.version }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
SSLLIB_DIR: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}/lib
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: 'Restore SSL library build'
id: cache-ssl-lib
uses: actions/cache@v5
with:
path: ./multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
key: ${{ matrix.os }}-multissl-${{ matrix.ssllib.name }}-${{ matrix.ssllib.version }}
- name: Install SSL Library
if: steps.cache-ssl-lib.outputs.cache-hit != 'true'
run: |
python3 Tools/ssl/multissltests.py \
--steps=library \
--base-directory "$MULTISSL_DIR" \
'--${{ matrix.ssllib.name }}' '${{ matrix.ssllib.version }}' \
--system Linux
- name: Configure CPython
run: |
./configure CFLAGS="-fdiagnostics-format=json" \
--config-cache \
--enable-slower-safety \
--with-pydebug \
--with-openssl="$SSLLIB_DIR" \
--with-builtin-hashlib-hashes=blake2 \
--with-ssl-default-suites=openssl
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Verify python is linked to the right lib
run: |
./python -c 'import ssl; print(ssl.OPENSSL_VERSION)' \
| grep -iE '${{ matrix.ssllib.name }}.*${{ matrix.ssllib.version }}'
- name: SSL tests
run: ./python Lib/test/ssltests.py
build-android:
name: Android (${{ matrix.arch }})
needs: build-context
if: needs.build-context.outputs.run-android == 'true'
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- arch: aarch64
runs-on: macos-26
- arch: x86_64
runs-on: ubuntu-24.04
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build and test
run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
build-ios:
name: iOS
needs: build-context
if: needs.build-context.outputs.run-ios == 'true'
timeout-minutes: 60
runs-on: macos-14
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
# GitHub recommends explicitly selecting the desired Xcode version:
# https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140
# This became a necessity as a result of
# https://github.com/actions/runner-images/issues/12541 and
# https://github.com/actions/runner-images/issues/12751.
- name: Select Xcode version
run: |
sudo xcode-select --switch /Applications/Xcode_15.4.app
- name: Build and test
run: python3 Platforms/Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5'
build-emscripten:
name: 'Emscripten'
needs: build-context
if: needs.build-context.outputs.run-emscripten == 'true'
uses: ./.github/workflows/reusable-emscripten.yml
build-wasi:
name: 'WASI'
needs: build-context
if: needs.build-context.outputs.run-wasi == 'true'
uses: ./.github/workflows/reusable-wasi.yml
test-hypothesis:
name: "Hypothesis tests on Ubuntu"
runs-on: ubuntu-24.04
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
env:
OPENSSL_VER: 3.5.5
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure OpenSSL env vars
run: |
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
uses: actions/cache@v5
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: Create directories for read-only out-of-tree builds
run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR"
- name: Bind mount sources read-only
run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
../cpython-ro-srcdir/configure \
--config-cache \
--with-pydebug \
--enable-slower-safety \
--with-openssl="$OPENSSL_DIR"
- name: Build CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make -j4
- name: Display build info
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make pythoninfo
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: "Create hypothesis venv"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
VENV_LOC=$(realpath -m .)/hypovenv
VENV_PYTHON=$VENV_LOC/bin/python
echo "HYPOVENV=${VENV_LOC}" >> "$GITHUB_ENV"
echo "VENV_PYTHON=${VENV_PYTHON}" >> "$GITHUB_ENV"
./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt"
- name: 'Restore Hypothesis database'
id: cache-hypothesis-database
uses: actions/cache@v5
with:
path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/
key: hypothesis-database-${{ github.head_ref || github.run_id }}
restore-keys: |
hypothesis-database-
- name: "Run tests"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
# Most of the excluded tests are slow test suites with no property tests
#
# (GH-104097) test_sysconfig is skipped because it has tests that are
# failing when executed from inside a virtual environment.
"${VENV_PYTHON}" -m test \
-W \
--slowest \
-j4 \
--timeout 900 \
-x test_asyncio \
-x test_multiprocessing_fork \
-x test_multiprocessing_forkserver \
-x test_multiprocessing_spawn \
-x test_concurrent_futures \
-x test_socket \
-x test_subprocess \
-x test_signal \
-x test_sysconfig
- uses: actions/upload-artifact@v7
if: always()
with:
name: hypothesis-example-db
path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/examples/
build-asan:
name: 'Address sanitizer'
runs-on: ${{ matrix.os }}
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
env:
OPENSSL_VER: 3.5.5
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Set up GCC-10 for ASAN
uses: egor-tensin/setup-gcc@v2
with:
version: 10
- name: Configure OpenSSL env vars
run: |
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
uses: actions/cache@v5
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Configure CPython
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc --with-openssl="$OPENSSL_DIR"
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: xvfb-run make ci
build-san:
# ${{ '' } is a hack to nest jobs under the same sidebar category.
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
strategy:
fail-fast: false
matrix:
check-name:
- Thread
free-threading:
- false
- true
sanitizer:
- TSan
include:
- check-name: Undefined behavior
sanitizer: UBSan
free-threading: false
uses: ./.github/workflows/reusable-san.yml
with:
sanitizer: ${{ matrix.sanitizer }}
free-threading: ${{ matrix.free-threading }}
cross-build-linux:
name: Cross build Linux
runs-on: ubuntu-latest
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Set build dir
run:
# an absolute path outside of the working directoy
echo "BUILD_DIR=$(realpath ${{ github.workspace }}/../build)" >> "$GITHUB_ENV"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure host build
run: ./configure --prefix="$BUILD_DIR/host-python"
- name: Install host Python
run: make -j8 install
- name: Run test subset with host build
run: |
"$BUILD_DIR/host-python/bin/python3" -m test test_sysconfig test_site test_embed
- name: Configure cross build
run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3"
- name: Install cross Python
run: make -j8 install
- name: Run test subset with host build
run: |
"$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed
cifuzz:
# ${{ '' } is a hack to nest jobs under the same sidebar category.
name: CIFuzz${{ '' }} # zizmor: ignore[obfuscation]
needs: build-context
if: >-
needs.build-context.outputs.run-ci-fuzz == 'true'
|| needs.build-context.outputs.run-ci-fuzz-stdlib == 'true'
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
sanitizer:
- address
oss-fuzz-project-name:
- cpython3
- python3-libraries
include:
- sanitizer: undefined
oss-fuzz-project-name: cpython3
- sanitizer: memory
oss-fuzz-project-name: cpython3
exclude:
# Note that the 'no-exclude' sentinel below is to prevent
# an empty string value from excluding all jobs and causing
# GHA to create a 'default' matrix entry with all empty values.
- oss-fuzz-project-name: >-
${{
needs.build-context.outputs.run-ci-fuzz == 'true'
&& 'no-exclude'
|| 'cpython3'
}}
- oss-fuzz-project-name: >-
${{
needs.build-context.outputs.run-ci-fuzz-stdlib == 'true'
&& 'no-exclude'
|| 'python3-libraries'
}}
uses: ./.github/workflows/reusable-cifuzz.yml
with:
oss-fuzz-project-name: ${{ matrix.oss-fuzz-project-name }}
sanitizer: ${{ matrix.sanitizer }}
all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
runs-on: ubuntu-latest
timeout-minutes: 5
needs:
- build-context # Transitive dependency, needed to access `run-tests` value
- check-docs
- check-autoconf-regen
- check-generated-files
- check-c-api-docs
- build-windows
- build-windows-msi
- build-macos
- build-ubuntu
- build-ubuntu-ssltests
- build-ios
- build-emscripten
- build-wasi
- test-hypothesis
- build-asan
- build-san
- cross-build-linux
- cifuzz
if: always()
steps:
- name: Check whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
build-android,
build-emscripten,
build-windows-msi,
build-ubuntu-ssltests,
test-hypothesis,
cifuzz,
allowed-skips: >-
${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
${{
needs.build-context.outputs.run-tests != 'true'
&& '
check-autoconf-regen,
check-generated-files,
'
|| ''
}}
${{
!fromJSON(needs.build-context.outputs.run-tests)
&& !fromJSON(needs.build-context.outputs.run-docs)
&& 'check-c-api-docs,'
|| ''
}}
${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
${{
!fromJSON(needs.build-context.outputs.run-ci-fuzz)
&& !fromJSON(needs.build-context.outputs.run-ci-fuzz-stdlib)
&& 'cifuzz,' ||
''
}}
${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
${{
!fromJSON(needs.build-context.outputs.run-ubuntu)
&& '
build-ubuntu,
build-ubuntu-ssltests,
test-hypothesis,
build-asan,
build-san,
cross-build-linux,
'
|| ''
}}
${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
${{ !fromJSON(needs.build-context.outputs.run-ios) && 'build-ios,' || '' }}
${{ !fromJSON(needs.build-context.outputs.run-emscripten) && 'build-emscripten,' || '' }}
${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
jobs: ${{ toJSON(needs) }}
documentation-links .github/workflows/documentation-links.yml
View raw YAML
name: Read the Docs PR preview
# Automatically edits a pull request's descriptions with a link
# to the documentation's preview on Read the Docs.
on:
pull_request_target:
types:
- opened
paths:
- 'Doc/**'
- '.github/workflows/doc.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
documentation-links:
runs-on: ubuntu-latest
permissions:
pull-requests: write
timeout-minutes: 5
steps:
- uses: readthedocs/actions/preview@v1
with:
project-slug: "cpython-previews"
single-version: "true"
jit matrix perms .github/workflows/jit.yml
View raw YAML
name: JIT
on:
pull_request:
paths: &paths
- '**jit**'
- 'Python/bytecodes.c'
- 'Python/optimizer*.c'
- 'Python/executor_cases.c.h'
- 'Python/optimizer_cases.c.h'
- '**_testinternalcapi**'
- '!Python/perf_jit_trampoline.c'
- '!**/*.md'
- '!**/*.ini'
push:
paths: *paths
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
LLVM_VERSION: 21
jobs:
interpreter:
name: Interpreter (Debug)
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build tier two interpreter
run: |
./configure --enable-experimental-jit=interpreter --with-pydebug
make all --jobs 4
- name: Test tier two interpreter
run: |
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
windows:
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
target:
- i686-pc-windows-msvc/msvc
- x86_64-pc-windows-msvc/msvc
- aarch64-pc-windows-msvc/msvc
debug:
- true
- false
include:
- target: i686-pc-windows-msvc/msvc
architecture: Win32
runner: windows-2025-vs2026
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
runner: windows-2025-vs2026
- target: aarch64-pc-windows-msvc/msvc
architecture: ARM64
runner: windows-11-arm
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
# PCbuild downloads LLVM automatically:
- name: Build
run: |
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
- name: Test
run: |
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
macos:
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
target:
- x86_64-apple-darwin/clang
- aarch64-apple-darwin/clang
debug:
- true
- false
include:
- target: x86_64-apple-darwin/clang
runner: macos-26-intel
- target: aarch64-apple-darwin/clang
runner: macos-26
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install LLVM
run: |
brew update
brew install llvm@${{ env.LLVM_VERSION }}
- name: Build
run: |
export SDKROOT="$(xcrun --show-sdk-path)"
# Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to
# make sure we don't break downstream distributors (like uv):
export CFLAGS_JIT='-Werror=unguarded-availability'
export MACOSX_DEPLOYMENT_TARGET=10.15
./configure --enable-experimental-jit --enable-universalsdk --with-universal-archs=universal2 ${{ matrix.debug && '--with-pydebug' || '' }}
make all --jobs 4
- name: Test
run: |
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
linux:
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
target:
- x86_64-unknown-linux-gnu/gcc
- aarch64-unknown-linux-gnu/gcc
debug:
- true
- false
include:
- target: x86_64-unknown-linux-gnu/gcc
runner: ubuntu-24.04
- target: aarch64-unknown-linux-gnu/gcc
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }}
make all --jobs 4
- name: Test
run: |
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
linux-extras:
name: ${{ matrix.name }}
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- name: Free-Threaded (Debug)
configure_flags: --enable-experimental-jit --with-pydebug --disable-gil
continue_on_error: true
- name: JIT without optimizations (Debug)
configure_flags: --enable-experimental-jit --with-pydebug
test_env: "PYTHON_UOPS_OPTIMIZE=0"
- name: JIT with tail calling interpreter
configure_flags: --enable-experimental-jit --with-tail-call-interp --with-pydebug
use_clang: true
run_tests: false
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
if [ "${{ matrix.use_clang }}" = "true" ]; then
export CC=clang-${{ env.LLVM_VERSION }}
fi
./configure ${{ matrix.configure_flags }}
make all --jobs 4
- name: Test
if: matrix.run_tests != false
run: |
${{ matrix.test_env }} ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
continue-on-error: ${{ matrix.continue_on_error }}
lint perms .github/workflows/lint.yml
View raw YAML
name: Lint
on: [push, pull_request, workflow_dispatch]
permissions:
contents: read
env:
FORCE_COLOR: 1
RUFF_OUTPUT_FORMAT: github
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: j178/prek-action@v1
mypy matrix perms .github/workflows/mypy.yml
View raw YAML
# Workflow to run mypy on select parts of the CPython repo
name: mypy
on:
push:
branches:
- main
pull_request:
paths:
- ".github/workflows/mypy.yml"
- "Lib/_colorize.py"
- "Lib/_pyrepl/**"
- "Lib/test/libregrtest/**"
- "Lib/tomllib/**"
- "Misc/mypy/**"
- "Tools/build/check_extension_modules.py"
- "Tools/build/check_warnings.py"
- "Tools/build/compute-changes.py"
- "Tools/build/consts_getter.py"
- "Tools/build/deepfreeze.py"
- "Tools/build/generate-build-details.py"
- "Tools/build/generate_sbom.py"
- "Tools/build/generate_stdlib_module_names.py"
- "Tools/build/mypy.ini"
- "Tools/build/umarshal.py"
- "Tools/build/update_file.py"
- "Tools/build/verify_ensurepip_wheels.py"
- "Tools/cases_generator/**"
- "Tools/check-c-api-docs/**"
- "Tools/clinic/**"
- "Tools/jit/**"
- "Tools/peg_generator/**"
- "Tools/requirements-dev.txt"
workflow_dispatch:
permissions:
contents: read
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
FORCE_COLOR: 1
TERM: xterm-256color # needed for FORCE_COLOR to work on mypy on Ubuntu, see https://github.com/python/mypy/issues/13817
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
mypy:
name: Run mypy on ${{ matrix.target }}
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
target: [
"Lib/_pyrepl",
"Lib/test/libregrtest",
"Lib/tomllib",
"Tools/build",
"Tools/cases_generator",
"Tools/check-c-api-docs",
"Tools/clinic",
"Tools/jit",
"Tools/peg_generator",
]
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: Tools/requirements-dev.txt
- run: pip install -r Tools/requirements-dev.txt
- run: python3 Misc/mypy/make_symlinks.py --symlink
- run: mypy --config-file ${{ matrix.target }}/mypy.ini
new-bugs-announce-notifier perms .github/workflows/new-bugs-announce-notifier.yml
View raw YAML
name: new-bugs-announce notifier
on:
issues:
types:
- opened
permissions:
issues: read
jobs:
notify-new-bugs-announce:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/setup-node@v6
with:
node-version: 20
- run: npm install mailgun.js form-data
- name: Send notification
uses: actions/github-script@v8
env:
MAILGUN_API_KEY: ${{ secrets.MAILGUN_PYTHON_ORG_MAILGUN_KEY }}
with:
script: |
const Mailgun = require("mailgun.js");
const formData = require('form-data');
const mailgun = new Mailgun(formData);
const DOMAIN = "mailgun.python.org";
const mg = mailgun.client({username: 'api', key: process.env.MAILGUN_API_KEY});
github.rest.issues.get({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
})
.then(function(issue) {
const payload = {
author : issue.data.user.login,
issue : issue.data.number,
title : issue.data.title,
url : issue.data.html_url,
labels : issue.data.labels.map(label => { return label.name }).join(", "),
assignee : issue.data.assignees.map(assignee => { return assignee.login }),
// We need to truncate the body size, because the max size for
// the whole payload is 16kb. We want to be safe and assume that
// body can take up to ~8kb of space.
body : (issue.data.body || "").substring(0, 8000)
};
const data = {
from: "CPython Issues <github@mailgun.python.org>",
to: "new-bugs-announce@python.org",
subject: `[Issue ${issue.data.number}] ${issue.data.title}`,
template: "new-github-issue",
'o:tracking-clicks': 'no',
'h:X-Mailgun-Variables': JSON.stringify(payload)
};
return mg.messages.create(DOMAIN, data)
})
.then(msg => console.log(msg));
require-pr-label .github/workflows/require-pr-label.yml
View raw YAML
name: Check labels
on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
jobs:
label-dnm:
name: DO-NOT-MERGE
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
permissions:
pull-requests: read
timeout-minutes: 10
steps:
- name: Check there's no DO-NOT-MERGE
uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 0
labels: |
DO-NOT-MERGE
label-reviews:
name: Unresolved review
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
permissions:
pull-requests: read
timeout-minutes: 10
steps:
# Check that the PR is not awaiting changes from the author due to previous review.
- name: Check there's no required changes
uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 0
labels: |
awaiting changes
awaiting change review
- id: is-feature
name: Check whether this PR is a feature (contains a "type-feature" label)
uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 1
labels: |
type-feature
exit_type: success # don't fail the check if the PR is not a feature, just record the result
# In case of a feature PR, check for a complete review (contains an "awaiting merge" label).
- id: awaiting-merge
if: steps.is-feature.outputs.status == 'success'
name: Check for complete review
uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 1
labels: |
awaiting merge
reusable-check-c-api-docs perms .github/workflows/reusable-check-c-api-docs.yml
View raw YAML
name: Reusable C API Docs Check
on:
workflow_call:
permissions:
contents: read
env:
FORCE_COLOR: 1
jobs:
check-c-api-docs:
name: 'Check if all C APIs are documented'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: Check for undocumented C APIs
run: python Tools/check-c-api-docs/main.py
reusable-cifuzz security .github/workflows/reusable-cifuzz.yml
View raw YAML
# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
name: Reusable CIFuzz
on:
workflow_call:
inputs:
oss-fuzz-project-name:
description: OSS-Fuzz project name
required: true
type: string
sanitizer:
description: OSS-Fuzz sanitizer
required: true
type: string
jobs:
cifuzz:
name: ${{ inputs.oss-fuzz-project-name }} (${{ inputs.sanitizer }})
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Build fuzzers (${{ inputs.sanitizer }})
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
sanitizer: ${{ inputs.sanitizer }}
- name: Run fuzzers (${{ inputs.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
fuzz-seconds: 600
oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
output-sarif: true
sanitizer: ${{ inputs.sanitizer }}
- name: Upload crash
if: failure() && steps.build.outcome == 'success'
uses: actions/upload-artifact@v7
with:
name: ${{ inputs.sanitizer }}-artifacts
path: ./out/artifacts
- name: Upload SARIF
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
reusable-context .github/workflows/reusable-context.yml
View raw YAML
name: Reusable build context
on: # yamllint disable-line rule:truthy
workflow_call:
outputs:
# Every referenced step MUST always set its output variable,
# either via ``Tools/build/compute-changes.py`` or in this workflow file.
# Boolean outputs (generally prefixed ``run-``) can then later be used
# safely through the following idiom in job conditionals and other
# expressions. Here's some examples:
#
# if: fromJSON(needs.build-context.outputs.run-tests)
#
# ${{
# fromJSON(needs.build-context.outputs.run-tests)
# && 'truthy-branch'
# || 'falsy-branch'
# }}
#
run-android:
description: Whether to run the Android tests
value: ${{ jobs.compute-changes.outputs.run-android }} # bool
run-ci-fuzz:
description: Whether to run the CIFuzz job for 'cpython' fuzzer
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
run-ci-fuzz-stdlib:
description: Whether to run the CIFuzz job for 'python3-libraries' fuzzer
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz-stdlib }} # bool
run-docs:
description: Whether to build the docs
value: ${{ jobs.compute-changes.outputs.run-docs }} # bool
run-ios:
description: Whether to run the iOS tests
value: ${{ jobs.compute-changes.outputs.run-ios }} # bool
run-macos:
description: Whether to run the macOS tests
value: ${{ jobs.compute-changes.outputs.run-macos }} # bool
run-tests:
description: Whether to run the regular tests
value: ${{ jobs.compute-changes.outputs.run-tests }} # bool
run-ubuntu:
description: Whether to run the Ubuntu tests
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
run-emscripten:
description: Whether to run the Emscripten tests
value: ${{ jobs.compute-changes.outputs.run-emscripten }} # bool
run-wasi:
description: Whether to run the WASI tests
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
run-windows-msi:
description: Whether to run the MSI installer smoke tests
value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool
run-windows-tests:
description: Whether to run the Windows tests
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
jobs:
compute-changes:
name: Create context from changed files
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
run-android: ${{ steps.changes.outputs.run-android }}
run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
run-ci-fuzz-stdlib: ${{ steps.changes.outputs.run-ci-fuzz-stdlib }}
run-docs: ${{ steps.changes.outputs.run-docs }}
run-ios: ${{ steps.changes.outputs.run-ios }}
run-macos: ${{ steps.changes.outputs.run-macos }}
run-tests: ${{ steps.changes.outputs.run-tests }}
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
run-emscripten: ${{ steps.changes.outputs.run-emscripten }}
run-wasi: ${{ steps.changes.outputs.run-wasi }}
run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
steps:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3"
- run: >-
echo '${{ github.event_name }}'
- uses: actions/checkout@v6
with:
persist-credentials: false
ref: >-
${{
github.event_name == 'pull_request'
&& github.event.pull_request.head.sha
|| ''
}}
# Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721
- name: Fetch commits to get branch diff
if: github.event_name == 'pull_request'
run: |
set -eux
# Fetch enough history to find a common ancestor commit (aka merge-base):
git fetch origin "${refspec_pr}" --depth=$(( commits + 1 )) \
--no-tags --prune --no-recurse-submodules
# This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from):
COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 "${branch_pr}" )
DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" )
# Get all commits since that commit date from the base branch (eg: main):
git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
--no-tags --prune --no-recurse-submodules
env:
branch_pr: 'origin/${{ github.event.pull_request.head.ref }}'
commits: ${{ github.event.pull_request.commits }}
refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}'
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
# We only want to run tests on PRs when related files are changed,
# or when someone triggers a manual workflow run.
- name: Compute changed files
id: changes
run: python Tools/build/compute-changes.py
env:
GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }}
CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
reusable-docs perms .github/workflows/reusable-docs.yml
View raw YAML
name: Reusable Docs
on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
build-doc:
name: 'Docs'
runs-on: ubuntu-latest
timeout-minutes: 60
env:
branch_base: 'origin/${{ github.event.pull_request.base.ref }}'
branch_pr: 'origin/${{ github.event.pull_request.head.ref }}'
commits: ${{ github.event.pull_request.commits }}
refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}'
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
steps:
- name: 'Check out latest PR branch commit'
uses: actions/checkout@v6
with:
persist-credentials: false
ref: >-
${{
github.event_name == 'pull_request'
&& github.event.pull_request.head.sha
|| ''
}}
# Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721
- name: 'Fetch commits to get branch diff'
if: github.event_name == 'pull_request'
run: |
# Fetch enough history to find a common ancestor commit (aka merge-base):
git fetch origin "${refspec_pr}" --depth=$(( commits + 1 )) \
--no-tags --prune --no-recurse-submodules
# This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from):
COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 "${branch_pr}" )
DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" )
# Get all commits since that commit date from the base branch (eg: master or main):
git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
--no-tags --prune --no-recurse-submodules
- name: 'Set up Python'
uses: actions/setup-python@v6
with:
python-version: '3'
cache: 'pip'
cache-dependency-path: 'Doc/requirements.txt'
- name: 'Install build dependencies'
run: make -C Doc/ venv
# To annotate PRs with Sphinx nitpicks (missing references)
- name: 'Build HTML documentation'
continue-on-error: true
run: |
set -Eeuo pipefail
# Build docs with the nit-picky option; write warnings to file
make -C Doc/ PYTHON=../python SPHINXOPTS="--quiet --nitpicky --warning-file sphinx-warnings.txt" html
- name: 'Check warnings'
if: github.event_name == 'pull_request'
run: |
python Doc/tools/check-warnings.py \
--annotate-diff "${branch_base}" "${branch_pr}" \
--fail-if-regression \
--fail-if-improved \
--fail-if-new-news-nit
# Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release
doctest:
name: 'Doctest'
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/cache@v5
with:
path: ~/.cache/pip
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}
restore-keys: |
ubuntu-doc-
- name: 'Install Dependencies'
run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install --no-install-recommends wamerican
- name: 'Configure CPython'
run: ./configure --with-pydebug
- name: 'Build CPython'
run: make -j4
- name: 'Install build dependencies'
run: make -C Doc/ PYTHON=../python venv
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="--fail-on-warning" doctest
check-epub:
name: 'Check EPUB'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: 'Set up Python'
uses: actions/setup-python@v6
with:
python-version: '3'
cache: 'pip'
cache-dependency-path: 'Doc/requirements.txt'
- name: 'Install build dependencies'
run: |
make -C Doc/ venv
python -m pip install epubcheck
- name: 'Build EPUB documentation'
run: make -C Doc/ PYTHON=../python epub
- name: 'Run epubcheck'
continue-on-error: true
run: epubcheck Doc/build/epub/Python.epub &> Doc/epubcheck.txt
- run: cat Doc/epubcheck.txt
- name: 'Check for fatal errors in EPUB'
run: python Doc/tools/check-epub.py
reusable-emscripten .github/workflows/reusable-emscripten.yml
View raw YAML
name: Reusable Emscripten
on:
workflow_call:
env:
FORCE_COLOR: 1
jobs:
build-emscripten-reusable:
name: 'build and test'
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: "Read Emscripten config"
id: emscripten-config
shell: python
run: |
import hashlib
import json
import os
import tomllib
from pathlib import Path
config = tomllib.loads(Path("Platforms/emscripten/config.toml").read_text())
h = hashlib.sha256()
h.update(json.dumps(config["dependencies"], sort_keys=True).encode())
h.update(Path("Platforms/emscripten/make_libffi.sh").read_bytes())
h.update(b'1') # Update to explicitly bust cache
emsdk_cache = Path(os.environ["RUNNER_TEMP"]) / "emsdk-cache"
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"emscripten-version={config['emscripten-version']}\n")
f.write(f"node-version={config['node-version']}\n")
f.write(f"deps-hash={h.hexdigest()}\n")
with open(os.environ["GITHUB_ENV"], "a") as f:
f.write(f"EMSDK_CACHE={emsdk_cache}\n")
- name: "Install Node.js"
uses: actions/setup-node@v6
with:
node-version: ${{ steps.emscripten-config.outputs.node-version }}
- name: "Cache Emscripten SDK"
id: emsdk-cache
uses: actions/cache@v5
with:
path: ${{ env.EMSDK_CACHE }}
key: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}-${{ steps.emscripten-config.outputs.deps-hash }}
restore-keys: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}
- name: "Install Python"
uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: "Runner image version"
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: "Install Emscripten"
run: python3 Platforms/emscripten install-emscripten
- name: "Configure build Python"
run: python3 Platforms/emscripten configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
run: python3 Platforms/emscripten make-build-python
- name: "Make dependencies"
run: >-
python3 Platforms/emscripten make-dependencies
${{ steps.emsdk-cache.outputs.cache-hit == 'true' && '--check-up-to-date' || '' }}
- name: "Configure host Python"
run: python3 Platforms/emscripten configure-host --host-runner node -- --config-cache
- name: "Make host Python"
run: python3 Platforms/emscripten make-host
- name: "Display build info"
run: python3 Platforms/emscripten run --pythoninfo
- name: "Test"
run: python3 Platforms/emscripten run --test
reusable-macos .github/workflows/reusable-macos.yml
View raw YAML
name: Reusable macOS
on:
workflow_call:
inputs:
free-threading:
required: false
type: boolean
default: false
os:
description: OS to run the job
required: true
type: string
env:
FORCE_COLOR: 1
jobs:
build-macos:
name: build and test (${{ inputs.os }})
runs-on: ${{ inputs.os }}
timeout-minutes: 60
env:
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Install Homebrew dependencies
run: |
brew install pkg-config openssl@3.5 xz gdbm tcl-tk@9 make
# Because alternate versions are not symlinked into place by default:
brew link --overwrite tcl-tk@9
- name: Configure CPython
run: |
MACOSX_DEPLOYMENT_TARGET=10.15 \
GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \
GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \
./configure \
--config-cache \
--with-pydebug \
--enable-slower-safety \
--enable-safety \
${{ inputs.free-threading && '--disable-gil' || '' }} \
--prefix=/opt/python-dev \
--with-openssl="$(brew --prefix openssl@3.5)"
- name: Build CPython
if : ${{ inputs.free-threading || inputs.os != 'macos-26-intel' }}
run: gmake -j8
- name: Build CPython for compiler warning check
if : ${{ !inputs.free-threading && inputs.os == 'macos-26-intel' }}
run: set -o pipefail; gmake -j8 --output-sync 2>&1 | tee compiler_output_macos.txt
- name: Display build info
run: make pythoninfo
- name: Check compiler warnings
if : ${{ !inputs.free-threading && inputs.os == 'macos-26-intel' }}
run: >-
python3 Tools/build/check_warnings.py
--compiler-output-file-path=compiler_output_macos.txt
--warning-ignore-file-path=Tools/build/.warningignore_macos
--compiler-output-type=clang
--fail-on-regression
--fail-on-improvement
--path-prefix="./"
- name: Tests
run: make ci
reusable-san .github/workflows/reusable-san.yml
View raw YAML
name: Reusable Sanitizer
on:
workflow_call:
inputs:
sanitizer:
required: true
type: string
free-threading:
description: Whether to use free-threaded mode
required: false
type: boolean
default: false
env:
FORCE_COLOR: 1
jobs:
build-san-reusable:
name: >-
${{ inputs.sanitizer }}${{
inputs.free-threading
&& ' (free-threading)'
|| ''
}}
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Install dependencies
run: |
sudo ./.github/workflows/posix-deps-apt.sh
# Install clang
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
if [ "${SANITIZER}" = "TSan" ]; then
sudo ./llvm.sh 17 # gh-121946: llvm-18 package is temporarily broken
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 100
sudo update-alternatives --set clang /usr/bin/clang-17
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-17 100
sudo update-alternatives --set clang++ /usr/bin/clang++-17
# Reduce ASLR to avoid TSan crashing
sudo sysctl -w vm.mmap_rnd_bits=28
else
sudo ./llvm.sh 20
fi
- name: Sanitizer option setup
run: |
if [ "${SANITIZER}" = "TSan" ]; then
echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{
fromJSON(inputs.free-threading)
&& '_free_threading'
|| ''
}}.txt handle_segv=0" >> "$GITHUB_ENV"
else
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION}" >> "$GITHUB_ENV"
fi
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
env:
SANITIZER: ${{ inputs.sanitizer }}
SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
- name: Configure CPython
run: >-
./configure
--config-cache
${{
inputs.sanitizer == 'TSan'
&& '--with-thread-sanitizer'
|| '--with-undefined-behavior-sanitizer'
}}
--with-pydebug
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: >-
./python -m test
${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
-j4
- name: Parallel tests
if: >-
inputs.sanitizer == 'TSan'
&& fromJSON(inputs.free-threading)
run: ./python -m test --tsan-parallel --parallel-threads=4 -j4
- name: Display logs
if: always()
run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
- name: Archive logs
if: always()
uses: actions/upload-artifact@v7
with:
name: >-
${{ inputs.sanitizer }}-logs-${{
fromJSON(inputs.free-threading)
&& 'free-threading'
|| 'default'
}}
path: san_log.*
if-no-files-found: ignore
reusable-ubuntu .github/workflows/reusable-ubuntu.yml
View raw YAML
name: Reusable Ubuntu
on:
workflow_call:
inputs:
bolt-optimizations:
description: Whether to enable BOLT optimizations
required: false
type: boolean
default: false
free-threading:
description: Whether to use free-threaded mode
required: false
type: boolean
default: false
os:
description: OS to run the job
required: true
type: string
test-opts:
description: Extra options to pass to the test runner via TESTOPTS
required: false
type: string
default: ''
env:
FORCE_COLOR: 1
jobs:
build-ubuntu-reusable:
name: build and test (${{ inputs.os }})
runs-on: ${{ inputs.os }}
timeout-minutes: 60
env:
OPENSSL_VER: 3.5.5
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Install Clang and BOLT
if: ${{ fromJSON(inputs.bolt-optimizations) }}
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 19
sudo apt-get install --no-install-recommends bolt-19
echo PATH="$(llvm-config-19 --bindir):$PATH" >> $GITHUB_ENV
- name: Configure OpenSSL env vars
run: |
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
uses: actions/cache@v5
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ inputs.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: Create directories for read-only out-of-tree builds
run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR"
- name: Bind mount sources read-only
run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
- name: Runner image version
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
# `test_unpickle_module_race` writes to the source directory, which is
# read-only during builds — so we exclude it from profiling with BOLT.
run: >-
PROFILE_TASK='-m test --pgo --ignore test_unpickle_module_race'
../cpython-ro-srcdir/configure
--config-cache
--with-pydebug
--enable-slower-safety
--enable-safety
--with-openssl="$OPENSSL_DIR"
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
${{ fromJSON(inputs.bolt-optimizations) && '--enable-bolt' || '' }}
- name: Build CPython out-of-tree
if: ${{ inputs.free-threading }}
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make -j
- name: Build CPython out-of-tree (for compiler warning check)
if: ${{ !inputs.free-threading }}
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: set -o pipefail; make -j --output-sync 2>&1 | tee compiler_output_ubuntu.txt
- name: Display build info
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make pythoninfo
- name: Check compiler warnings
if: ${{ !inputs.free-threading }}
run: >-
python Tools/build/check_warnings.py
--compiler-output-file-path="${CPYTHON_BUILDDIR}/compiler_output_ubuntu.txt"
--warning-ignore-file-path "${GITHUB_WORKSPACE}/Tools/build/.warningignore_ubuntu"
--compiler-output-type=gcc
--fail-on-regression
--fail-on-improvement
--path-prefix="../cpython-ro-srcdir/"
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw
- name: Tests
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: xvfb-run make ci EXTRATESTOPTS="${TEST_OPTS}"
env:
TEST_OPTS: ${{ inputs.test-opts }}
reusable-wasi .github/workflows/reusable-wasi.yml
View raw YAML
name: Reusable WASI
on:
workflow_call:
env:
FORCE_COLOR: 1
jobs:
build-wasi-reusable:
name: 'build and test'
runs-on: ubuntu-24.04-arm
timeout-minutes: 60
env:
WASMTIME_VERSION: 38.0.3
CROSS_BUILD_PYTHON: cross-build/build
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
# No problem resolver registered as one doesn't currently exist for Clang.
- name: "Install wasmtime"
uses: bytecodealliance/actions/wasmtime/setup@v1
with:
version: ${{ env.WASMTIME_VERSION }}
- name: "Read WASI SDK version"
id: wasi-sdk-version
run: |
import tomllib
from pathlib import Path
import os
config = tomllib.loads(Path("Platforms/WASI/config.toml").read_text())
version = config["targets"]["wasi-sdk"]
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"version={version}\n")
shell: python
- name: "Install WASI SDK"
id: install-wasi-sdk
uses: bytecodealliance/setup-wasi-sdk-action@b2de090b44eb70013ee96b393727d473b35e1728
with:
version: ${{ steps.wasi-sdk-version.outputs.version }}
add-to-path: false
- name: "Install Python"
uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: "Runner image version"
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: "Configure build Python"
run: python3 Platforms/WASI configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
run: python3 Platforms/WASI make-build-python
- name: "Configure host"
# `--with-pydebug` inferred from configure-build-python
run: python3 Platforms/WASI configure-host -- --config-cache
env:
WASI_SDK_PATH: ${{ steps.install-wasi-sdk.outputs.wasi-sdk-path }}
- name: "Make host"
run: python3 Platforms/WASI make-host
- name: "Display build info"
run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
- name: "Test"
run: make --directory "${CROSS_BUILD_WASI}" test
reusable-windows .github/workflows/reusable-windows.yml
View raw YAML
name: Reusable Windows
on:
workflow_call:
inputs:
arch:
description: CPU architecture
required: true
type: string
free-threading:
description: Whether to compile CPython in free-threading mode
required: false
type: boolean
default: false
env:
FORCE_COLOR: 1
IncludeUwp: >-
true
jobs:
build:
name: Build and test (${{ inputs.arch }})
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Register MSVC problem matcher
if: inputs.arch != 'Win32'
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: >-
.\\PCbuild\\build.bat
-e -d -v
-p "${ARCH}"
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
shell: bash
- name: Display build info
run: .\\python.bat -m test.pythoninfo
- name: Tests
run: >-
.\\PCbuild\\rt.bat
-p "${ARCH}"
-d -q --fast-ci
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
shell: bash
reusable-windows-msi perms .github/workflows/reusable-windows-msi.yml
View raw YAML
name: Reusable Windows MSI
on:
workflow_call:
inputs:
arch:
description: CPU architecture
required: true
type: string
permissions:
contents: read
env:
FORCE_COLOR: 1
jobs:
build:
name: installer for ${{ inputs.arch }}
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
IncludeFreethreaded: true
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build CPython installer
run: ./Tools/msi/build.bat --doc -"${ARCH}"
shell: bash
stale .github/workflows/stale.yml
View raw YAML
name: Mark stale pull requests
on:
schedule:
- cron: "0 */6 * * *"
jobs:
stale:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
permissions:
pull-requests: write
timeout-minutes: 10
steps:
- name: "Check PRs"
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'
stale-pr-label: 'stale'
days-before-issue-stale: -1
days-before-pr-stale: 30
days-before-close: -1
ascending: true
operations-per-run: 120
tail-call matrix perms .github/workflows/tail-call.yml
View raw YAML
name: Tail calling interpreter
on:
pull_request:
paths: &paths
- '.github/workflows/tail-call.yml'
- 'Python/bytecodes.c'
- 'Python/ceval.c'
- 'Python/ceval_macros.h'
- 'Python/generated_cases.c.h'
push:
paths: *paths
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
LLVM_VERSION: 21
jobs:
windows:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
runner: windows-2025-vs2026
build_flags: ""
run_tests: true
- target: x86_64-pc-windows-msvc/msvc-free-threading
architecture: x64
runner: windows-2025-vs2026
build_flags: --disable-gil
run_tests: false
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build
shell: pwsh
run: |
./PCbuild/build.bat --tail-call-interp ${{ matrix.build_flags }} -c Release -p ${{ matrix.architecture }}
- name: Test
if: matrix.run_tests
shell: pwsh
run: |
./PCbuild/rt.bat -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
macos:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin/clang
runner: macos-26-intel
- target: aarch64-apple-darwin/clang
runner: macos-26
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: |
brew update
brew install llvm@${{ env.LLVM_VERSION }}
- name: Build
run: |
export SDKROOT="$(xcrun --show-sdk-path)"
export PATH="/usr/local/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
export PATH="/opt/homebrew/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp
make all --jobs 4
- name: Test
run: |
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
linux:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu/gcc
runner: ubuntu-24.04
configure_flags: --with-pydebug
- target: x86_64-unknown-linux-gnu/gcc-free-threading
runner: ubuntu-24.04
configure_flags: --disable-gil
- target: aarch64-unknown-linux-gnu/gcc
runner: ubuntu-24.04-arm
configure_flags: --with-pydebug
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp ${{ matrix.configure_flags }}
make all --jobs 4
- name: Test
run: |
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
verify-ensurepip-wheels perms .github/workflows/verify-ensurepip-wheels.yml
View raw YAML
name: Verify bundled wheels
on:
workflow_dispatch:
push:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/build/verify_ensurepip_wheels.py'
pull_request:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/build/verify_ensurepip_wheels.py'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: '3'
- name: Compare checksum of bundled wheels to the ones published on PyPI
run: ./Tools/build/verify_ensurepip_wheels.py
verify-expat perms .github/workflows/verify-expat.yml
View raw YAML
name: Verify bundled libexpat
on:
workflow_dispatch:
push:
paths:
- 'Modules/expat/**'
- '.github/workflows/verify-expat.yml'
pull_request:
paths:
- 'Modules/expat/**'
- '.github/workflows/verify-expat.yml'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Download and verify bundled libexpat files
run: |
./Modules/expat/refresh.sh
git diff --exit-code Modules/expat/