Skip to content

Commit 7048033

Browse files
authored
tests: Move httpx under toxgen (#4780)
* Move httpx under toxgen * This is not straightforward since we depend on `pytest-httpx` which has a very weird strict relationship to which httpx versions it supports * In addition to that, some `pytest-httpx` versions will not install on Python 3.8 despite the corresponding `httpx` versions being compatible -- added a new way to filter out these scenarios * This also removes the -latest Networking group as the httpx test suite was the last Networking test suite that wasn't completely pinned * Also move gcp to the permanent part of the ignore list as it doesn't fit the toxgen mold Ref #4506
1 parent 78843dc commit 7048033

File tree

7 files changed

+109
-141
lines changed

7 files changed

+109
-141
lines changed

.github/workflows/test-integrations-network.yml

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,73 +22,6 @@ env:
2222
CACHED_BUILD_PATHS: |
2323
${{ github.workspace }}/dist-serverless
2424
jobs:
25-
test-network-latest:
26-
name: Network (latest)
27-
timeout-minutes: 30
28-
runs-on: ${{ matrix.os }}
29-
strategy:
30-
fail-fast: false
31-
matrix:
32-
python-version: ["3.9","3.12","3.13"]
33-
# python3.6 reached EOL and is no longer being supported on
34-
# new versions of hosted runners on Github Actions
35-
# ubuntu-20.04 is the last version that supported python3.6
36-
# see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877
37-
os: [ubuntu-22.04]
38-
# Use Docker container only for Python 3.6
39-
container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }}
40-
steps:
41-
- uses: actions/checkout@v5.0.0
42-
- uses: actions/setup-python@v6
43-
if: ${{ matrix.python-version != '3.6' }}
44-
with:
45-
python-version: ${{ matrix.python-version }}
46-
allow-prereleases: true
47-
- name: Setup Test Env
48-
run: |
49-
pip install "coverage[toml]" tox
50-
- name: Erase coverage
51-
run: |
52-
coverage erase
53-
- name: Test grpc latest
54-
run: |
55-
set -x # print commands that are executed
56-
./scripts/runtox.sh "py${{ matrix.python-version }}-grpc-latest"
57-
- name: Test httpx latest
58-
run: |
59-
set -x # print commands that are executed
60-
./scripts/runtox.sh "py${{ matrix.python-version }}-httpx-latest"
61-
- name: Test requests latest
62-
run: |
63-
set -x # print commands that are executed
64-
./scripts/runtox.sh "py${{ matrix.python-version }}-requests-latest"
65-
- name: Generate coverage XML (Python 3.6)
66-
if: ${{ !cancelled() && matrix.python-version == '3.6' }}
67-
run: |
68-
export COVERAGE_RCFILE=.coveragerc36
69-
coverage combine .coverage-sentry-*
70-
coverage xml --ignore-errors
71-
- name: Generate coverage XML
72-
if: ${{ !cancelled() && matrix.python-version != '3.6' }}
73-
run: |
74-
coverage combine .coverage-sentry-*
75-
coverage xml
76-
- name: Upload coverage to Codecov
77-
if: ${{ !cancelled() }}
78-
uses: codecov/codecov-action@v5.5.1
79-
with:
80-
token: ${{ secrets.CODECOV_TOKEN }}
81-
files: coverage.xml
82-
# make sure no plugins alter our coverage reports
83-
plugins: noop
84-
verbose: true
85-
- name: Upload test results to Codecov
86-
if: ${{ !cancelled() }}
87-
uses: codecov/test-results-action@v1
88-
with:
89-
token: ${{ secrets.CODECOV_TOKEN }}
90-
files: .junitxml
91-
verbose: true
9225
test-network-pinned:
9326
name: Network (pinned)
9427
timeout-minutes: 30

scripts/populate_tox/README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,14 @@ This key is optional.
107107
### `python`
108108

109109
Sometimes, the whole test suite should only run on specific Python versions.
110-
This can be achieved via the `python` key, which expects a version specifier.
110+
This can be achieved via the `python` key.
111111

112-
For example, if you want AIOHTTP tests to only run on Python 3.7+, you can say:
112+
There are two variants how to define the Python versions to run the test suite
113+
on.
114+
115+
If you want the test suite to only be run on specific Python versions, you can
116+
set `python` to a version specifier. For example, if you want AIOHTTP tests to
117+
only run on Python 3.7+, you can say:
113118

114119
```python
115120
"aiohttp": {
@@ -118,12 +123,27 @@ For example, if you want AIOHTTP tests to only run on Python 3.7+, you can say:
118123
}
119124
```
120125

126+
If the Python version to use is dependent on the version of the package under
127+
test, you can use the more expressive dictionary variant. For instance, while
128+
HTTPX v0.28 supports Python 3.8, a test dependency of ours, `pytest-httpx`,
129+
doesn't. If you want to specify that HTTPX test suite should not be run on
130+
a Python version older than 3.9 if the HTTPX version is 0.28 or higher, you can
131+
say:
132+
133+
```python
134+
"httpx": {
135+
"python": {
136+
# run the test suite for httpx v0.28+ on Python 3.9+ only
137+
">=0.28": ">=3.9",
138+
},
139+
}
140+
```
141+
121142
The `python` key is optional, and when possible, it should be omitted. The script
122-
should automatically detect which Python versions the package supports.
123-
However, if a package has broken
124-
metadata or the SDK is explicitly not supporting some packages on specific
125-
Python versions (because of, for example, broken context vars), the `python`
126-
key can be used.
143+
should automatically detect which Python versions the package supports. However,
144+
if a package has broken metadata or the SDK is explicitly not supporting some
145+
packages on specific Python versions (because of, for example, broken context
146+
vars), the `python` key can be used.
127147

128148
### `include`
129149

scripts/populate_tox/config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@
150150
},
151151
"python": ">=3.7",
152152
},
153+
"httpx": {
154+
"package": "httpx",
155+
"deps": {
156+
"*": ["anyio<4.0.0"],
157+
">=0.16,<0.17": ["pytest-httpx==0.10.0"],
158+
">=0.17,<0.19": ["pytest-httpx==0.12.0"],
159+
">=0.19,<0.21": ["pytest-httpx==0.14.0"],
160+
">=0.21,<0.23": ["pytest-httpx==0.19.0"],
161+
">=0.23,<0.24": ["pytest-httpx==0.21.0"],
162+
">=0.24,<0.25": ["pytest-httpx==0.22.0"],
163+
">=0.25,<0.26": ["pytest-httpx==0.25.0"],
164+
">=0.26,<0.27": ["pytest-httpx==0.28.0"],
165+
">=0.27,<0.28": ["pytest-httpx==0.30.0"],
166+
">=0.28,<0.29": ["pytest-httpx==0.35.0"],
167+
},
168+
"python": {
169+
">=0.28": ">=3.9",
170+
},
171+
},
153172
"huey": {
154173
"package": "huey",
155174
},

scripts/populate_tox/populate_tox.py

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@
6363
"aws_lambda",
6464
"cloud_resource_context",
6565
"common",
66+
"gcp",
6667
"gevent",
6768
"opentelemetry",
6869
"potel",
6970
# Integrations that can be migrated -- we should eventually remove all
7071
# of these from the IGNORE list
71-
"gcp",
72-
"httpx",
7372
"redis",
7473
"requests",
7574
"rq",
@@ -240,9 +239,9 @@ def _supports_lowest(release: Version) -> bool:
240239
sys.exit(1)
241240

242241
py_versions = determine_python_versions(pypi_data)
243-
target_python_versions = TEST_SUITE_CONFIG[integration].get("python")
244-
if target_python_versions:
245-
target_python_versions = SpecifierSet(target_python_versions)
242+
target_python_versions = _transform_target_python_versions(
243+
TEST_SUITE_CONFIG[integration].get("python")
244+
)
246245
return bool(supported_python_versions(py_versions, target_python_versions))
247246

248247
if not _supports_lowest(releases[0]):
@@ -327,7 +326,10 @@ def _pick_releases(
327326

328327
def supported_python_versions(
329328
package_python_versions: Union[SpecifierSet, list[Version]],
330-
custom_supported_versions: Optional[SpecifierSet] = None,
329+
custom_supported_versions: Optional[
330+
Union[SpecifierSet, dict[SpecifierSet, SpecifierSet]]
331+
] = None,
332+
version: Optional[Version] = None,
331333
) -> list[Version]:
332334
"""
333335
Get the intersection of Python versions supported by the package and the SDK.
@@ -354,9 +356,25 @@ def supported_python_versions(
354356
curr = MIN_PYTHON_VERSION
355357
while curr <= MAX_PYTHON_VERSION:
356358
if curr in package_python_versions:
357-
if not custom_supported_versions or curr in custom_supported_versions:
359+
if not custom_supported_versions:
358360
supported.append(curr)
359361

362+
else:
363+
if isinstance(custom_supported_versions, SpecifierSet):
364+
if curr in custom_supported_versions:
365+
supported.append(curr)
366+
367+
elif version is not None and isinstance(
368+
custom_supported_versions, dict
369+
):
370+
for v, py in custom_supported_versions.items():
371+
if version in v:
372+
if curr in py:
373+
supported.append(curr)
374+
break
375+
else:
376+
supported.append(curr)
377+
360378
# Construct the next Python version (i.e., bump the minor)
361379
next = [int(v) for v in str(curr).split(".")]
362380
next[1] += 1
@@ -535,20 +553,38 @@ def _add_python_versions_to_release(
535553

536554
time.sleep(PYPI_COOLDOWN) # give PYPI some breathing room
537555

538-
target_python_versions = TEST_SUITE_CONFIG[integration].get("python")
539-
if target_python_versions:
540-
target_python_versions = SpecifierSet(target_python_versions)
556+
target_python_versions = _transform_target_python_versions(
557+
TEST_SUITE_CONFIG[integration].get("python")
558+
)
541559

542560
release.python_versions = pick_python_versions_to_test(
543561
supported_python_versions(
544562
determine_python_versions(release_pypi_data),
545563
target_python_versions,
564+
release,
546565
)
547566
)
548567

549568
release.rendered_python_versions = _render_python_versions(release.python_versions)
550569

551570

571+
def _transform_target_python_versions(
572+
python_versions: Union[str, dict[str, str], None]
573+
) -> Union[SpecifierSet, dict[SpecifierSet, SpecifierSet], None]:
574+
"""Wrap the contents of the `python` key in SpecifierSets."""
575+
if not python_versions:
576+
return None
577+
578+
if isinstance(python_versions, str):
579+
return SpecifierSet(python_versions)
580+
581+
if isinstance(python_versions, dict):
582+
updated = {}
583+
for key, value in python_versions.items():
584+
updated[SpecifierSet(key)] = SpecifierSet(value)
585+
return updated
586+
587+
552588
def get_file_hash() -> str:
553589
"""Calculate a hash of the tox.ini file."""
554590
hasher = hashlib.md5()

scripts/populate_tox/tox.jinja

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ envlist =
4848
# GCP
4949
{py3.7}-gcp
5050

51-
# HTTPX
52-
{py3.6,py3.9}-httpx-v{0.16,0.18}
53-
{py3.6,py3.10}-httpx-v{0.20,0.22}
54-
{py3.7,py3.11,py3.12}-httpx-v{0.23,0.24}
55-
{py3.9,py3.11,py3.12}-httpx-v{0.25,0.27}
56-
{py3.9,py3.12,py3.13}-httpx-latest
57-
5851
# OpenTelemetry (OTel)
5952
{py3.7,py3.9,py3.12,py3.13}-opentelemetry
6053

@@ -137,27 +130,6 @@ deps =
137130
aws_lambda: requests
138131
aws_lambda: uvicorn
139132
140-
# HTTPX
141-
httpx-v0.16: pytest-httpx==0.10.0
142-
httpx-v0.18: pytest-httpx==0.12.0
143-
httpx-v0.20: pytest-httpx==0.14.0
144-
httpx-v0.22: pytest-httpx==0.19.0
145-
httpx-v0.23: pytest-httpx==0.21.0
146-
httpx-v0.24: pytest-httpx==0.22.0
147-
httpx-v0.25: pytest-httpx==0.25.0
148-
httpx: pytest-httpx
149-
# anyio is a dep of httpx
150-
httpx: anyio<4.0.0
151-
httpx-v0.16: httpx~=0.16.0
152-
httpx-v0.18: httpx~=0.18.0
153-
httpx-v0.20: httpx~=0.20.0
154-
httpx-v0.22: httpx~=0.22.0
155-
httpx-v0.23: httpx~=0.23.0
156-
httpx-v0.24: httpx~=0.24.0
157-
httpx-v0.25: httpx~=0.25.0
158-
httpx-v0.27: httpx~=0.27.0
159-
httpx-latest: httpx
160-
161133
# OpenTelemetry (OTel)
162134
opentelemetry: opentelemetry-distro
163135

sentry_sdk/integrations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ def iter_default_integrations(with_auto_enabling_integrations):
141141
"gql": (3, 4, 1),
142142
"graphene": (3, 3),
143143
"grpc": (1, 32, 0), # grpcio
144+
"httpx": (0, 16, 0),
144145
"huggingface_hub": (0, 24, 7),
145146
"langchain": (0, 1, 0),
146147
"langgraph": (0, 6, 6),

tox.ini

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# The file (and all resulting CI YAMLs) then need to be regenerated via
1111
# "scripts/generate-test-files.sh".
1212
#
13-
# Last generated: 2025-09-18T10:26:22.484602+00:00
13+
# Last generated: 2025-09-18T10:42:56.677852+00:00
1414

1515
[tox]
1616
requires =
@@ -48,13 +48,6 @@ envlist =
4848
# GCP
4949
{py3.7}-gcp
5050

51-
# HTTPX
52-
{py3.6,py3.9}-httpx-v{0.16,0.18}
53-
{py3.6,py3.10}-httpx-v{0.20,0.22}
54-
{py3.7,py3.11,py3.12}-httpx-v{0.23,0.24}
55-
{py3.9,py3.11,py3.12}-httpx-v{0.25,0.27}
56-
{py3.9,py3.12,py3.13}-httpx-latest
57-
5851
# OpenTelemetry (OTel)
5952
{py3.7,py3.9,py3.12,py3.13}-opentelemetry
6053

@@ -202,6 +195,11 @@ envlist =
202195
{py3.7,py3.11,py3.12}-grpc-v1.62.3
203196
{py3.9,py3.12,py3.13}-grpc-v1.75.0
204197

198+
{py3.6,py3.8,py3.9}-httpx-v0.16.1
199+
{py3.6,py3.9,py3.10}-httpx-v0.20.0
200+
{py3.7,py3.10,py3.11}-httpx-v0.24.1
201+
{py3.9,py3.11,py3.12}-httpx-v0.28.1
202+
205203

206204
# ~~~ Tasks ~~~
207205
{py3.7,py3.9,py3.10}-arq-v0.23
@@ -368,27 +366,6 @@ deps =
368366
aws_lambda: requests
369367
aws_lambda: uvicorn
370368

371-
# HTTPX
372-
httpx-v0.16: pytest-httpx==0.10.0
373-
httpx-v0.18: pytest-httpx==0.12.0
374-
httpx-v0.20: pytest-httpx==0.14.0
375-
httpx-v0.22: pytest-httpx==0.19.0
376-
httpx-v0.23: pytest-httpx==0.21.0
377-
httpx-v0.24: pytest-httpx==0.22.0
378-
httpx-v0.25: pytest-httpx==0.25.0
379-
httpx: pytest-httpx
380-
# anyio is a dep of httpx
381-
httpx: anyio<4.0.0
382-
httpx-v0.16: httpx~=0.16.0
383-
httpx-v0.18: httpx~=0.18.0
384-
httpx-v0.20: httpx~=0.20.0
385-
httpx-v0.22: httpx~=0.22.0
386-
httpx-v0.23: httpx~=0.23.0
387-
httpx-v0.24: httpx~=0.24.0
388-
httpx-v0.25: httpx~=0.25.0
389-
httpx-v0.27: httpx~=0.27.0
390-
httpx-latest: httpx
391-
392369
# OpenTelemetry (OTel)
393370
opentelemetry: opentelemetry-distro
394371

@@ -592,6 +569,16 @@ deps =
592569
grpc: types-protobuf
593570
grpc: pytest-asyncio
594571

572+
httpx-v0.16.1: httpx==0.16.1
573+
httpx-v0.20.0: httpx==0.20.0
574+
httpx-v0.24.1: httpx==0.24.1
575+
httpx-v0.28.1: httpx==0.28.1
576+
httpx: anyio<4.0.0
577+
httpx-v0.16.1: pytest-httpx==0.10.0
578+
httpx-v0.20.0: pytest-httpx==0.14.0
579+
httpx-v0.24.1: pytest-httpx==0.22.0
580+
httpx-v0.28.1: pytest-httpx==0.35.0
581+
595582

596583
# ~~~ Tasks ~~~
597584
arq-v0.23: arq==0.23

0 commit comments

Comments
 (0)