From 438684ab14a8813ffef317efdc7ba3636589cbc1 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Tue, 16 Jun 2026 11:28:31 -0400 Subject: [PATCH 1/4] Release v0.10.3 Bump version to 0.10.3 and ship the accumulated fixes since 0.10.2, most notably the /bytes endpoint fix (returns bytes instead of bytearray) for WSGI compliance with Werkzeug >= 2.1 / 3.x. Also adds a regression test that inspects the raw WSGI iterable so a bytearray regression can't slip past the (coercing) Werkzeug test client. --- README.md | 4 ++++ pyproject.toml | 2 +- tests/test_httpbin.py | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7dc09efa..f024400b 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,10 @@ Releases are triggered on commits tagged with `release-` (for example ## Changelog +* 0.10.3: + - Fixed the /bytes endpoint to return bytes (not bytearray) for WSGI compliance with newer Werkzeug, thanks @swt2c + - Dropped support for Python 3.7 + - Build and publish arm64 Docker images * 0.10.2: - Added support for Flask 3.0 * 0.10.1: diff --git a/pyproject.toml b/pyproject.toml index 894c5509..c5574d0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ Repository = "https://github.com/psf/httpbin" [project] name = "httpbin" -version = "0.10.2" +version = "0.10.3" requires-python = ">=3.8" description = "HTTP Request and Response Service" readme = "README.md" diff --git a/tests/test_httpbin.py b/tests/test_httpbin.py index 6b751245..9d995b93 100755 --- a/tests/test_httpbin.py +++ b/tests/test_httpbin.py @@ -519,6 +519,19 @@ def test_stream_bytes_with_seed(self): response.data, b'\xc5\xd7\x14\x84\xf8\xcf\x9b\xf4\xb7o' ) + def test_bytes_endpoint_yields_bytes(self): + """WSGI bodies must be bytes (not bytearray) so strict servers + (wsgiref / pytest-httpbin) don't 500. The test client coerces the + body, so we inspect the raw WSGI iterable. Regression for /bytes.""" + from werkzeug.test import create_environ + env = create_environ('/bytes/64', 'http://localhost/') + chunks = list(httpbin.app(env, lambda *a, **k: None)) + self.assertTrue(chunks, "no body produced") + self.assertTrue( + all(type(c) is bytes for c in chunks), + [type(c).__name__ for c in chunks] + ) + def test_delete_endpoint_returns_body(self): response = self.app.delete( '/delete', From 47e676643942dc124165184840a196cf6dcb6afd Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Tue, 16 Jun 2026 11:32:15 -0400 Subject: [PATCH 2/4] CI: bump artifact actions v3 -> v4 GitHub auto-fails jobs using the deprecated actions/upload-artifact@v3 and download-artifact@v3, so CI never reached the test step. Bump both to v4. upload-artifact@v4 errors on duplicate artifact names, so in the test matrix the requirements.txt upload is gated to a single job (the docker job only needs one copy). --- .github/workflows/ci.yml | 7 +++++-- .github/workflows/publish.yml | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d419cd08..05727bfb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,10 @@ jobs: - name: Run tests run: python -m pytest tests - name: Store tested requirements.txt file as artifact - uses: actions/upload-artifact@v3 + # Only upload from a single matrix job: upload-artifact@v4 errors on + # duplicate artifact names, and the docker job only needs one copy. + if: matrix.os == 'ubuntu-22.04' && matrix.python-version == '3.10' + uses: actions/upload-artifact@v4 with: name: requirements.txt path: | @@ -74,7 +77,7 @@ jobs: echo "APP_VERSION=$(/tmp/tomlq/bin/tomlq -r .project.version pyproject.toml)" >> $GITHUB_ENV echo "APP_DESC=$(/tmp/tomlq/bin/tomlq -r .project.description pyproject.toml)" >> $GITHUB_ENV - name: Retrieve tested requirements file - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: requirements.txt - name: Ensure docker build is working diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6e7e9bd2..4e526fd6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,7 +31,7 @@ jobs: requirements.txt Dockerfile - name: Store tested requirements.txt file as artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: requirements.txt path: | @@ -54,7 +54,7 @@ jobs: echo "APP_VERSION=$(/tmp/tomlq/bin/tomlq -r .project.version pyproject.toml)" >> $GITHUB_ENV echo "APP_DESC=$(/tmp/tomlq/bin/tomlq -r .project.description pyproject.toml)" >> $GITHUB_ENV - name: Retrieve tested requirements file - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: requirements.txt - name: Check file contents From c79e992b624666bc3efb3349f058fc99236cda3d Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Tue, 16 Jun 2026 13:00:12 -0400 Subject: [PATCH 3/4] CI: drop PyPy from test matrix The mainapp extra installs gevent, which publishes no PyPy wheels and fails to compile from source on PyPy under Cython 3 (corecext.pyx references the removed py2 'long' builtin). httpbin targets CPython only (see pyproject classifiers), and the release/publish pipeline tests CPython 3.10 alone, so PyPy CI was non-blocking dead weight that had bit-rotted. --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05727bfb..6836dabc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,9 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8", "pypy-3.9", "pypy-3.10"] + # PyPy is omitted: the mainapp extra pulls gevent, which ships no PyPy + # wheels and fails to build from source on PyPy under Cython 3. + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-22.04, macOS-latest, windows-latest] # Python 3.8 and 3.9 do not run on macOS-latest which # is now using arm64 hardware. From 16a004d8edc2ff0eae0527bf8a20b09c7f864162 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Tue, 16 Jun 2026 13:01:32 -0400 Subject: [PATCH 4/4] Test against Python 3.13 and 3.14 Add 3.13 and 3.14 to the CI matrix and the package classifiers. gevent, greenlet, and brotlicffi all publish cp313/cp314 (and abi3) wheels, so no source builds are required. --- .github/workflows/ci.yml | 2 +- pyproject.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6836dabc..0f7b595d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: matrix: # PyPy is omitted: the mainapp extra pulls gevent, which ships no PyPy # wheels and fails to build from source on PyPy under Cython 3. - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] os: [ubuntu-22.04, macOS-latest, windows-latest] # Python 3.8 and 3.9 do not run on macOS-latest which # is now using arm64 hardware. diff --git a/pyproject.toml b/pyproject.toml index c5574d0a..6c7a58ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,8 @@ classifiers = [ "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", ] dependencies = [ "brotlicffi",