Skip to content

Commit d02dfc2

Browse files
committed
setup: Use cog to automate the annual chore of updating Python versions
We must specify our supported python versions in a variety of places and formats, so use cog to update them all at once. This commit drops support for Python 3.9, which will no longer be supported by the time of the next release, and formalizes support for Python 3.14.
1 parent c2bd430 commit d02dfc2

File tree

8 files changed

+115
-31
lines changed

8 files changed

+115
-31
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ on:
2020
permissions: {}
2121

2222
env:
23+
# [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
2324
python-version: '3.13'
25+
# [[[end]]]
2426

2527
jobs:
2628
build_sdist:

.github/workflows/test.yml

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@ jobs:
2525
- uses: actions/setup-python@v5
2626
name: Install Python
2727
with:
28-
# Lint python version must be synced with tox.ini
28+
# [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
2929
python-version: '3.13'
30+
# [[[end]]]
3031
- name: Install tox
3132
run: python -m pip install tox -c requirements.txt
3233

3334
- name: Run test suite
35+
# [[[cog cog.outl(f"run: python -m tox -e py3{default_python_minor},lint")]]]
3436
run: python -m tox -e py313,lint
37+
# [[[end]]]
3538

3639
test_tox:
3740
name: Run full tests
@@ -40,34 +43,47 @@ jobs:
4043
strategy:
4144
matrix:
4245
include:
43-
- python: '3.9'
44-
tox_env: py39-full
46+
# [[[cog
47+
# configs = []
48+
# for minor in range(int(min_python_minor), int(max_python_minor) + 1):
49+
# configs.append((f"3.{minor}", f"py3{minor}-full"))
50+
# for minor in range(int(min_python_threaded_minor), int(max_python_threaded_minor) + 1):
51+
# configs.append((f"3.{minor}t", f"py3{minor}-full"))
52+
# # Early versions of 3.10 and 3.11 had different deprecation
53+
# # warnings in asyncio. Test with them too to make sure everything
54+
# # works the same way.
55+
# configs.append(("3.10.8", "py310-full"))
56+
# configs.append(("3.11.0", "py311-full"))
57+
# # Pypy is a lot slower due to jit warmup costs, so don't run the
58+
# # "full" test config there.
59+
# configs.append(("pypy-3.10", "pypy3"))
60+
# # Docs python version must be synced with tox.ini
61+
# configs.append((f"3.{default_python_minor}", "docs"))
62+
# for version, tox_env in configs:
63+
# cog.outl(f" - python: '{version}'")
64+
# cog.outl(f" tox_env: {tox_env}")
65+
# ]]]
4566
- python: '3.10'
4667
tox_env: py310-full
47-
- python: '3.10.8'
48-
# Early versions of 3.10 and 3.11 had different deprecation
49-
# warnings in asyncio. Test with them too to make sure everything
50-
# works the same way.
51-
tox_env: py310-full
5268
- python: '3.11'
5369
tox_env: py311-full
54-
- python: '3.11.0'
55-
tox_env: py311-full
5670
- python: '3.12'
5771
tox_env: py312-full
5872
- python: '3.13'
5973
tox_env: py313-full
60-
- python: '3.14.0-rc.1 - 3.14'
74+
- python: '3.14'
75+
tox_env: py314-full
76+
- python: '3.14t'
6177
tox_env: py314-full
62-
- python: '3.14t-dev'
63-
tox_env: py314t
78+
- python: '3.10.8'
79+
tox_env: py310-full
80+
- python: '3.11.0'
81+
tox_env: py311-full
6482
- python: 'pypy-3.10'
65-
# Pypy is a lot slower due to jit warmup costs, so don't run the
66-
# "full" test config there.
6783
tox_env: pypy3
6884
- python: '3.13'
69-
# Docs python version must be synced with tox.ini
7085
tox_env: docs
86+
# [[[end]]]
7187

7288
steps:
7389
- uses: actions/checkout@v4
@@ -101,7 +117,9 @@ jobs:
101117
- uses: actions/setup-python@v5
102118
name: Install Python
103119
with:
120+
# [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
104121
python-version: '3.13'
122+
# [[[end]]]
105123
- name: Run test suite
106124
# TODO: figure out what's up with these log messages
107125
run: py -m tornado.test --fail-if-logs=false
@@ -141,4 +159,6 @@ jobs:
141159
# For speed, we only build one python version and one arch. We throw away the wheels
142160
# built here; the real build is defined in build.yml.
143161
CIBW_ARCHS: native
162+
# [[[cog cog.outl(f"CIBW_BUILD: cp3{default_python_minor}-manylinux*")]]]
144163
CIBW_BUILD: cp313-manylinux*
164+
# [[[end]]]

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ installed in this way, so you may wish to download a copy of the
9999
source tarball or clone the `git repository
100100
<https://github.com/tornadoweb/tornado>`_ as well.
101101

102-
**Prerequisites**: Tornado 6.3 requires Python 3.9 or newer. The following
102+
**Prerequisites**: Tornado requires Python 3. The following
103103
optional packages may be useful:
104104

105105
* `pycurl <http://pycurl.io/>`_ is used by the optional

maint/scripts/runcog.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
3+
uvx --from cogapp cog \
4+
-D min_python_minor=10 \
5+
-D max_python_minor=14 \
6+
-D min_python_threaded_minor=14 \
7+
-D max_python_threaded_minor=14 \
8+
-D default_python_minor=13 \
9+
-r $(git grep -l '\[\[\[cog')

pyproject.toml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,21 @@ requires = ["setuptools"]
33
build-backend = "setuptools.build_meta"
44

55
[tool.black]
6-
target-version = ['py39', 'py310', 'py311', 'py312', 'py313']
6+
# [[[cog
7+
# versions = [f"py3{m}" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
8+
# cog.outl(f"target-version = {versions}")
9+
# ]]]
10+
target-version = ['py310', 'py311', 'py312', 'py313', 'py314']
11+
#[[[end]]]
712

813
[tool.cibuildwheel]
9-
build = "cp39* cp310* cp311* cp312* cp313* cp314* cp314t*"
14+
# [[[cog
15+
# versions = [f"cp3{m}*" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
16+
# versions += ["cp314t*"]
17+
# cog.outl(f"build = \"{" ".join(versions)}\"")
18+
# ]]]
19+
build = "cp310* cp311* cp312* cp313* cp314* cp314t*"
20+
#[[[end]]]
1021
test-command = "python -m tornado.test"
1122

1223
[tool.cibuildwheel.macos]

setup.cfg

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
license_file = LICENSE
33

44
[mypy]
5-
python_version = 3.9
5+
# [[[cog cog.outl(f"python_version = 3.{min_python_minor}")]]]
6+
python_version = 3.10
7+
# [[[end]]]
68
no_implicit_optional = True
79

810
[mypy-tornado.*,tornado.platform.*]

setup.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@
3939

4040
can_use_limited_api = not sysconfig.get_config_var("Py_GIL_DISABLED")
4141

42+
if can_use_limited_api:
43+
# [[[cog
44+
# cog.out(f"define_macros = [(\"Py_LIMITED_API\", ")
45+
# cog.out(f"\"0x03{int(min_python_minor):02x}0000\"")
46+
# cog.outl(")]")
47+
# cog.outl(f"bdist_wheel_options = {{\"py_limited_api\": \"cp3{min_python_minor}\"}}")
48+
# ]]]
49+
define_macros = [("Py_LIMITED_API", "0x030a0000")]
50+
bdist_wheel_options = {"py_limited_api": "cp310"}
51+
# [[[end]]]
52+
else:
53+
define_macros = []
54+
bdist_wheel_options = {}
55+
4256
# This extension builds and works on pypy as well, although pypy's jit
4357
# produces equivalent performance.
4458
kwargs["ext_modules"] = [
@@ -51,18 +65,20 @@
5165
# Use the stable ABI so our wheels are compatible across python
5266
# versions.
5367
py_limited_api=can_use_limited_api,
54-
define_macros=[("Py_LIMITED_API", "0x03090000")] if can_use_limited_api else [],
68+
define_macros=define_macros,
5569
)
5670
]
5771

58-
if can_use_limited_api:
59-
kwargs["options"] = {"bdist_wheel": {"py_limited_api": "cp39"}}
72+
if bdist_wheel_options:
73+
kwargs["options"] = {"bdist_wheel": bdist_wheel_options}
6074

6175

6276
setuptools.setup(
6377
name="tornado",
6478
version=version,
65-
python_requires=">= 3.9",
79+
# [[[cog cog.outl(f"python_requires=\">= 3.{min_python_minor}\",")]]]
80+
python_requires=">= 3.10",
81+
# [[[end]]]
6682
packages=["tornado", "tornado.test", "tornado.platform"],
6783
package_data={
6884
# data files need to be listed both here (which determines what gets
@@ -102,11 +118,16 @@
102118
classifiers=[
103119
"License :: OSI Approved :: Apache Software License",
104120
"Programming Language :: Python :: 3",
105-
"Programming Language :: Python :: 3.9",
106-
"Programming Language :: Python :: 3.10",
107-
"Programming Language :: Python :: 3.11",
108-
"Programming Language :: Python :: 3.12",
109-
"Programming Language :: Python :: 3.13",
121+
# [[[cog
122+
# for minor in range(int(min_python_minor), int(max_python_minor) + 1):
123+
# cog.outl(f"\"Programming Language :: Python :: 3.{minor}\"")
124+
# ]]]
125+
"Programming Language :: Python :: 3.10"
126+
"Programming Language :: Python :: 3.11"
127+
"Programming Language :: Python :: 3.12"
128+
"Programming Language :: Python :: 3.13"
129+
"Programming Language :: Python :: 3.14"
130+
# [[[end]]]
110131
"Programming Language :: Python :: Implementation :: CPython",
111132
"Programming Language :: Python :: Implementation :: PyPy",
112133
],

tox.ini

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
[tox]
1414
envlist =
1515
# Basic configurations: Run the tests for each python version.
16-
py39-full,py310-full,py311-full,py312-full,py313-full,py314-full,py314t,pypy3-full
16+
# [[[cog
17+
# versions = [f"py3{m}" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
18+
# versions += ["pypy3"]
19+
# cog.outl(','.join(versions))
20+
# ]]]
21+
py310,py311,py312,py313,py314,pypy3
22+
# [[[end]]]
1723

1824
# Build and test the docs with sphinx.
1925
docs
@@ -29,8 +35,13 @@ basepython =
2935
# linter warning-suppression comments go), so we specify a
3036
# python version for these builds.
3137
# These versions must be synced with the versions in .github/workflows/test.yml
38+
# [[[cog
39+
# cog.outl(f"docs: python3.{default_python_minor}")
40+
# cog.outl(f"lint: python3.{default_python_minor}")
41+
# ]]]
3242
docs: python3.13
3343
lint: python3.13
44+
# [[[end]]]
3445

3546
deps =
3647
full: pycurl
@@ -41,7 +52,13 @@ deps =
4152

4253
setenv =
4354
# Treat the extension as mandatory in testing (but not on pypy)
44-
{py3,py39,py310,py311,py312,py313,py314,py314t}: TORNADO_EXTENSION=1
55+
# [[[cog
56+
# versions = [f"py3{m}" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
57+
# versions.insert(0, "py3")
58+
# cog.outl(f"{{{",".join(versions)}}}: TORNADO_EXTENSION=1")
59+
# ]]]
60+
{py3,py310,py311,py312,py313,py314}: TORNADO_EXTENSION=1
61+
# [[[end]]]
4562
# CI workers are often overloaded and can cause our tests to exceed
4663
# the default timeout of 5s.
4764
ASYNC_TEST_TIMEOUT=25
@@ -113,5 +130,7 @@ commands =
113130
# something new than of depending on something old and deprecated.
114131
# But sometimes something we depend on gets removed so we should also
115132
# test the newest version.
133+
# [[[cog cog.outl(f"env -u PYTHONWARNDEFAULTENCODING mypy --platform linux --python-version 3.{default_python_minor} {{posargs:tornado}}")]]]
116134
env -u PYTHONWARNDEFAULTENCODING mypy --platform linux --python-version 3.13 {posargs:tornado}
135+
# [[[end]]]
117136
changedir = {toxinidir}

0 commit comments

Comments
 (0)