]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
setup: Use cog to automate the annual chore of updating Python versions 3536/head
authorBen Darnell <ben@bendarnell.com>
Wed, 20 Aug 2025 18:37:14 +0000 (14:37 -0400)
committerBen Darnell <ben@bendarnell.com>
Wed, 20 Aug 2025 20:44:34 +0000 (16:44 -0400)
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.

.github/workflows/build.yml
.github/workflows/test.yml
docs/index.rst
maint/scripts/runcog.sh [new file with mode: 0755]
pyproject.toml
setup.cfg
setup.py
tox.ini

index 8355230ffcbaaacfe4d57c82b66d6de7724978c6..e8e1a2cf7cb2f1730c958e9bc2552d8067d6ef18 100644 (file)
@@ -20,7 +20,9 @@ on:
 permissions: {}
 
 env:
+  # [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
   python-version: '3.13'
+  # [[[end]]]
 
 jobs:
   build_sdist:
index 5b89c3b61bc5612b99eedfbfb30b7d140e9156bb..e6d7ac3e40f7b0da6fdefbba43ae5cf57c8ed1e2 100644 (file)
@@ -25,13 +25,16 @@ jobs:
       - uses: actions/setup-python@v5
         name: Install Python
         with:
-          # Lint python version must be synced with tox.ini
+          # [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
           python-version: '3.13'
+          # [[[end]]]
       - name: Install tox
         run: python -m pip install tox -c requirements.txt
 
       - name: Run test suite
+        # [[[cog cog.outl(f"run: python -m tox -e py3{default_python_minor},lint")]]]
         run: python -m tox -e py313,lint
+        # [[[end]]]
 
   test_tox:
     name: Run full tests
@@ -40,34 +43,58 @@ jobs:
     strategy:
       matrix:
         include:
-          - python: '3.9'
-            tox_env: py39-full
+          # [[[cog
+          #    configs  = []
+          #    for minor in range(int(min_python_minor), int(max_python_minor) + 1):
+          #      if minor == int(dev_python_minor):
+          #          # For python versions in development, specify a range so we install
+          #          # a final version if available, otherwise a prerelease.
+          #          # The .0 is necessary here for unclear reasons.
+          #          configs.append((f"3.{minor}.0-dev - 3.{minor}", f"py3{minor}"))
+          #      else:
+          #          configs.append((f"3.{minor}", f"py3{minor}-full"))
+          #      if int(min_python_threaded_minor) <= minor <= int(max_python_threaded_minor):
+          #          if minor == int(dev_python_minor):
+          #              # The range trick above doesn't work for threaded builds, so we'll
+          #              # just be stuck with last prerelease until we update dev_python_minor.
+          #              configs.append((f"3.{minor}t-dev", f"py3{minor}"))
+          #          else:
+          #              configs.append((f"3.{minor}t", f"py3{minor}"))
+          #    # Early versions of 3.10 and 3.11 had different deprecation
+          #    # warnings in asyncio. Test with them too to make sure everything
+          #    # works the same way.
+          #    configs.append(("3.10.8", "py310-full"))
+          #    configs.append(("3.11.0", "py311-full"))
+          #    # Pypy is a lot slower due to jit warmup costs, so don't run the
+          #    # "full" test config there.
+          #    configs.append(("pypy-3.10", "pypy3"))
+          #    # Docs python version must be synced with tox.ini
+          #    configs.append((f"3.{default_python_minor}", "docs"))
+          #    for version, tox_env in configs:
+          #      cog.outl(f"  - python: '{version}'")
+          #      cog.outl(f"    tox_env: {tox_env}")
+          #    ]]]
           - python: '3.10'
             tox_env: py310-full
-          - python: '3.10.8'
-            # Early versions of 3.10 and 3.11 had different deprecation
-            # warnings in asyncio. Test with them too to make sure everything
-            # works the same way.
-            tox_env: py310-full
           - python: '3.11'
             tox_env: py311-full
-          - python: '3.11.0'
-            tox_env: py311-full
           - python: '3.12'
             tox_env: py312-full
           - python: '3.13'
             tox_env: py313-full
-          - python: '3.14.0-rc.1 - 3.14'
-            tox_env: py314-full
+          - python: '3.14.0-dev - 3.14'
+            tox_env: py314
           - python: '3.14t-dev'
-            tox_env: py314t
+            tox_env: py314
+          - python: '3.10.8'
+            tox_env: py310-full
+          - python: '3.11.0'
+            tox_env: py311-full
           - python: 'pypy-3.10'
-            # Pypy is a lot slower due to jit warmup costs, so don't run the
-            # "full" test config there.
             tox_env: pypy3
           - python: '3.13'
-            # Docs python version must be synced with tox.ini
             tox_env: docs
+          # [[[end]]]
 
     steps:
       - uses: actions/checkout@v4
@@ -101,7 +128,9 @@ jobs:
       - uses: actions/setup-python@v5
         name: Install Python
         with:
+          # [[[cog cog.outl(f"python-version: '3.{default_python_minor}'")]]]
           python-version: '3.13'
+          # [[[end]]]
       - name: Run test suite
         # TODO: figure out what's up with these log messages
         run: py -m tornado.test --fail-if-logs=false
@@ -141,4 +170,6 @@ jobs:
           # For speed, we only build one python version and one arch. We throw away the wheels
           # built here; the real build is defined in build.yml.
           CIBW_ARCHS: native
+          # [[[cog cog.outl(f"CIBW_BUILD: cp3{default_python_minor}-manylinux*")]]]
           CIBW_BUILD: cp313-manylinux*
+          # [[[end]]]
index 9b1218625a154b2f424dfd18978a768fbe77ce7e..9b3df09ff7d3eeed9b25876f7d06422fd704413e 100644 (file)
@@ -99,7 +99,7 @@ installed in this way, so you may wish to download a copy of the
 source tarball or clone the `git repository
 <https://github.com/tornadoweb/tornado>`_ as well.
 
-**Prerequisites**: Tornado 6.3 requires Python 3.9 or newer. The following
+**Prerequisites**: Tornado requires Python 3. The following
 optional packages may be useful:
 
 * `pycurl <http://pycurl.io/>`_ is used by the optional
diff --git a/maint/scripts/runcog.sh b/maint/scripts/runcog.sh
new file mode 100755 (executable)
index 0000000..0314bfb
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# max/min_python_minor are the range of Python 3.x versions we support.
+# max_min_python_threaded_minor are the range of free-threaded python
+# versions we support.
+# default_python_minor is used in various parts of the build/CI pipeline,
+# most significantly in the docs and lint builds which can be sensitive
+# to minor version changes. We use the same version for all miscellaneous
+# tasks for consistency.
+# dev_python_minor is the version of Python that is currently under development
+# and is used to install pre-release versions of Python in CI.
+uvx --from cogapp cog \
+    -D min_python_minor=10 \
+    -D max_python_minor=14 \
+    -D min_python_threaded_minor=14 \
+    -D max_python_threaded_minor=14 \
+    -D default_python_minor=13 \
+    -D dev_python_minor=14 \
+    -r $(git grep -l '\[\[\[cog')
index c8f2c2ca427943f9023e5b2e81205b175661b0ed..7e6b3174cbae667521863562478f2b96aa02cbc1 100644 (file)
@@ -3,10 +3,20 @@ requires = ["setuptools"]
 build-backend = "setuptools.build_meta"
 
 [tool.black]
-target-version = ['py39', 'py310', 'py311', 'py312', 'py313']
+# [[[cog
+#    cog.outl(f"target-version = ['py3{min_python_minor}']")
+# ]]]
+target-version = ['py310']
+#[[[end]]]
 
 [tool.cibuildwheel]
-build = "cp39* cp310* cp311* cp312* cp313* cp314* cp314t*"
+# [[[cog
+#    versions = [f"cp3{m}*" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
+#    versions += ["cp314t*"]
+#    cog.outl(f"build = \"{" ".join(versions)}\"")
+# ]]]
+build = "cp310* cp311* cp312* cp313* cp314* cp314t*"
+#[[[end]]]
 test-command = "python -m tornado.test"
 
 [tool.cibuildwheel.macos]
index f1d2b312f81663d62b9601500ef634224a6dc530..957b526bbd8417c06e6ffe29a0d3578139d66aec 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -2,7 +2,9 @@
 license_file = LICENSE
 
 [mypy]
-python_version = 3.9
+# [[[cog cog.outl(f"python_version = 3.{min_python_minor}")]]]
+python_version = 3.10
+# [[[end]]]
 no_implicit_optional = True
 
 [mypy-tornado.*,tornado.platform.*]
index e2a699124273ce04663466fbcf46442e6da6b115..62eca36c18e3f5ed025390305e476e9d7428dafa 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,20 @@ if (
 
     can_use_limited_api = not sysconfig.get_config_var("Py_GIL_DISABLED")
 
+    if can_use_limited_api:
+        # [[[cog
+        #   cog.out(f"define_macros = [(\"Py_LIMITED_API\", ")
+        #   cog.out(f"\"0x03{int(min_python_minor):02x}0000\"")
+        #   cog.outl(")]")
+        #   cog.outl(f"bdist_wheel_options = {{\"py_limited_api\": \"cp3{min_python_minor}\"}}")
+        #   ]]]
+        define_macros = [("Py_LIMITED_API", "0x030a0000")]
+        bdist_wheel_options = {"py_limited_api": "cp310"}
+        # [[[end]]]
+    else:
+        define_macros = []
+        bdist_wheel_options = {}
+
     # This extension builds and works on pypy as well, although pypy's jit
     # produces equivalent performance.
     kwargs["ext_modules"] = [
@@ -51,18 +65,20 @@ if (
             # Use the stable ABI so our wheels are compatible across python
             # versions.
             py_limited_api=can_use_limited_api,
-            define_macros=[("Py_LIMITED_API", "0x03090000")] if can_use_limited_api else [],
+            define_macros=define_macros,
         )
     ]
 
-    if can_use_limited_api:
-        kwargs["options"] = {"bdist_wheel": {"py_limited_api": "cp39"}}
+    if bdist_wheel_options:
+        kwargs["options"] = {"bdist_wheel": bdist_wheel_options}
 
 
 setuptools.setup(
     name="tornado",
     version=version,
-    python_requires=">= 3.9",
+    # [[[cog cog.outl(f"python_requires=\">= 3.{min_python_minor}\",")]]]
+    python_requires=">= 3.10",
+    # [[[end]]]
     packages=["tornado", "tornado.test", "tornado.platform"],
     package_data={
         # data files need to be listed both here (which determines what gets
@@ -102,11 +118,16 @@ setuptools.setup(
     classifiers=[
         "License :: OSI Approved :: Apache Software License",
         "Programming Language :: Python :: 3",
-        "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",
+        # [[[cog
+        #   for minor in range(int(min_python_minor), int(max_python_minor) + 1):
+        #     cog.outl(f"\"Programming Language :: Python :: 3.{minor}\"")
+        #   ]]]
+        "Programming Language :: Python :: 3.10"
+        "Programming Language :: Python :: 3.11"
+        "Programming Language :: Python :: 3.12"
+        "Programming Language :: Python :: 3.13"
+        "Programming Language :: Python :: 3.14"
+        # [[[end]]]
         "Programming Language :: Python :: Implementation :: CPython",
         "Programming Language :: Python :: Implementation :: PyPy",
     ],
diff --git a/tox.ini b/tox.ini
index be3abce9ccacab181c067b977f2f82ea44ea9eb0..88e8eb9dfbd6707881091a5bae922df0b270582d 100644 (file)
--- a/tox.ini
+++ b/tox.ini
 [tox]
 envlist =
         # Basic configurations: Run the tests for each python version.
-        py39-full,py310-full,py311-full,py312-full,py313-full,py314-full,py314t,pypy3-full
+        # [[[cog
+        #   versions = [f"py3{m}" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
+        #   versions += ["pypy3"]
+        #   cog.outl(','.join(versions))
+        #  ]]]
+        py310,py311,py312,py313,py314,pypy3
+        # [[[end]]]
 
         # Build and test the docs with sphinx.
         docs
@@ -29,8 +35,13 @@ basepython =
            # linter warning-suppression comments go), so we specify a
            # python version for these builds.
            # These versions must be synced with the versions in .github/workflows/test.yml
+           # [[[cog
+           #    cog.outl(f"docs: python3.{default_python_minor}")
+           #    cog.outl(f"lint: python3.{default_python_minor}")
+           #    ]]]
            docs: python3.13
            lint: python3.13
+           # [[[end]]]
 
 deps =
      full: pycurl
@@ -41,7 +52,13 @@ deps =
 
 setenv =
        # Treat the extension as mandatory in testing (but not on pypy)
-       {py3,py39,py310,py311,py312,py313,py314,py314t}: TORNADO_EXTENSION=1
+       # [[[cog
+       #    versions = [f"py3{m}" for m in range(int(min_python_minor), int(max_python_minor) + 1)]
+       #    versions.insert(0, "py3")
+       #    cog.outl(f"{{{",".join(versions)}}}: TORNADO_EXTENSION=1")
+       # ]]]
+       {py3,py310,py311,py312,py313,py314}: TORNADO_EXTENSION=1
+       # [[[end]]]
        # CI workers are often overloaded and can cause our tests to exceed
        # the default timeout of 5s.
        ASYNC_TEST_TIMEOUT=25
@@ -113,5 +130,7 @@ commands =
          # something new than of depending on something old and deprecated.
          # But sometimes something we depend on gets removed so we should also
          # test the newest version.
+         # [[[cog cog.outl(f"env -u PYTHONWARNDEFAULTENCODING mypy --platform linux --python-version 3.{default_python_minor} {{posargs:tornado}}")]]]
          env -u PYTHONWARNDEFAULTENCODING mypy --platform linux --python-version 3.13 {posargs:tornado}
+         # [[[end]]]
 changedir = {toxinidir}