Skip to content
Merged
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python -m pytest t

PRs must pass `pytest --cov` on the CI matrix (Python 3.12 **and** 3.13). There
is no black/ruff/flake8 gate — formatting is advisory. (`requires-python` in
`pyproject.toml` is `>=3.9`.)
`pyproject.toml` is `>=3.12`.)

## Public API

Expand Down
42 changes: 25 additions & 17 deletions autonerves/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,32 @@ def _emit_python_version_warning():
return

py = f"{current[0]}.{current[1]}"
lines = [
f"PyAuto: Python {py} detected -- first-class support is 3.12 and 3.13.",
"",
f"Things will probably work fine on {py}, but it is not the recommended",
"version and you may hit edge cases.",
]
if current < (3, 11):
lines.extend(
[
"",
"Note: JAX acceleration is not available on Python <3.11. Models",
"that pass use_jax=True will error.",
]
if current < (3, 12):
lines = [
f"PyAuto: Python {py} detected -- Python 3.12 or newer is required.",
"",
"This Python version is unsupported by current PyAuto releases.",
"Install Python 3.12 or 3.13, or pin a pre-migration PyAuto release.",
]
warning = (
f"PyAuto: running on unsupported Python {py}; current releases "
"require Python >=3.12."
)
else:
lines = [
f"PyAuto: Python {py} detected -- this Python version is experimental.",
"",
"PyAuto currently tests and supports Python 3.12 and 3.13.",
f"Python {py} may encounter known compatibility issues.",
"Use Python 3.12 or 3.13 for production work.",
]
warning = (
f"PyAuto: running on experimental Python {py}; supported versions "
"are 3.12/3.13."
)
lines.extend(
[
"",
"Recommended: install Python 3.12 or 3.13.",
"To silence this warning, add to <cwd>/config/general.yaml:",
"",
" version:",
Expand All @@ -76,9 +84,9 @@ def _emit_python_version_warning():

print("\n".join(framed), file=sys.stderr)
warnings.warn(
f"PyAuto: running on Python {py}; first-class support is 3.12/3.13. "
f"Suppress this warning via 'version.python_version_check: False' in "
f"config/general.yaml.",
warning
+ " Suppress this warning via 'version.python_version_check: False' "
"in config/general.yaml.",
UserWarning,
stacklevel=2,
)
Expand Down
14 changes: 5 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version"]
description = "PyAuto Configration"
readme = { file = "README.md", content-type = "text/markdown" }
license = { text = "MIT" }
requires-python = ">=3.9"
requires-python = ">=3.12"
authors = [
{ name = "James Nightingale", email = "James.Nightingale@newcastle.ac.uk" },
{ name = "Richard Hayes", email = "richard@rghsoftware.co.uk" },
Expand All @@ -18,15 +18,11 @@ classifiers = [
"Topic :: Scientific/Engineering :: Physics",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13"
]
keywords = ["cli"]
dependencies = [
"pathlib",
"typing-inspect>=0.4.0",
"PyYAML>=6.0.1",
"numpy>=1.24.0,<3.0.0"
Expand All @@ -47,9 +43,9 @@ local_scheme = "no-local-version"

[project.optional-dependencies]
jax = [
"jax>=0.7.0,<0.11.0; python_version >= '3.11'",
"jaxlib>=0.7.0,<0.11.0; python_version >= '3.11'",
"jaxnnls==1.0.1; python_version >= '3.11'"
"jax>=0.7.0,<0.11.0",
"jaxlib>=0.7.0,<0.11.0",
"jaxnnls==1.0.1"
]
optional = [
"autonerves[jax]",
Expand All @@ -63,4 +59,4 @@ testpaths = ["test_autonerves"]
filterwarnings = [
"ignore:cuda_plugin_extension:UserWarning",
"ignore::DeprecationWarning:jax",
]
]
78 changes: 78 additions & 0 deletions test_autonerves/test_python_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import sys
from types import SimpleNamespace
import warnings

import pytest

import autonerves


def _set_python_version(monkeypatch, major, minor):
monkeypatch.setattr(
autonerves,
"sys",
SimpleNamespace(version_info=(major, minor), stderr=sys.stderr),
)
monkeypatch.setattr(
autonerves,
"_python_version_check_bypassed",
lambda: False,
)


@pytest.mark.parametrize("minor", [12, 13])
def test_supported_python_versions_do_not_warn(monkeypatch, capsys, minor):
_set_python_version(monkeypatch, major=3, minor=minor)

with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
autonerves._emit_python_version_warning()

assert caught == []
assert capsys.readouterr().err == ""


def test_python_below_minimum_is_reported_as_unsupported(monkeypatch, capsys):
_set_python_version(monkeypatch, major=3, minor=11)

with pytest.warns(UserWarning, match=r"require Python >=3\.12"):
autonerves._emit_python_version_warning()

message = capsys.readouterr().err
assert "Python 3.12 or newer is required" in message
assert "unsupported by current PyAuto releases" in message
assert "pre-migration PyAuto release" in message


def test_python_above_supported_range_is_reported_as_experimental(monkeypatch, capsys):
_set_python_version(monkeypatch, major=3, minor=14)

with pytest.warns(UserWarning, match=r"experimental Python 3\.14"):
autonerves._emit_python_version_warning()

message = capsys.readouterr().err
assert "Python 3.14 detected -- this Python version is experimental" in message
assert "tests and supports Python 3.12 and 3.13" in message
assert "Use Python 3.12 or 3.13 for production work" in message


def test_python_version_warning_respects_yaml_bypass(monkeypatch, tmp_path, capsys):
config_path = tmp_path / "config"
config_path.mkdir()
(config_path / "general.yaml").write_text(
"version:\n python_version_check: false\n"
)
monkeypatch.chdir(tmp_path)
monkeypatch.setattr(
autonerves,
"sys",
SimpleNamespace(version_info=(3, 14)),
)

with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
autonerves._emit_python_version_warning()

assert autonerves._python_version_check_bypassed() is True
assert caught == []
assert capsys.readouterr().err == ""
Loading