From 59d4a80fcf8a7b3a46b2560f75dc0d171e7ea8ff Mon Sep 17 00:00:00 2001 From: Yurii Motov <109919500+YuriiMotov@users.noreply.github.com> Date: Wed, 27 May 2026 12:47:28 +0200 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=85=20Add=20`httpx2`=20test=20depende?= =?UTF-8?q?ncy=20to=20avoid=20deprecation=20warning=20(#15603)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/publish.yml | 1 + .github/workflows/test.yml | 11 +++++- pyproject.toml | 1 + .../test_tutorial001.py | 5 ++- .../test_tutorial003.py | 9 +++-- uv.lock | 36 +++++++++++++++++++ 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 32d6ea4f98..f7f180e8e2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,6 +29,7 @@ jobs: uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: version: "0.11.4" + enable-cache: "false" - name: Build distribution run: uv build - name: Publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7380cb75e9..edcc49b309 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,6 +81,11 @@ jobs: uv-resolution: highest codspeed: codspeed deprecated-tests: "no-deprecation" + - os: ubuntu-latest + python-version: "3.13" + uv-resolution: highest + deprecated-tests: "no-deprecation" + without-httpx2: true - os: ubuntu-latest python-version: "3.14" coverage: coverage @@ -129,15 +134,19 @@ jobs: - name: Install deprecated libraries just for testing if: matrix.deprecated-tests == 'test-deprecation' run: uv pip install orjson ujson + - name: Uninstall httpx2 to run tests with httpx + if: matrix.without-httpx2 == 'true' + run: uv pip uninstall httpx2 - name: Reinstall SQLAlchemy without Cython extensions if: matrix.python-version == '3.14t' && matrix.os == 'ubuntu-latest' run: "DISABLE_SQLALCHEMY_CEXT=1 uv pip install --force-reinstall --no-binary :all: sqlalchemy" - run: mkdir coverage - name: Test - run: uv run --no-sync bash scripts/test-cov.sh + run: uv run --no-sync bash scripts/test-cov.sh $PYTEST_OPTIONS env: COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}} CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}} + PYTEST_OPTIONS: ${{ (matrix.without-httpx2 == 'true') && '-W ignore::UserWarning' || '' }} # Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow - name: Store coverage files if: matrix.coverage == 'coverage' diff --git a/pyproject.toml b/pyproject.toml index 4bac4757b4..9affa3d1d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -146,6 +146,7 @@ docs = [ ] docs-tests = [ "httpx >=0.23.0,<1.0.0", + "httpx2>=2.0.0", "ruff >=0.14.14", ] github-actions = [ diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial001.py b/tests/test_tutorial/test_header_param_models/test_tutorial001.py index 8391bd1197..cc274cd64d 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial001.py @@ -1,6 +1,7 @@ import importlib import pytest +from dirty_equals import IsOneOf from fastapi.testclient import TestClient from inline_snapshot import snapshot @@ -68,7 +69,9 @@ def test_header_param_model_invalid(client: TestClient): "x_tag": [], "host": "testserver", "accept": "*/*", - "accept-encoding": "gzip, deflate", + "accept-encoding": IsOneOf( + "gzip, deflate", "gzip, deflate, zstd" + ), "connection": "keep-alive", "user-agent": "testclient", }, diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial003.py b/tests/test_tutorial/test_header_param_models/test_tutorial003.py index 7d0da24fd5..de2fb87ec6 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial003.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial003.py @@ -1,6 +1,7 @@ import importlib import pytest +from dirty_equals import IsOneOf from fastapi.testclient import TestClient from inline_snapshot import snapshot @@ -66,7 +67,9 @@ def test_header_param_model_no_underscore(client: TestClient): "traceparent": "123", "x_tag": [], "accept": "*/*", - "accept-encoding": "gzip, deflate", + "accept-encoding": IsOneOf( + "gzip, deflate", "gzip, deflate, zstd" + ), "connection": "keep-alive", "user-agent": "testclient", "save-data": "true", @@ -105,7 +108,9 @@ def test_header_param_model_invalid(client: TestClient): "x_tag": [], "host": "testserver", "accept": "*/*", - "accept-encoding": "gzip, deflate", + "accept-encoding": IsOneOf( + "gzip, deflate", "gzip, deflate, zstd" + ), "connection": "keep-alive", "user-agent": "testclient", }, diff --git a/uv.lock b/uv.lock index 15ce0c67c4..a0608e8d76 100644 --- a/uv.lock +++ b/uv.lock @@ -1151,6 +1151,7 @@ dev = [ { name = "griffe-typingdoc" }, { name = "griffe-warnings-deprecated" }, { name = "httpx" }, + { name = "httpx2" }, { name = "inline-snapshot" }, { name = "jieba" }, { name = "markdown-include-variants" }, @@ -1186,6 +1187,7 @@ docs = [ { name = "griffe-typingdoc" }, { name = "griffe-warnings-deprecated" }, { name = "httpx" }, + { name = "httpx2" }, { name = "jieba" }, { name = "markdown-include-variants" }, { name = "mdx-include" }, @@ -1199,6 +1201,7 @@ docs = [ ] docs-tests = [ { name = "httpx" }, + { name = "httpx2" }, { name = "ruff" }, ] github-actions = [ @@ -1216,6 +1219,7 @@ tests = [ { name = "dirty-equals" }, { name = "flask" }, { name = "httpx" }, + { name = "httpx2" }, { name = "inline-snapshot" }, { name = "mypy" }, { name = "pwdlib", extra = ["argon2"] }, @@ -1288,6 +1292,7 @@ dev = [ { name = "griffe-typingdoc", specifier = ">=0.3.0" }, { name = "griffe-warnings-deprecated", specifier = ">=1.1.0" }, { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, + { name = "httpx2", specifier = ">=2.0.0" }, { name = "inline-snapshot", specifier = ">=0.21.1" }, { name = "jieba", specifier = ">=0.42.1" }, { name = "markdown-include-variants", specifier = ">=0.0.8" }, @@ -1323,6 +1328,7 @@ docs = [ { name = "griffe-typingdoc", specifier = ">=0.3.0" }, { name = "griffe-warnings-deprecated", specifier = ">=1.1.0" }, { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, + { name = "httpx2", specifier = ">=2.0.0" }, { name = "jieba", specifier = ">=0.42.1" }, { name = "markdown-include-variants", specifier = ">=0.0.8" }, { name = "mdx-include", specifier = ">=1.4.1,<2.0.0" }, @@ -1336,6 +1342,7 @@ docs = [ ] docs-tests = [ { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, + { name = "httpx2", specifier = ">=2.0.0" }, { name = "ruff", specifier = ">=0.14.14" }, ] github-actions = [ @@ -1353,6 +1360,7 @@ tests = [ { name = "dirty-equals", specifier = ">=0.9.0" }, { name = "flask", specifier = ">=3.0.0,<4.0.0" }, { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, + { name = "httpx2", specifier = ">=2.0.0" }, { name = "inline-snapshot", specifier = ">=0.21.1" }, { name = "mypy", specifier = ">=1.14.1" }, { name = "pwdlib", extras = ["argon2"], specifier = ">=0.2.1" }, @@ -2129,6 +2137,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, ] +[[package]] +name = "httpcore2" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/7e/8ab39aab1d392845b6512009a9be57d24a5bd4ec7a22d02e513d0645e7a8/httpcore2-2.2.0.tar.gz", hash = "sha256:10e0e142f1ecc1c1cb2a9ebbce82e57f16169f61d163ea336abf36799e89294b", size = 63533, upload-time = "2026-05-17T05:29:55.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/22/64de17e7956e8c002f7558ed667d924c2a288344aeff4bd8ff5dc5fdb70b/httpcore2-2.2.0-py3-none-any.whl", hash = "sha256:ce859f268bf8d34fa2d7753e09e4dd5194f557e1b3038439b68a89b2999572fa", size = 79288, upload-time = "2026-05-17T05:29:52.56Z" }, +] + [[package]] name = "httptools" version = "0.7.1" @@ -2196,6 +2217,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, ] +[[package]] +name = "httpx2" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore2" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/aa/c3119de1aa7ad870a01aaddbf3bc3445ed9a681c31d45e3838fd8b7bc155/httpx2-2.2.0.tar.gz", hash = "sha256:f3428d59b1752b8f5629826277262fb4d65e3a683f48af8a5b16c4d012e0b801", size = 80477, upload-time = "2026-05-17T05:29:57.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/e0/e0a52596c14194e428c20de4903f4abec38c0dfb5364d20f1d4a2b6266ef/httpx2-2.2.0-py3-none-any.whl", hash = "sha256:12347ebd2daeaefd50b529359778fff767082a09c5826752c963e71269722ff0", size = 74083, upload-time = "2026-05-17T05:29:54.543Z" }, +] + [[package]] name = "huggingface-hub" version = "1.4.1" From dbfd55cea3a656029a9368924f3d8f1f829702c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 27 May 2026 10:47:52 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d22aa39cf9..0592b28081 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -15,6 +15,7 @@ hide: ### Internal +* ✅ Add `httpx2` test dependency to avoid deprecation warning. PR [#15603](https://github.com/fastapi/fastapi/pull/15603) by [@YuriiMotov](https://github.com/YuriiMotov). * ⬆ Bump the python-packages group with 15 updates. PR [#15594](https://github.com/fastapi/fastapi/pull/15594) by [@dependabot[bot]](https://github.com/apps/dependabot). * 👷 Configure Dependabot to group updates and update weekly. PR [#15560](https://github.com/fastapi/fastapi/pull/15560) by [@YuriiMotov](https://github.com/YuriiMotov). From 57535ef85b97d95862ec3de443c648e1c6aee139 Mon Sep 17 00:00:00 2001 From: Yurii Motov <109919500+YuriiMotov@users.noreply.github.com> Date: Wed, 27 May 2026 22:22:44 +0200 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9C=85=20Use=20custom=20`changing=5Fdir`?= =?UTF-8?q?=20instead=20of=20`CLIRunner.isolated=5Ffilesystem`=20to=20set?= =?UTF-8?q?=20working=20dir=20(#15616)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/test_translation_fixer/conftest.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/tests/test_translation_fixer/conftest.py b/scripts/tests/test_translation_fixer/conftest.py index 06366d5a45..5c5c0e2dc3 100644 --- a/scripts/tests/test_translation_fixer/conftest.py +++ b/scripts/tests/test_translation_fixer/conftest.py @@ -1,5 +1,8 @@ +import os import shutil import sys +from collections.abc import Generator +from contextlib import contextmanager from pathlib import Path import pytest @@ -23,11 +26,20 @@ def pytest_collection_modifyitems(config, items: list[pytest.Item]) -> None: item.add_marker(skip_on_windows) +@contextmanager +def changing_dir(directory: str | Path) -> Generator[None, None, None]: + initial_dir = os.getcwd() + os.chdir(directory) + try: + yield + finally: + os.chdir(initial_dir) + + @pytest.fixture(name="runner") -def get_runner(): - runner = CliRunner() - with runner.isolated_filesystem(): - yield runner +def get_runner(tmp_path: Path): + with changing_dir(tmp_path): + yield CliRunner() @pytest.fixture(name="root_dir") From ad09734fa3e69b9cbd0fd2d57ba59fa8e73c2f86 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 27 May 2026 20:23:09 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0592b28081..3f5fa2fa6f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -15,6 +15,7 @@ hide: ### Internal +* ✅ Use custom `changing_dir` instead of `CLIRunner.isolated_filesystem` to set working dir. PR [#15616](https://github.com/fastapi/fastapi/pull/15616) by [@YuriiMotov](https://github.com/YuriiMotov). * ✅ Add `httpx2` test dependency to avoid deprecation warning. PR [#15603](https://github.com/fastapi/fastapi/pull/15603) by [@YuriiMotov](https://github.com/YuriiMotov). * ⬆ Bump the python-packages group with 15 updates. PR [#15594](https://github.com/fastapi/fastapi/pull/15594) by [@dependabot[bot]](https://github.com/apps/dependabot). * 👷 Configure Dependabot to group updates and update weekly. PR [#15560](https://github.com/fastapi/fastapi/pull/15560) by [@YuriiMotov](https://github.com/YuriiMotov).