Skip to content

Commit c43da88

Browse files
committed
build(deps): drop Python 3.9, bump httpx/pytest-httpx, adapt async mocker
Raise the runtime floor to Python 3.10 (verified on 3.10 and 3.12) and modernize the HTTP toolchain: - python >=3.10,<4 (drop 3.9 from deps and CI matrix) - httpx >=0.28, pytest-httpx >=0.35, inflect >=7 - dev: pytest >=8,<9, pytest-asyncio >=0.24,<2, pytest-cov <7 pytest-httpx >=0.35 (which pulls httpx 0.28) is the only path to httpx 0.28, and it forces the pytest/pytest-asyncio bumps transitively. Its 0.31+ API changes break the async mocker, so adapt it: - HTTPXMock now requires _HTTPXMockOptions; construct it with assert_all_requests_were_expected=False and can_send_already_matched_responses=True to preserve the previous behaviour (one registered response answers retried requests). - reset() no longer performs assertions; call _assert_options() explicitly, gated by success, to keep failing on unrequested mocks. - match_content now serializes JSON with compact separators to match httpx 0.28's compact request-body serialization. Mark test_execute_error_with_reason (native httpx_mock fixture, retries on 500) with the matching httpx_mock options. All 399 tests pass.
1 parent 8d3ff5f commit c43da88

5 files changed

Lines changed: 85 additions & 95 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
strategy:
1616
matrix:
17-
python-version: ['3.9', '3.10', '3.11', '3.12']
17+
python-version: ['3.10', '3.11', '3.12']
1818
steps:
1919
- name: Checkout
2020
uses: actions/checkout@v3

connect/client/testing/fluent.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import responses
1111
from pytest import MonkeyPatch
1212
from pytest_httpx import HTTPXMock
13+
from pytest_httpx._options import _HTTPXMockOptions
1314
from responses import matchers
1415

1516
from connect.client.fluent import _ConnectClientBase
@@ -165,7 +166,13 @@ def _get_namespace_class(self):
165166

166167

167168
_monkeypatch = MonkeyPatch()
168-
_async_mocker = HTTPXMock()
169+
# The ConnectClient retries requests, so a single registered response must be
170+
# able to answer repeated (retried) requests.
171+
_async_mocker = HTTPXMock(
172+
_HTTPXMockOptions(
173+
can_send_already_matched_responses=True,
174+
),
175+
)
169176

170177

171178
class AsyncConnectClientMocker(ConnectClientMocker):
@@ -194,8 +201,14 @@ async def mocked_handle_async_request(
194201
)
195202

196203
def reset(self, success=True):
197-
_async_mocker.reset(success)
198-
_monkeypatch.undo()
204+
try:
205+
if success:
206+
# pytest-httpx>=0.31 no longer asserts on reset(); do it explicitly
207+
# so unrequested mocks / unexpected requests still fail the test.
208+
_async_mocker._assert_options()
209+
finally:
210+
_async_mocker.reset()
211+
_monkeypatch.undo()
199212

200213
def mock(
201214
self,
@@ -222,7 +235,12 @@ def mock(
222235

223236
if match_body:
224237
if isinstance(match_body, (dict, list, tuple)):
225-
kwargs['match_content'] = json.dumps(match_body).encode('utf-8')
238+
# httpx>=0.28 serializes JSON request bodies compactly, so match
239+
# the same separators or match_content won't compare equal.
240+
kwargs['match_content'] = json.dumps(
241+
match_body,
242+
separators=(',', ':'),
243+
).encode('utf-8')
226244
else:
227245
kwargs['match_content'] = match_body
228246

poetry.lock

Lines changed: 51 additions & 82 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ classifiers = [
1717
"Environment :: Console",
1818
"Operating System :: OS Independent",
1919
"Intended Audience :: Developers",
20-
"Programming Language :: Python :: 3.9",
2120
"Programming Language :: Python :: 3.10",
2221
"Programming Language :: Python :: 3.11",
2322
"Programming Language :: Python :: 3.12",
@@ -35,20 +34,20 @@ keywords = [
3534
]
3635

3736
[tool.poetry.dependencies]
38-
python = ">=3.9,<4"
37+
python = ">=3.10,<4"
3938
connect-markdown-renderer = "^3"
4039
PyYAML = ">=5.3.1"
4140
requests = ">=2.23"
42-
inflect = ">=4.1"
43-
httpx = ">=0.23"
41+
inflect = ">=7"
42+
httpx = ">=0.28"
4443
asgiref = "^3.3.4"
4544
responses = ">=0.14.0,<1"
46-
pytest-httpx = ">=0.27,<0.30"
45+
pytest-httpx = ">=0.35"
4746

4847
[tool.poetry.group.test.dependencies]
4948
black = "23.*"
50-
pytest = ">=6.1.2,<8"
51-
pytest-cov = ">=2.10.1,<5"
49+
pytest = ">=8,<9"
50+
pytest-cov = ">=2.10.1,<7"
5251
pytest-mock = "^3.10"
5352
coverage = {extras = ["toml"], version = ">=5.3,<7"}
5453
flake8 = ">=6"
@@ -62,7 +61,7 @@ flake8-isort = "^6.0"
6261
flake8-broken-line = ">=1.0"
6362
flake8-pyproject = "^1.2.3"
6463
isort = "^5.10"
65-
pytest-asyncio = "^0.15.1"
64+
pytest-asyncio = ">=0.24,<2"
6665

6766
[tool.poetry.group.docs.dependencies]
6867
mkdocs = "^1.3.1"

tests/async_client/test_fluent.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ async def test_execute_uparseable_connect_error(httpx_mock):
348348

349349

350350
@pytest.mark.asyncio
351+
@pytest.mark.httpx_mock(
352+
assert_all_requests_were_expected=False,
353+
can_send_already_matched_responses=True,
354+
)
351355
@pytest.mark.parametrize('encoding', ('utf-8', 'iso-8859-1'))
352356
async def test_execute_error_with_reason(httpx_mock, encoding):
353357
httpx_mock.add_response(

0 commit comments

Comments
 (0)