Skip to content

Commit 1fa3a6f

Browse files
committed
Merge branch 'master' into antonpirker/better-aws-tests
2 parents d742102 + a3b6e5d commit 1fa3a6f

File tree

4 files changed

+101
-17
lines changed

4 files changed

+101
-17
lines changed

scripts/populate_tox/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,15 @@ integration_name: {
4545
rule2: [package3, package4, ...],
4646
},
4747
"python": python_version_specifier,
48+
"include": package_version_specifier,
4849
}
4950
```
5051

52+
When talking about version specifiers, we mean
53+
[version specifiers as defined](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5)
54+
by the Python Packaging Authority. See also the actual implementation
55+
in [packaging.specifiers](https://packaging.pypa.io/en/stable/specifiers.html).
56+
5157
### `package`
5258

5359
The name of the third party package as it's listed on PyPI. The script will
@@ -118,6 +124,35 @@ metadata or the SDK is explicitly not supporting some packages on specific
118124
Python versions (because of, for example, broken context vars), the `python`
119125
key can be used.
120126

127+
### `include`
128+
129+
Sometimes we only want to consider testing some specific versions of packages.
130+
For example, the Starlite package has two alpha prereleases of version 2.0.0, but
131+
we do not want to test these, since Starlite 2.0 was renamed to Litestar.
132+
133+
The value of the `include` key expects a version specifier defining which
134+
versions should be considered for testing. For example, since we only want to test
135+
versions below 2.x in Starlite, we can use
136+
137+
```python
138+
"starlite": {
139+
"include": "<2",
140+
...
141+
}
142+
```
143+
144+
The `include` key can also be used to exclude a set of specific versions by using
145+
`!=` version specifiers. For example, the Starlite restriction above could equivalently
146+
be expressed like so:
147+
148+
149+
```python
150+
"starlite": {
151+
"include": "!=2.0.0a1,!=2.0.0a2",
152+
...
153+
}
154+
```
155+
121156

122157
## How-Tos
123158

scripts/populate_tox/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
],
130130
},
131131
"python": "<=3.11",
132+
"include": "!=2.0.0a1,!=2.0.0a2", # these are not relevant as there will never be a stable 2.0 release (starlite continues as litestar)
132133
},
133134
"statsig": {
134135
"package": "statsig",

scripts/populate_tox/populate_tox.py

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def fetch_release(package: str, version: Version) -> dict:
111111

112112
def _prefilter_releases(
113113
integration: str, releases: dict[str, dict], older_than: Optional[datetime] = None
114-
) -> list[Version]:
114+
) -> tuple[list[Version], Optional[Version]]:
115115
"""
116116
Filter `releases`, removing releases that are for sure unsupported.
117117
@@ -120,6 +120,10 @@ def _prefilter_releases(
120120
they require additional API calls to be made. The purpose of this function is
121121
to slim down the list so that we don't have to make more API calls than
122122
necessary for releases that are for sure not supported.
123+
124+
The function returns a tuple with:
125+
- the list of prefiltered releases
126+
- an optional prerelease if there is one that should be tested
123127
"""
124128
min_supported = _MIN_VERSIONS.get(integration)
125129
if min_supported is not None:
@@ -129,7 +133,14 @@ def _prefilter_releases(
129133
f" {integration} doesn't have a minimum version defined in sentry_sdk/integrations/__init__.py. Consider defining one"
130134
)
131135

136+
include_versions = None
137+
if TEST_SUITE_CONFIG[integration].get("include") is not None:
138+
include_versions = SpecifierSet(
139+
TEST_SUITE_CONFIG[integration]["include"], prereleases=True
140+
)
141+
132142
filtered_releases = []
143+
last_prerelease = None
133144

134145
for release, data in releases.items():
135146
if not data:
@@ -149,9 +160,15 @@ def _prefilter_releases(
149160
if min_supported and version < min_supported:
150161
continue
151162

152-
if version.is_prerelease or version.is_postrelease:
153-
# TODO: consider the newest prerelease unless obsolete
154-
# https://github.com/getsentry/sentry-python/issues/4030
163+
if version.is_postrelease or version.is_devrelease:
164+
continue
165+
166+
if include_versions is not None and version not in include_versions:
167+
continue
168+
169+
if version.is_prerelease:
170+
if last_prerelease is None or version > last_prerelease:
171+
last_prerelease = version
155172
continue
156173

157174
for i, saved_version in enumerate(filtered_releases):
@@ -166,18 +183,30 @@ def _prefilter_releases(
166183
else:
167184
filtered_releases.append(version)
168185

169-
return sorted(filtered_releases)
186+
filtered_releases.sort()
187+
188+
# Check if the latest prerelease is relevant (i.e., it's for a version higher
189+
# than the last released version); if not, don't consider it
190+
if last_prerelease is not None:
191+
if not filtered_releases or last_prerelease > filtered_releases[-1]:
192+
return filtered_releases, last_prerelease
193+
194+
return filtered_releases, None
170195

171196

172197
def get_supported_releases(
173198
integration: str, pypi_data: dict, older_than: Optional[datetime] = None
174-
) -> list[Version]:
199+
) -> tuple[list[Version], Optional[Version]]:
175200
"""
176201
Get a list of releases that are currently supported by the SDK.
177202
178203
This takes into account a handful of parameters (Python support, the lowest
179204
version we've defined for the framework, the date of the release).
180205
206+
We return the list of supported releases and optionally also the newest
207+
prerelease, if it should be tested (meaning it's for a version higher than
208+
the current stable version).
209+
181210
If an `older_than` timestamp is provided, no release newer than that will be
182211
considered.
183212
"""
@@ -186,7 +215,9 @@ def get_supported_releases(
186215
# Get a consolidated list without taking into account Python support yet
187216
# (because that might require an additional API call for some
188217
# of the releases)
189-
releases = _prefilter_releases(integration, pypi_data["releases"], older_than)
218+
releases, latest_prerelease = _prefilter_releases(
219+
integration, pypi_data["releases"], older_than
220+
)
190221

191222
# Determine Python support
192223
expected_python_versions = TEST_SUITE_CONFIG[integration].get("python")
@@ -210,14 +241,18 @@ def _supports_lowest(release: Version) -> bool:
210241
# version(s) that we do, cut off the rest
211242
releases = releases[i:]
212243

213-
return releases
244+
return releases, latest_prerelease
214245

215246

216-
def pick_releases_to_test(releases: list[Version]) -> list[Version]:
247+
def pick_releases_to_test(
248+
releases: list[Version], last_prerelease: Optional[Version]
249+
) -> list[Version]:
217250
"""Pick a handful of releases to test from a sorted list of supported releases."""
218251
# If the package has majors (or major-like releases, even if they don't do
219252
# semver), we want to make sure we're testing them all. If not, we just pick
220253
# the oldest, the newest, and a couple in between.
254+
#
255+
# If there is a relevant prerelease, also test that in addition to the above.
221256
has_majors = len(set([v.major for v in releases])) > 1
222257
filtered_releases = set()
223258

@@ -252,7 +287,11 @@ def pick_releases_to_test(releases: list[Version]) -> list[Version]:
252287
releases[-1], # latest
253288
}
254289

255-
return sorted(filtered_releases)
290+
filtered_releases = sorted(filtered_releases)
291+
if last_prerelease is not None:
292+
filtered_releases.append(last_prerelease)
293+
294+
return filtered_releases
256295

257296

258297
def supported_python_versions(
@@ -553,19 +592,24 @@ def main(fail_on_changes: bool = False) -> None:
553592
pypi_data = fetch_package(package)
554593

555594
# Get the list of all supported releases
556-
# If in check mode, ignore releases newer than `last_updated`
595+
596+
# If in fail-on-changes mode, ignore releases newer than `last_updated`
557597
older_than = last_updated if fail_on_changes else None
558-
releases = get_supported_releases(integration, pypi_data, older_than)
598+
599+
releases, latest_prerelease = get_supported_releases(
600+
integration, pypi_data, older_than
601+
)
602+
559603
if not releases:
560604
print(" Found no supported releases.")
561605
continue
562606

563607
_compare_min_version_with_defined(integration, releases)
564608

565609
# Pick a handful of the supported releases to actually test against
566-
# and fetch the PYPI data for each to determine which Python versions
610+
# and fetch the PyPI data for each to determine which Python versions
567611
# to test it on
568-
test_releases = pick_releases_to_test(releases)
612+
test_releases = pick_releases_to_test(releases, latest_prerelease)
569613

570614
for release in test_releases:
571615
_add_python_versions_to_release(integration, package, release)

tox.ini

Lines changed: 7 additions & 3 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-02-18T12:57:32.874168+00:00
13+
# Last generated: 2025-02-19T12:41:15.689786+00:00
1414

1515
[tox]
1616
requires =
@@ -211,10 +211,11 @@ envlist =
211211
{py3.8,py3.10,py3.11}-ariadne-v0.20.1
212212
{py3.8,py3.11,py3.12}-ariadne-v0.22
213213
{py3.8,py3.11,py3.12}-ariadne-v0.24.0
214-
{py3.8,py3.11,py3.12}-ariadne-v0.25.2
214+
{py3.9,py3.12,py3.13}-ariadne-v0.26.0
215215

216216
{py3.6,py3.9,py3.10}-gql-v3.4.1
217217
{py3.7,py3.11,py3.12}-gql-v3.5.0
218+
{py3.9,py3.12,py3.13}-gql-v3.6.0b4
218219

219220
{py3.6,py3.9,py3.10}-graphene-v3.3
220221
{py3.8,py3.12,py3.13}-graphene-v3.4.3
@@ -236,6 +237,7 @@ envlist =
236237
{py3.6,py3.7,py3.8}-celery-v4.4.7
237238
{py3.6,py3.7,py3.8}-celery-v5.0.5
238239
{py3.8,py3.11,py3.12}-celery-v5.4.0
240+
{py3.8,py3.12,py3.13}-celery-v5.5.0rc4
239241

240242
{py3.6,py3.7}-dramatiq-v1.9.0
241243
{py3.6,py3.8,py3.9}-dramatiq-v1.12.3
@@ -597,13 +599,14 @@ deps =
597599
ariadne-v0.20.1: ariadne==0.20.1
598600
ariadne-v0.22: ariadne==0.22
599601
ariadne-v0.24.0: ariadne==0.24.0
600-
ariadne-v0.25.2: ariadne==0.25.2
602+
ariadne-v0.26.0: ariadne==0.26.0
601603
ariadne: fastapi
602604
ariadne: flask
603605
ariadne: httpx
604606

605607
gql-v3.4.1: gql[all]==3.4.1
606608
gql-v3.5.0: gql[all]==3.5.0
609+
gql-v3.6.0b4: gql[all]==3.6.0b4
607610

608611
graphene-v3.3: graphene==3.3
609612
graphene-v3.4.3: graphene==3.4.3
@@ -635,6 +638,7 @@ deps =
635638
celery-v4.4.7: celery==4.4.7
636639
celery-v5.0.5: celery==5.0.5
637640
celery-v5.4.0: celery==5.4.0
641+
celery-v5.5.0rc4: celery==5.5.0rc4
638642
celery: newrelic
639643
celery: redis
640644
py3.7-celery: importlib-metadata<5.0

0 commit comments

Comments
 (0)