Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Free-threaded/noGIL Python 3.13t testing experiment #659

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8632a9d
Test against NumPy nightlies
agriyakhetarpal Sep 25, 2024
59bbdab
Merge branch 'master' into feat/nightly-numpy-tests
agriyakhetarpal Oct 15, 2024
1b0c3da
Split into a nightly test job, rework the workflow
agriyakhetarpal Oct 15, 2024
6358800
Merge branch 'master' into feat/nightly-numpy-tests
agriyakhetarpal Oct 16, 2024
b48ebd0
Fix type demotion issue in `combo_check`
agriyakhetarpal Dec 1, 2024
2ae5302
Merge branch 'master' into feat/nightly-numpy-tests
agriyakhetarpal Dec 1, 2024
e384483
Enforce binary wheels are downloaded from SPNW
agriyakhetarpal Dec 1, 2024
c6b8a41
Add a free-threading nox session
agriyakhetarpal Dec 2, 2024
79124bd
Add a noGIL job with forked `setup-python`
agriyakhetarpal Dec 2, 2024
331d9b8
Document `free-threading` `nox` session
agriyakhetarpal Dec 2, 2024
6fb016b
Set `PYTHON_GIL` to `0` for the test suite
agriyakhetarpal Dec 2, 2024
a381e47
Explicitly disable GIL fallback for workflow
agriyakhetarpal Dec 2, 2024
98bd2dc
For now, don't set PYTHON_GIL env var in GHA job
agriyakhetarpal Dec 2, 2024
119d8ee
Don't use coverage plugin or xdist for free-threaded tests
agriyakhetarpal Dec 14, 2024
b2a246f
Remove required plugins, migrate additional options
agriyakhetarpal Dec 14, 2024
7c0ca36
Add more free-threaded testing via plugins
agriyakhetarpal Dec 14, 2024
587813d
Merge branch 'master' into feat/free-threading-tests
agriyakhetarpal Dec 14, 2024
3a4d6c6
Fix typo in test command
agriyakhetarpal Dec 14, 2024
c7a9f47
Add two more sessions for pytest plugins
agriyakhetarpal Dec 14, 2024
55ab962
Add GHA matrix for free-threaded plugin execution
agriyakhetarpal Dec 14, 2024
aff687d
Fix typo in pytest-run-parallel plugin name
agriyakhetarpal Dec 14, 2024
b79abab
Fix bad pytest invocation
agriyakhetarpal Dec 14, 2024
f8735dd
Run both plugins for 100 iterations
agriyakhetarpal Dec 14, 2024
c70f7ef
Remove unneeded `UV_NO_CACHE` env var
agriyakhetarpal Dec 14, 2024
2cf7b09
Run for 10 and 100 iterations respectively
agriyakhetarpal Dec 14, 2024
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
42 changes: 42 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,45 @@ jobs:
- uses: yezz123/setup-uv@v4
- name: Run tests against nightly wheels for NumPy and SciPy
run: uvx nox -s nightly-tests

# In this job, we test with the free-threaded (no-GIL) Python 3.13t
# interpreter on all platforms. This is a special job and uses the
# "free-threading" session in noxfile.py. This job is available only
# for Python 3.13t at the time of writing and uses the nightly wheels
# for NumPy and SciPy, since free-threaded builds for either of them
# are not available on PyPI yet.
free-threaded-testing:
name: "Free-threading tests / ${{ matrix.platform }} / Python ${{ matrix.python-version }} / Plugin ${{ matrix.plugin }}"
runs-on: ${{ matrix.platform }}
# Temporarily disable this environment variable to see if this fixes the message as follows:
# "Fatal Python error: config_read_gil: Disabling the GIL is not supported by this build"
# env:
# PYTHON_GIL: "0"
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-13, macos-latest, windows-latest]
python-version: ["3.13t"]
plugin: ["none", "pytest-run-parallel", "pytest-freethreaded"]
steps:
- uses: actions/[email protected]
- uses: Quansight-Labs/setup-python@b9ab292c751a42bcd2bb465b7fa202ea2c3f5796 # v5.3.1
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- uses: yezz123/setup-uv@ab6be5a42627f19dc36e57b548592a5e52cece4a # v4.1

# 1) Test suite with free-threading enabled, but no free-threading-specific plugins
- name: Run free-threaded tests on ${{ matrix.platform}}
if: ${{ matrix.plugin == 'none' }}
run: uvx nox -s free-threading

# 2) Test suite with free-threading enabled, plus pytest-run-parallel plugin
- name: Run free-threaded tests with ${{ matrix.plugin }} on ${{ matrix.platform}}
if: ${{ matrix.plugin == 'pytest-run-parallel' }}
run: uvx nox -s free-threading-pytest-run-parallel -- -sra --parallel-threads 5 --iterations 10

# 3) Test suite with free-threading enabled, plus pytest-freethreaded plugin
- name: Run free-threaded tests with ${{ matrix.plugin }} on ${{ matrix.platform}}
if: ${{ matrix.plugin == 'pytest-freethreaded' }}
run: uvx nox -s free-threading-pytest-freethreaded -- -sra --threads 5 --iterations 100
17 changes: 9 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ pip install nox

## Run tests, linting, packaging checks

| Command | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nox --list` | Lists all available Nox sessions, including selected ones |
| `nox -s lint` | Runs code style checks with pre-commit and pre-commit hooks as listed in `.pre-commit-config.yaml`. Accepts posargs to pass additional arguments to the linter. |
| `nox -s tests` | Runs tests with your default Python interpreter. Accepts posargs to pass additional arguments and configuration to `pytest`. |
| `nox -s nightly-tests` | Similar to `nox -s tests`, except that it runs tests with nightly versions of dependencies (NumPy, SciPy, etc.). |
| `nox -s validate-package` | Builds a source distribution and a wheel using `pypa/build` and checks the package with `twine` in strict mode. |
| `nox` | Runs all selected sessions, as listed in `nox.options.sessions` in `noxfile.py`. |
| Command | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nox --list` | Lists all available Nox sessions, including selected ones |
| `nox -s lint` | Runs code style checks with pre-commit and pre-commit hooks as listed in `.pre-commit-config.yaml`. Accepts posargs to pass additional arguments to the linter. |
| `nox -s tests` | Runs tests with your default Python interpreter. Accepts posargs to pass additional arguments and configuration to `pytest`. |
| `nox -s nightly-tests` | Similar to `nox -s tests`, except that it runs tests with nightly versions of dependencies (NumPy, SciPy, etc.). |
| `nox -s free-threading` | Similar to `nox -s nightly-tests`, except that it runs tests with a free-threaded Python interpreter and corresponding builds for dependencies (NumPy, SciPy, etc.). |
| `nox -s validate-package` | Builds a source distribution and a wheel using `pypa/build` and checks the package with `twine` in strict mode. |
| `nox` | Runs all selected sessions, as listed in `nox.options.sessions` in `noxfile.py`. |

Additionally, `nox` supports tags to run specific sessions, e.g., `nox --tags tests` runs all sessions tagged with `tests`.

Expand Down
88 changes: 85 additions & 3 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"UV_INDEX_URL": NIGHTLY_INDEX_URL,
"UV_PRERELEASE": "allow",
"UV_INDEX_STRATEGY": "first-index",
"UV_NO_CACHE": "true",
}

nox.needs_version = ">=2024.4.15"
Expand All @@ -34,7 +33,9 @@ def run_tests(session):
session.install("-e", ".[test]", silent=False)
else:
session.install("-e", ".[test,scipy]", silent=False)
session.run("pytest", "--cov=autograd", "--cov-report=xml", "--cov-append", *session.posargs)
session.run(
"pytest", "-n", "auto", "--cov=autograd", "--cov-report=xml", "--cov-append", *session.posargs
)


@nox.session(name="lint", reuse_venv=True)
Expand All @@ -47,6 +48,7 @@ def ruff(session):
@nox.session(name="nightly-tests", tags=["tests"])
def run_nightly_tests(session):
"""Run tests against nightly versions of dependencies"""
session.run("python", "-VV")
session.install("-e", ".[test]", silent=False)
# SciPy doesn't have wheels on PyPy
if platform.python_implementation() == "PyPy":
Expand All @@ -57,4 +59,84 @@ def run_nightly_tests(session):
session.install(
"numpy", "scipy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
session.run("pytest", "--cov=autograd", "--cov-report=xml", "--cov-append", *session.posargs)
session.run(
"pytest", "-n", "auto", "--cov=autograd", "--cov-report=xml", "--cov-append", *session.posargs
)


# Wheels for NumPy and SciPy are available as nightly builds, so we test
# against them on Python 3.13t, which is the only version that supports
# free-threaded Python. This session is similar to the "nightly-tests"
# session, but it uses a free-threaded Python interpreter. Also, we don't
# the "test" extra but install the test dependencies manually.
#
# When the PYTHON_GIL environment variable is set to 0, we enforce that
# extension modules that haven't declared themselves as safe to not rely
# on the GIL are run with the GIL disabled.
@nox.session(name="free-threading", python=["3.13t"])
def run_with_free_threaded_python(session):
"""Run tests with free threaded Python (no-GIL)"""
session.run("python", "-VV")
session.install("-e", ".", silent=False)
session.install("pytest", silent=False)

# SciPy doesn't have wheels on PyPy
if platform.python_implementation() == "PyPy":
session.install(
"numpy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
else:
session.install(
"numpy", "scipy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
session.run(
"pytest",
*session.posargs,
env={"PYTHON_GIL": "0"},
)


@nox.session(name="free-threading-pytest-run-parallel", python=["3.13t"])
def run_pytest_run_in_parallel_plugin(session):
"""Run stress tests with free threaded Python (no-GIL) using the pytest-run-in-parallel plugin"""
session.run("python", "-VV")
session.install("-e", ".", silent=False)
session.install("pytest", "pytest-run-parallel", silent=False)

# SciPy doesn't have wheels on PyPy
if platform.python_implementation() == "PyPy":
session.install(
"numpy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
else:
session.install(
"numpy", "scipy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
session.run(
"pytest",
*session.posargs,
env={"PYTHON_GIL": "0"},
)


@nox.session(name="free-threading-pytest-freethreaded", python=["3.13t"])
def run_pytest_freethreaded(session):
"""Run stress tests with free threaded Python (no-GIL) using the pytest-freethreaded plugin"""
session.run("python", "-VV")
session.install("-e", ".", silent=False)
session.install("pytest", "pytest-freethreaded", silent=False)

# SciPy doesn't have wheels on PyPy
if platform.python_implementation() == "PyPy":
session.install(
"numpy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
else:
session.install(
"numpy", "scipy", "--upgrade", "--only-binary", ":all:", silent=False, env=UV_NIGHTLY_ENV_VARS
)
session.run(
"pytest",
*session.posargs,
env={"PYTHON_GIL": "0"},
)
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,9 @@ source = ["autograd"]
[tool.coverage.report]
show_missing = true

[tool.pytest.ini_options]
required_plugins = ["pytest-cov", "pytest-xdist"]
# TODO: generate HTML report, upload to CodeCov
addopts = "--color=yes -sra -n auto --cov=autograd --cov-report=xml --cov-report=term"
[tool.pytest.ini_options]
addopts = "--color=yes -sra"

[tool.ruff]
extend-exclude = []
Expand Down
Loading