Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/python-versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ latest = "3.15"
"3.13" = { tier = "supported" }
"3.14" = { tier = "supported" }
"3.15" = { tier = "supported" }
"3.14t" = { tier = "experimental" }
"3.14t" = { tier = "supported" }

[versions.pypy]
"pypy3.10" = { tier = "ktlo" }
"pypy3.11" = { tier = "supported" }

# Experimental (#1660): free-threaded CPython (a `t` version, above) and
# GraalPy, by its release line, spelt as setup-python reads them. Each runs as
# one non-blocking leg of experimental.yml, named `(experimental)`, a workflow
# of its own that nothing waits on (#1732), and in no other matrix:
# no wheel, conda build or required context. The weekly job has no source for
# either, so it keeps these lines as written, after the other versions of their
# table. Promoting one once its leg is green is a hand edit, which
# util/python_versions.py refuses until it has all of them.
# Hand-kept (#1660): free-threaded CPython (a `t` version, above) and GraalPy,
# by its release line, spelt as setup-python reads them. The weekly job has no
# source for either, so it keeps these lines as written, after the other
# versions of their table. #1958 promoted 3.14t: supported, it runs `test`,
# `integration` and `Compat` legs with the GIL off, and no wheel or conda build
# of its own, as 3.14's wheel is the one it installs. GraalPy stays one
# non-blocking leg of experimental.yml, which nothing waits on (#1732), until
# util/python_versions.py has its wheel, conda build and Compat leg.
[versions.graalpy]
"graalpy-25.4" = { tier = "experimental" }

Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/experimental.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Experimental Tests

# The experimental tier (#1660): free-threaded CPython and GraalPy, one leg each,
# here and in no other workflow. #1732, the owner's option 2: nothing waits on
# The experimental tier (#1660): GraalPy, one leg, here and in no other workflow;
# free-threaded 3.14t left for unit-tests.yml (#1958). #1732: nothing waits on
# these legs. They used to be legs of unit-tests.yml, first of `test` and then of
# a job of their own there, and either way the Unit Tests run stayed in progress
# until GraalPy finished, up to 140 minutes. Every `workflow_run` consumer of
Expand Down Expand Up @@ -172,8 +172,8 @@ jobs:
# the tier less the round-trip sweeps, which this job did not run then (see
# `Run unit tests`), held 3.5-4.5 times as much, by per-module times from a local
# 3.14 run and the 3.14, 3.15 and 3.14t legs of run 38581834697: 88-113
# minutes on GraalPy (estimate). 3.14t, which shares the caps, took 5.8
# minutes over the whole unit tier in that run.
# minutes on GraalPy (estimate). 3.14t, then an experimental leg here, took
# 5.8 minutes over the whole unit tier in that run.
#
# #1740 gives GraalPy 3 workers, not 4, so at 4/3 of that time its tests should
# take about 117-151 minutes (an inference from the 88-113, not measured),
Expand Down Expand Up @@ -258,8 +258,8 @@ jobs:
python -c "import os; print('cpu_count', os.cpu_count())"

# #1938: the interpreter `Run unit tests` runs util/superseded.py on, a
# CPython of its own: `latest`, never the leg's GraalPy or free-threaded
# build, which would also have to take requests. `update-environment:
# CPython of its own: `latest`, never the leg's GraalPy, which would
# also have to take requests. `update-environment:
# false` leaves PATH, `pythonLocation` and `LD_LIBRARY_PATH` as the leg's
# setup-python set them, so the tests see the leg's interpreter alone;
# this one is run by its `python-path`, and finds its own libpython by
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/python-compatibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ jobs:
# showed two rows reading `Python 3.10`, one a 13-second import smoke test
# and one a three-minute test run, with nothing to tell them apart.
#
# #1633's tiers. The supported tier, 3.11-3.15, keeps the plain name,
# which is what ruleset 23497679 requires one context per version of. The
# #1633's tiers. The supported tier, 3.11-3.15 and 3.14t (#1958), keeps the
# plain name, which ruleset 23497679 requires one context per version of. The
# KTLO tier, end-of-life 3.7-3.10, is suffixed ` (KTLO)`, so no required
# context can match one. Its steps carry `continue-on-error`, as in
# unit-tests.yml's `test` job: job-level, a failed leg's check run concluded
Expand Down Expand Up @@ -121,6 +121,12 @@ jobs:
echo "::${ANNOTATION_LEVEL} title=pcapkit does not import on ${LEG//,/%2C}::See the traceback in this step's log."
exit 1
fi
# #1958: on a free-threaded build, with no PYTHON_GIL set, importing
# pcapkit and its dependencies must leave the GIL off.
if ! python -c 'import sys, sysconfig, pcapkit; sys.exit(sysconfig.get_config_var("Py_GIL_DISABLED") == 1 and sys._is_gil_enabled())'; then
echo "::${ANNOTATION_LEVEL} title=pcapkit turns the GIL on on ${LEG//,/%2C}::Importing pcapkit enabled the GIL on this free-threaded build; see the RuntimeWarning in this step's log."
exit 1
fi

# #1672: the KTLO leg's report -- the same step ends every KTLO matrix
# job; see unit-tests.yml's `test` job for how it works.
Expand Down
34 changes: 30 additions & 4 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,17 @@ jobs:
# #1672: the level of every annotation a failing step writes -- a warning on
# a KTLO leg, which must not show red, an error on a supported one. The
# steps are shared with `test-ktlo`, whose legs carry `ktlo: true`.
#
# #1958, the owner's ruling: the free-threaded leg, 3.14t, runs with the GIL
# off. `PYTHON_GIL=0` keeps it off when an extension module that does not
# declare `Py_mod_gil` is imported, as `lxml.etree` did through bs4 in every
# experimental run (docs.python.org, Command line and environment,
# PYTHON_GIL); the install leaves `lxml` out besides (see that step), and
# tests/_gil_guard.py fails the leg if a test still finds the GIL on. Empty,
# so unset to CPython, on every other leg, where `0` would be an error.
env:
ANNOTATION_LEVEL: ${{ matrix.ktlo && 'warning' || 'error' }}
PYTHON_GIL: ${{ endsWith(matrix.python-version, 't') && '0' || '' }}
strategy:
fail-fast: false
# #1660: .github/python-versions.toml's supported tier, CPython's then
Expand All @@ -122,8 +131,10 @@ jobs:
# coverage cost 1.8x on 3.15 locally (2.0x on 3.14): a step of about
# 15-19 minutes under the job's 45.
#
# The experimental tier (#1660) runs in experimental.yml, a workflow of
# its own, so that nothing here waits on it (#1732).
# Free-threaded 3.14t is a supported CPython leg since #1958, after
# CPython's others, with the GIL off (see `env` above). The experimental
# tier, GraalPy (#1660), runs in experimental.yml, a workflow of its own,
# so that nothing here waits on it (#1732).
matrix: ${{ fromJSON(needs.python-versions.outputs.test) }}

# `&test-steps`: `test-ktlo` runs these same steps, by YAML alias.
Expand Down Expand Up @@ -181,6 +192,13 @@ jobs:
# interpreter: if setup-python failed, the image's `python` would be
# tested under this leg's name. On a supported leg either fails the job;
# on a KTLO leg the annotation is a warning (#1672).
#
# #1958: a free-threaded leg uninstalls the `test` extra's `lxml`, which no
# marker can leave out. lxml 6 declares no `Py_mod_gil`, its maintainer
# reports crashes in its threading tests on 3.14t without the GIL
# (bugs.launchpad.net/lxml/+bug/2111289), and its free-threading support
# is in the 7.0 alphas alone (lxml CHANGES.txt, 7.0.0a1). So the tests
# gated on HAS_LXML skip there, each of them `LATEST` in any case.
- name: Install package and test dependencies
id: install
if: ${{ steps.python.outcome == 'success' }}
Expand All @@ -196,6 +214,9 @@ jobs:
echo "::${ANNOTATION_LEVEL} title=pcapkit did not install on ${LEG//,/%2C}::${reason//%/%25}. The rest of this leg is skipped."
exit 1
fi
if [ "$(python -c 'import sysconfig; print(sysconfig.get_config_var("Py_GIL_DISABLED"))')" = 1 ]; then
python -m pip uninstall -y lxml
fi

# #1958, the owner's ruling E: latest CPython runs the whole suite, so its
# leg installs everything the suite gates on that pip can install there --
Expand Down Expand Up @@ -436,9 +457,10 @@ jobs:
needs: [changes, python-versions]
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
timeout-minutes: 45
# See the `test` job above.
# See the `test` job above, PYTHON_GIL too.
env:
ANNOTATION_LEVEL: ${{ matrix.ktlo && 'warning' || 'error' }}
PYTHON_GIL: ${{ endsWith(matrix.python-version, 't') && '0' || '' }}
strategy:
fail-fast: false
# The supported tier of the `test` job above, without its coverage leg;
Expand Down Expand Up @@ -483,7 +505,8 @@ jobs:
# `pypcap-parity` job below covers those methods instead, on the same
# fixture-tier selection as this job but in a venv of its own.
#
# A KTLO leg that cannot install stops here, as in the `test` job above.
# A KTLO leg that cannot install stops here, as in the `test` job above,
# and a free-threaded one leaves `lxml` out, as there (#1958).
- name: Install package, test and generator dependencies
id: install
if: ${{ steps.python.outcome == 'success' }}
Expand All @@ -499,6 +522,9 @@ jobs:
echo "::${ANNOTATION_LEVEL} title=pcapkit did not install on ${LEG//,/%2C}::${reason//%/%25}. The rest of this leg is skipped."
exit 1
fi
if [ "$(python -c 'import sysconfig; print(sysconfig.get_config_var("Py_GIL_DISABLED"))')" = 1 ]; then
python -m pip uninstall -y lxml
fi

# #1958: the `test` job's step of the same name. On `latest` this job runs
# the whole fixture tier, so it installs the whole suite's set too.
Expand Down
4 changes: 2 additions & 2 deletions docs/source/contributing/releasing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Editing ``__version__`` by hand without also moving :file:`CITATION.cff`'s
(``:494-514``) asserts the two agree, and ``create-release.yml``'s
``unit-tests`` job (``:581-597``) calls ``unit-tests.yml`` with
``gate-only: true``, which runs the **full** suite rather than the tiered
subset an ordinary push runs (its ``gate`` job, ``unit-tests.yml:1798-1873``).
subset an ordinary push runs (its ``gate`` job, ``unit-tests.yml:1824-1899``).
That gate runs whenever a release will -- a moved ``__version__`` is exactly
what makes ``version_check``'s evidence read "not yet published" -- and every
publishing job requires it to have succeeded (``:621,808,974,1210``), so a
Expand All @@ -62,7 +62,7 @@ Either run the script, or move both fields by hand in the same commit.
This is the **only** edit a person makes to get a release started -- the tag,
the Release, and every upload are the workflow's job from here. Other
checks run unconditionally on the same path, though none is a step in *this*
process: the ``changelog`` job (``unit-tests.yml:1641-1667``) fails outright if
process: the ``changelog`` job (``unit-tests.yml:1667-1693``) fails outright if
``CHANGELOG.md`` has drifted from its source entry under
:file:`docs/source/changelog/`, and the release-body step warns, without
failing, if that entry's heading still reads "unreleased"
Expand Down
Loading
Loading