]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
ci: add riscv64 manylinux/musllinux wheels 3546/head
authorJulien Stephan <jstephan@baylibre.com>
Wed, 26 Nov 2025 17:09:48 +0000 (18:09 +0100)
committerBen Darnell <ben@bendarnell.com>
Fri, 20 Mar 2026 01:16:25 +0000 (21:16 -0400)
Now that cibuildwheel and PyPI support riscv64, we can start building
riscv64 wheels for Tornado.

Because there is no native riscv64 runner available, this PR adds a
QEMU-based riscv64 job to the cibuildwheel workflow.

Due to emulation, we need to:
- Increase ASYNC_TEST_TIMEOUT to 30s to accommodate slower runs
- Increase timeout for test_request_timeout
- Skip test_unquote_large

Signed-off-by: Julien Stephan <jstephan@baylibre.com>
.github/workflows/build.yml
.github/zizmor.yml
tornado/test/httputil_test.py
tornado/test/simple_httpclient_test.py
tornado/test/util.py

index e6c085b1402ab1104840af4eb45e44365a823eaf..16790d1de8ffebf2839350ad29387ac795e77f00 100644 (file)
@@ -50,12 +50,17 @@ jobs:
           path: ./dist/tornado-*.tar.gz
 
   build_wheels:
-    name: Build wheels on ${{ matrix.os }}
+    name: Build wheels on ${{ matrix.os }}${{ matrix.name_suffix || '' }}
     runs-on: ${{ matrix.os }}
     strategy:
       fail-fast: false
       matrix:
         os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, windows-11-arm, macos-15]
+        arch: [auto]
+        include:
+          - os: ubuntu-24.04
+            arch: "riscv64"
+            name_suffix: "-riscv64"
 
     steps:
       - uses: actions/checkout@v4
@@ -66,8 +71,18 @@ jobs:
         with:
           python-version: ${{ env.python-version }}
 
+      - name: Set up QEMU
+        if: matrix.arch != 'auto'
+        uses: docker/setup-qemu-action@v3
+        with:
+          platforms: ${{ matrix.arch }}
+
       - name: Build wheels
         uses: pypa/cibuildwheel@v3.4.0
+        env:
+          CIBW_ARCHS: ${{ matrix.arch }}
+          # Increase timeouts for emulated archs
+          CIBW_ENVIRONMENT: ${{ matrix.arch != 'auto' && 'ASYNC_TEST_TIMEOUT=30 EMULATION=1' || '' }}
 
       - name: Audit ABI3 compliance
         # This may be moved into cibuildwheel itself in the future. See
@@ -76,7 +91,7 @@ jobs:
 
       - uses: actions/upload-artifact@v4
         with:
-          name: artifacts-${{ matrix.os }}
+          name: artifacts-${{ matrix.os }}${{ matrix.name_suffix || '' }}
           path: ./wheelhouse/*.whl
 
   upload_pypi_test:
index a71e19fa6f9c1e5a8231c9a47fdefa77f59b777a..50582e4bb1bd0cfcffb1d6fc905e11cfa4a75b0f 100644 (file)
@@ -11,4 +11,5 @@ rules:
         dependabot/*: ref-pin
         # Additional trusted repositories
         pypa/*: ref-pin
-        astral-sh/setup-uv: ref-pin
\ No newline at end of file
+        astral-sh/setup-uv: ref-pin
+        docker/setup-qemu-action: ref-pin
index 2924b210ec96b1811280c822449e9868b75fb389..fee6748db2ba1f864b7b83151fc42636fb49e843 100644 (file)
@@ -23,6 +23,8 @@ import time
 import urllib.parse
 import unittest
 
+from tornado.test.util import skipIfEmulated
+
 
 def form_data_args() -> tuple[dict[str, list[bytes]], dict[str, list[HTTPFile]]]:
     """Return two empty dicts suitable for use with parse_multipart_form_data.
@@ -714,6 +716,7 @@ class ParseCookieTest(unittest.TestCase):
                 c = parse_cookie(encoded)
                 self.assertEqual(c["a"], decoded)
 
+    @skipIfEmulated
     def test_unquote_large(self):
         # Adapted from
         # https://github.com/python/cpython/blob/dc7a2b6522ec7af41282bc34f405bee9b306d611/Lib/test/test_http_cookies.py#L87
index e897f79cd864e0f51df237c5bbb122618264ae8d..4a75773532bd1bf88b9d2e2476a5c7312b01db45 100644 (file)
@@ -315,7 +315,7 @@ class SimpleHTTPClientTestMixin(AsyncTestCase):
 
     def test_request_timeout(self):
         timeout = 0.1
-        if os.name == "nt":
+        if os.name == "nt" or os.environ.get("EMULATION") == "1":
             timeout = 0.5
 
         with self.assertRaises(HTTPTimeoutError):
index ca7dcec589e72bd2afb8e7bf52b31d8f5043a30d..36179252f72c7ab9d469f7ee62782afba389665c 100644 (file)
@@ -21,6 +21,12 @@ skipIfNonUnix = unittest.skipIf(
 # depend on an external network.
 skipIfNoNetwork = unittest.skipIf("NO_NETWORK" in os.environ, "network access disabled")
 
+# Set the environment variable EMULATION=1 to disable any tests that
+# are unreliable under emulation
+skipIfEmulated = unittest.skipIf(
+    "EMULATION" in os.environ, "test unreliable under emulation"
+)
+
 skipNotCPython = unittest.skipIf(
     # "CPython" here essentially refers to the traditional synchronous refcounting GC,
     # so we skip these tests in free-threading builds of cpython too.