Skip to content
Merged
67 changes: 0 additions & 67 deletions .github/workflows/test-integrations-network.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,73 +22,6 @@ env:
CACHED_BUILD_PATHS: |
${{ github.workspace }}/dist-serverless
jobs:
test-network-latest:
name: Network (latest)
timeout-minutes: 30
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["3.9","3.12","3.13"]
# python3.6 reached EOL and is no longer being supported on
# new versions of hosted runners on Github Actions
# ubuntu-20.04 is the last version that supported python3.6
# see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877
os: [ubuntu-22.04]
# Use Docker container only for Python 3.6
container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }}
steps:
- uses: actions/checkout@v5.0.0
- uses: actions/setup-python@v6
if: ${{ matrix.python-version != '3.6' }}
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Setup Test Env
run: |
pip install "coverage[toml]" tox
- name: Erase coverage
run: |
coverage erase
- name: Test grpc latest
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-grpc-latest"
- name: Test httpx latest
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-httpx-latest"
- name: Test requests latest
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-requests-latest"
- name: Generate coverage XML (Python 3.6)
if: ${{ !cancelled() && matrix.python-version == '3.6' }}
run: |
export COVERAGE_RCFILE=.coveragerc36
coverage combine .coverage-sentry-*
coverage xml --ignore-errors
- name: Generate coverage XML
if: ${{ !cancelled() && matrix.python-version != '3.6' }}
run: |
coverage combine .coverage-sentry-*
coverage xml
- name: Upload coverage to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5.5.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
# make sure no plugins alter our coverage reports
plugins: noop
verbose: true
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: .junitxml
verbose: true
test-network-pinned:
name: Network (pinned)
timeout-minutes: 30
Expand Down
34 changes: 27 additions & 7 deletions scripts/populate_tox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,14 @@ This key is optional.
### `python`

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

For example, if you want AIOHTTP tests to only run on Python 3.7+, you can say:
There are two variants how to define the Python versions to run the test suite
on.

If you want the test suite to only be run on specific Python versions, you can
set `python` to a version specifier. For example, if you want AIOHTTP tests to
only run on Python 3.7+, you can say:

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

If the Python version to use is dependent on the version of the package under
test, you can use the more expressive dictionary variant. For instance, while
HTTPX v0.28 supports Python 3.8, a test dependency of ours, `pytest-httpx`,
doesn't. If you want to specify that HTTPX test suite should not be run on
a Python version older than 3.9 if the HTTPX version is 0.28 or higher, you can
say:

```python
"httpx": {
"python": {
# run the test suite for httpx v0.28+ on Python 3.9+ only
">=0.28": ">=3.9",
},
}
```

The `python` key is optional, and when possible, it should be omitted. The script
should automatically detect which Python versions the package supports.
However, if a package has broken
metadata or the SDK is explicitly not supporting some packages on specific
Python versions (because of, for example, broken context vars), the `python`
key can be used.
should automatically detect which Python versions the package supports. However,
if a package has broken metadata or the SDK is explicitly not supporting some
packages on specific Python versions (because of, for example, broken context
vars), the `python` key can be used.

### `include`

Expand Down
19 changes: 19 additions & 0 deletions scripts/populate_tox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,25 @@
},
"python": ">=3.7",
},
"httpx": {
"package": "httpx",
"deps": {
"*": ["anyio<4.0.0"],
">=0.16,<0.17": ["pytest-httpx==0.10.0"],
">=0.17,<0.19": ["pytest-httpx==0.12.0"],
">=0.19,<0.21": ["pytest-httpx==0.14.0"],
">=0.21,<0.23": ["pytest-httpx==0.19.0"],
">=0.23,<0.24": ["pytest-httpx==0.21.0"],
">=0.24,<0.25": ["pytest-httpx==0.22.0"],
">=0.25,<0.26": ["pytest-httpx==0.25.0"],
">=0.26,<0.27": ["pytest-httpx==0.28.0"],
">=0.27,<0.28": ["pytest-httpx==0.30.0"],
">=0.28,<0.29": ["pytest-httpx==0.35.0"],
},
"python": {
">=0.28": ">=3.9",
},
},
"huey": {
"package": "huey",
},
Expand Down
56 changes: 46 additions & 10 deletions scripts/populate_tox/populate_tox.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,12 @@
"aws_lambda",
"cloud_resource_context",
"common",
"gcp",
"gevent",
"opentelemetry",
"potel",
# Integrations that can be migrated -- we should eventually remove all
# of these from the IGNORE list
"gcp",
"httpx",
"redis",
"requests",
"rq",
Expand Down Expand Up @@ -240,9 +239,9 @@ def _supports_lowest(release: Version) -> bool:
sys.exit(1)

py_versions = determine_python_versions(pypi_data)
target_python_versions = TEST_SUITE_CONFIG[integration].get("python")
if target_python_versions:
target_python_versions = SpecifierSet(target_python_versions)
target_python_versions = _transform_target_python_versions(
TEST_SUITE_CONFIG[integration].get("python")
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing Parameter Causes Version Constraint Ignore

The _supports_lowest function calls supported_python_versions without passing the release parameter. This prevents supported_python_versions from correctly processing dictionary-based Python version constraints (e.g., for httpx), which require the release parameter. Consequently, these constraints are ignored, leading _supports_lowest to incorrectly return False.

Fix in Cursor Fix in Web

return bool(supported_python_versions(py_versions, target_python_versions))

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

def supported_python_versions(
package_python_versions: Union[SpecifierSet, list[Version]],
custom_supported_versions: Optional[SpecifierSet] = None,
custom_supported_versions: Optional[
Union[SpecifierSet, dict[SpecifierSet, SpecifierSet]]
] = None,
version: Optional[Version] = None,
) -> list[Version]:
"""
Get the intersection of Python versions supported by the package and the SDK.
Expand All @@ -354,9 +356,25 @@ def supported_python_versions(
curr = MIN_PYTHON_VERSION
while curr <= MAX_PYTHON_VERSION:
if curr in package_python_versions:
if not custom_supported_versions or curr in custom_supported_versions:
if not custom_supported_versions:
supported.append(curr)

else:
if isinstance(custom_supported_versions, SpecifierSet):
if curr in custom_supported_versions:
supported.append(curr)

elif version is not None and isinstance(
custom_supported_versions, dict
):
for v, py in custom_supported_versions.items():
if version in v:
if curr in py:
supported.append(curr)
break
else:
supported.append(curr)

# Construct the next Python version (i.e., bump the minor)
next = [int(v) for v in str(curr).split(".")]
next[1] += 1
Expand Down Expand Up @@ -535,20 +553,38 @@ def _add_python_versions_to_release(

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

target_python_versions = TEST_SUITE_CONFIG[integration].get("python")
if target_python_versions:
target_python_versions = SpecifierSet(target_python_versions)
target_python_versions = _transform_target_python_versions(
TEST_SUITE_CONFIG[integration].get("python")
)

release.python_versions = pick_python_versions_to_test(
supported_python_versions(
determine_python_versions(release_pypi_data),
target_python_versions,
release,
)
)

release.rendered_python_versions = _render_python_versions(release.python_versions)


def _transform_target_python_versions(
python_versions: Union[str, dict[str, str], None]
) -> Union[SpecifierSet, dict[SpecifierSet, SpecifierSet], None]:
"""Wrap the contents of the `python` key in SpecifierSets."""
if not python_versions:
return None

if isinstance(python_versions, str):
return SpecifierSet(python_versions)

if isinstance(python_versions, dict):
updated = {}
for key, value in python_versions.items():
updated[SpecifierSet(key)] = SpecifierSet(value)
return updated


def get_file_hash() -> str:
"""Calculate a hash of the tox.ini file."""
hasher = hashlib.md5()
Expand Down
28 changes: 0 additions & 28 deletions scripts/populate_tox/tox.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ envlist =
# GCP
{py3.7}-gcp

# HTTPX
{py3.6,py3.9}-httpx-v{0.16,0.18}
{py3.6,py3.10}-httpx-v{0.20,0.22}
{py3.7,py3.11,py3.12}-httpx-v{0.23,0.24}
{py3.9,py3.11,py3.12}-httpx-v{0.25,0.27}
{py3.9,py3.12,py3.13}-httpx-latest

# OpenTelemetry (OTel)
{py3.7,py3.9,py3.12,py3.13}-opentelemetry

Expand Down Expand Up @@ -137,27 +130,6 @@ deps =
aws_lambda: requests
aws_lambda: uvicorn

# HTTPX
httpx-v0.16: pytest-httpx==0.10.0
httpx-v0.18: pytest-httpx==0.12.0
httpx-v0.20: pytest-httpx==0.14.0
httpx-v0.22: pytest-httpx==0.19.0
httpx-v0.23: pytest-httpx==0.21.0
httpx-v0.24: pytest-httpx==0.22.0
httpx-v0.25: pytest-httpx==0.25.0
httpx: pytest-httpx
# anyio is a dep of httpx
httpx: anyio<4.0.0
httpx-v0.16: httpx~=0.16.0
httpx-v0.18: httpx~=0.18.0
httpx-v0.20: httpx~=0.20.0
httpx-v0.22: httpx~=0.22.0
httpx-v0.23: httpx~=0.23.0
httpx-v0.24: httpx~=0.24.0
httpx-v0.25: httpx~=0.25.0
httpx-v0.27: httpx~=0.27.0
httpx-latest: httpx

# OpenTelemetry (OTel)
opentelemetry: opentelemetry-distro

Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ def iter_default_integrations(with_auto_enabling_integrations):
"gql": (3, 4, 1),
"graphene": (3, 3),
"grpc": (1, 32, 0), # grpcio
"httpx": (0, 16, 0),
"huggingface_hub": (0, 24, 7),
"langchain": (0, 1, 0),
"langgraph": (0, 6, 6),
Expand Down
45 changes: 16 additions & 29 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# The file (and all resulting CI YAMLs) then need to be regenerated via
# "scripts/generate-test-files.sh".
#
# Last generated: 2025-09-18T10:26:22.484602+00:00
# Last generated: 2025-09-18T10:42:56.677852+00:00

[tox]
requires =
Expand Down Expand Up @@ -48,13 +48,6 @@ envlist =
# GCP
{py3.7}-gcp

# HTTPX
{py3.6,py3.9}-httpx-v{0.16,0.18}
{py3.6,py3.10}-httpx-v{0.20,0.22}
{py3.7,py3.11,py3.12}-httpx-v{0.23,0.24}
{py3.9,py3.11,py3.12}-httpx-v{0.25,0.27}
{py3.9,py3.12,py3.13}-httpx-latest

# OpenTelemetry (OTel)
{py3.7,py3.9,py3.12,py3.13}-opentelemetry

Expand Down Expand Up @@ -202,6 +195,11 @@ envlist =
{py3.7,py3.11,py3.12}-grpc-v1.62.3
{py3.9,py3.12,py3.13}-grpc-v1.75.0

{py3.6,py3.8,py3.9}-httpx-v0.16.1
{py3.6,py3.9,py3.10}-httpx-v0.20.0
{py3.7,py3.10,py3.11}-httpx-v0.24.1
{py3.9,py3.11,py3.12}-httpx-v0.28.1


# ~~~ Tasks ~~~
{py3.7,py3.9,py3.10}-arq-v0.23
Expand Down Expand Up @@ -368,27 +366,6 @@ deps =
aws_lambda: requests
aws_lambda: uvicorn

# HTTPX
httpx-v0.16: pytest-httpx==0.10.0
httpx-v0.18: pytest-httpx==0.12.0
httpx-v0.20: pytest-httpx==0.14.0
httpx-v0.22: pytest-httpx==0.19.0
httpx-v0.23: pytest-httpx==0.21.0
httpx-v0.24: pytest-httpx==0.22.0
httpx-v0.25: pytest-httpx==0.25.0
httpx: pytest-httpx
# anyio is a dep of httpx
httpx: anyio<4.0.0
httpx-v0.16: httpx~=0.16.0
httpx-v0.18: httpx~=0.18.0
httpx-v0.20: httpx~=0.20.0
httpx-v0.22: httpx~=0.22.0
httpx-v0.23: httpx~=0.23.0
httpx-v0.24: httpx~=0.24.0
httpx-v0.25: httpx~=0.25.0
httpx-v0.27: httpx~=0.27.0
httpx-latest: httpx

# OpenTelemetry (OTel)
opentelemetry: opentelemetry-distro

Expand Down Expand Up @@ -592,6 +569,16 @@ deps =
grpc: types-protobuf
grpc: pytest-asyncio

httpx-v0.16.1: httpx==0.16.1
httpx-v0.20.0: httpx==0.20.0
httpx-v0.24.1: httpx==0.24.1
httpx-v0.28.1: httpx==0.28.1
httpx: anyio<4.0.0
httpx-v0.16.1: pytest-httpx==0.10.0
httpx-v0.20.0: pytest-httpx==0.14.0
httpx-v0.24.1: pytest-httpx==0.22.0
httpx-v0.28.1: pytest-httpx==0.35.0


# ~~~ Tasks ~~~
arq-v0.23: arq==0.23
Expand Down