Skip to content

Commit 7bebf79

Browse files
committed
Merge branch 'potel-base' into potel-base-run-all-tests
2 parents 8411980 + e41b24a commit 7bebf79

File tree

25 files changed

+391
-380
lines changed

25 files changed

+391
-380
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Do not edit this YAML file. This file is generated automatically by executing
2+
# python scripts/split_tox_gh_actions/split_tox_gh_actions.py
3+
# The template responsible for it is in
4+
# scripts/split_tox_gh_actions/templates/base.jinja
5+
name: Test Flags
6+
on:
7+
push:
8+
branches:
9+
- master
10+
- release/**
11+
- potel-base
12+
pull_request:
13+
# Cancel in progress workflows on pull_requests.
14+
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
17+
cancel-in-progress: true
18+
permissions:
19+
contents: read
20+
env:
21+
BUILD_CACHE_KEY: ${{ github.sha }}
22+
CACHED_BUILD_PATHS: |
23+
${{ github.workspace }}/dist-serverless
24+
jobs:
25+
test-flags-latest:
26+
name: Flags (latest)
27+
timeout-minutes: 30
28+
runs-on: ${{ matrix.os }}
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
python-version: ["3.8","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-20.04]
38+
steps:
39+
- uses: actions/[email protected]
40+
- uses: actions/setup-python@v5
41+
with:
42+
python-version: ${{ matrix.python-version }}
43+
allow-prereleases: true
44+
- name: Setup Test Env
45+
run: |
46+
pip install "coverage[toml]" tox
47+
- name: Erase coverage
48+
run: |
49+
coverage erase
50+
- name: Test launchdarkly latest
51+
run: |
52+
set -x # print commands that are executed
53+
./scripts/runtox.sh "py${{ matrix.python-version }}-launchdarkly-latest"
54+
- name: Test openfeature latest
55+
run: |
56+
set -x # print commands that are executed
57+
./scripts/runtox.sh "py${{ matrix.python-version }}-openfeature-latest"
58+
- name: Test unleash latest
59+
run: |
60+
set -x # print commands that are executed
61+
./scripts/runtox.sh "py${{ matrix.python-version }}-unleash-latest"
62+
- name: Generate coverage XML (Python 3.6)
63+
if: ${{ !cancelled() && matrix.python-version == '3.6' }}
64+
run: |
65+
export COVERAGE_RCFILE=.coveragerc36
66+
coverage combine .coverage-sentry-*
67+
coverage xml --ignore-errors
68+
- name: Generate coverage XML
69+
if: ${{ !cancelled() && matrix.python-version != '3.6' }}
70+
run: |
71+
coverage combine .coverage-sentry-*
72+
coverage xml
73+
- name: Upload coverage to Codecov
74+
if: ${{ !cancelled() }}
75+
uses: codecov/[email protected]
76+
with:
77+
token: ${{ secrets.CODECOV_TOKEN }}
78+
files: coverage.xml
79+
# make sure no plugins alter our coverage reports
80+
plugin: noop
81+
verbose: true
82+
- name: Upload test results to Codecov
83+
if: ${{ !cancelled() }}
84+
uses: codecov/test-results-action@v1
85+
with:
86+
token: ${{ secrets.CODECOV_TOKEN }}
87+
files: .junitxml
88+
verbose: true
89+
test-flags-pinned:
90+
name: Flags (pinned)
91+
timeout-minutes: 30
92+
runs-on: ${{ matrix.os }}
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
python-version: ["3.8","3.12","3.13"]
97+
# python3.6 reached EOL and is no longer being supported on
98+
# new versions of hosted runners on Github Actions
99+
# ubuntu-20.04 is the last version that supported python3.6
100+
# see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877
101+
os: [ubuntu-20.04]
102+
steps:
103+
- uses: actions/[email protected]
104+
- uses: actions/setup-python@v5
105+
with:
106+
python-version: ${{ matrix.python-version }}
107+
allow-prereleases: true
108+
- name: Setup Test Env
109+
run: |
110+
pip install "coverage[toml]" tox
111+
- name: Erase coverage
112+
run: |
113+
coverage erase
114+
- name: Test launchdarkly pinned
115+
run: |
116+
set -x # print commands that are executed
117+
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-launchdarkly"
118+
- name: Test openfeature pinned
119+
run: |
120+
set -x # print commands that are executed
121+
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-openfeature"
122+
- name: Test unleash pinned
123+
run: |
124+
set -x # print commands that are executed
125+
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-unleash"
126+
- name: Generate coverage XML (Python 3.6)
127+
if: ${{ !cancelled() && matrix.python-version == '3.6' }}
128+
run: |
129+
export COVERAGE_RCFILE=.coveragerc36
130+
coverage combine .coverage-sentry-*
131+
coverage xml --ignore-errors
132+
- name: Generate coverage XML
133+
if: ${{ !cancelled() && matrix.python-version != '3.6' }}
134+
run: |
135+
coverage combine .coverage-sentry-*
136+
coverage xml
137+
- name: Upload coverage to Codecov
138+
if: ${{ !cancelled() }}
139+
uses: codecov/[email protected]
140+
with:
141+
token: ${{ secrets.CODECOV_TOKEN }}
142+
files: coverage.xml
143+
# make sure no plugins alter our coverage reports
144+
plugin: noop
145+
verbose: true
146+
- name: Upload test results to Codecov
147+
if: ${{ !cancelled() }}
148+
uses: codecov/test-results-action@v1
149+
with:
150+
token: ${{ secrets.CODECOV_TOKEN }}
151+
files: .junitxml
152+
verbose: true
153+
check_required_tests:
154+
name: All pinned Flags tests passed
155+
needs: test-flags-pinned
156+
# Always run this, even if a dependent job failed
157+
if: always()
158+
runs-on: ubuntu-20.04
159+
steps:
160+
- name: Check for failures
161+
if: contains(needs.test-flags-pinned.result, 'failure') || contains(needs.test-flags-pinned.result, 'skipped')
162+
run: |
163+
echo "One of the dependent jobs has failed. You may need to re-run it." && exit 1

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# Changelog
22

3+
## 2.20.0
4+
5+
- **New integration:** Add [Typer](https://typer.tiangolo.com/) integration (#3869) by @patrick91
6+
7+
For more information, see the documentation for the [TyperIntegration](https://docs.sentry.io/platforms/python/integrations/typer/).
8+
9+
- **New integration:** Add [Unleash](https://www.getunleash.io/) feature flagging integration (#3888) by @aliu39
10+
11+
For more information, see the documentation for the [UnleashIntegration](https://docs.sentry.io/platforms/python/integrations/unleash/).
12+
13+
- Add custom tracking of feature flag evaluations (#3860) by @aliu39
14+
- Feature Flags: Register LD hook in setup instead of init, and don't check for initialization (#3890) by @aliu39
15+
- Feature Flags: Moved adding of `flags` context into Scope (#3917) by @antonpirker
16+
- Create a separate group for feature flag test suites (#3911) by @sentrivana
17+
- Fix flaky LaunchDarkly tests (#3896) by @aliu39
18+
- Fix LRU cache copying (#3883) by @ffelixg
19+
- Fix cache pollution from mutable reference (#3887) by @cmanallen
20+
- Centralize minimum version checking (#3910) by @sentrivana
21+
- Support SparkIntegration activation after SparkContext created (#3411) by @seyoon-lim
22+
- Preserve ARQ enqueue_job __kwdefaults__ after patching (#3903) by @danmr
23+
- Add Github workflow to comment on issues when a fix was released (#3866) by @antonpirker
24+
- Update test matrix for Sanic (#3904) by @antonpirker
25+
- Rename scripts (#3885) by @sentrivana
26+
- Fix CI (#3878) by @sentrivana
27+
- Treat `potel-base` as release branch in CI (#3912) by @sentrivana
28+
- build(deps): bump actions/create-github-app-token from 1.11.0 to 1.11.1 (#3893) by @dependabot
29+
- build(deps): bump codecov/codecov-action from 5.0.7 to 5.1.1 (#3867) by @dependabot
30+
- build(deps): bump codecov/codecov-action from 5.1.1 to 5.1.2 (#3892) by @dependabot
31+
332
## 2.19.2
433

534
### Various fixes & improvements
@@ -55,6 +84,14 @@
5584

5685
### Various fixes & improvements
5786

87+
- **New integration:** Add [LaunchDarkly](https://launchdarkly.com/) integration (#3648) by @cmanallen
88+
89+
For more information, see the documentation for the [LaunchDarklyIntegration](https://docs.sentry.io/platforms/python/integrations/launchdarkly/).
90+
91+
- **New integration:** Add [OpenFeature](https://openfeature.dev/) feature flagging integration (#3648) by @cmanallen
92+
93+
For more information, see the documentation for the [OpenFeatureIntegration](https://docs.sentry.io/platforms/python/integrations/opoenfeature/).
94+
5895
- Add LaunchDarkly and OpenFeature integration (#3648) by @cmanallen
5996
- Correct typo in a comment (#3726) by @szokeasaurusrex
6097
- End `http.client` span on timeout (#3723) by @Zylphrex

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year)
3232
author = "Sentry Team and Contributors"
3333

34-
release = "2.19.2"
34+
release = "2.20.0"
3535
version = ".".join(release.split(".")[:2]) # The short X.Y version.
3636

3737

scripts/split_tox_gh_actions/split_tox_gh_actions.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,6 @@
7676
"cloud_resource_context",
7777
"gcp",
7878
],
79-
"Tasks": [
80-
"arq",
81-
"beam",
82-
"celery",
83-
"dramatiq",
84-
"huey",
85-
"ray",
86-
"rq",
87-
"spark",
88-
],
8979
"DBs": [
9080
"asyncpg",
9181
"clickhouse_driver",
@@ -94,6 +84,11 @@
9484
"redis_py_cluster_legacy",
9585
"sqlalchemy",
9686
],
87+
"Flags": [
88+
"launchdarkly",
89+
"openfeature",
90+
"unleash",
91+
],
9792
"GraphQL": [
9893
"ariadne",
9994
"gql",
@@ -106,6 +101,16 @@
106101
"httpx",
107102
"requests",
108103
],
104+
"Tasks": [
105+
"arq",
106+
"beam",
107+
"celery",
108+
"dramatiq",
109+
"huey",
110+
"ray",
111+
"rq",
112+
"spark",
113+
],
109114
"Web 1": [
110115
"django",
111116
"flask",
@@ -125,15 +130,12 @@
125130
"tornado",
126131
],
127132
"Misc": [
128-
"launchdarkly",
129133
"loguru",
130-
"openfeature",
131134
"opentelemetry",
132135
"potel",
133136
"pure_eval",
134137
"trytond",
135138
"typer",
136-
"unleash",
137139
],
138140
}
139141

sentry_sdk/ai/monitoring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import sentry_sdk.utils
55
from sentry_sdk import start_span
6-
from sentry_sdk.tracing import Span
6+
from sentry_sdk.tracing import POTelSpan as Span
77
from sentry_sdk.utils import ContextVar
88

99
from typing import TYPE_CHECKING

sentry_sdk/ai/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
if TYPE_CHECKING:
44
from typing import Any
55

6-
from sentry_sdk.tracing import Span
6+
from sentry_sdk.tracing import POTelSpan as Span
77
from sentry_sdk.utils import logger
88

99

sentry_sdk/consts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,4 +567,4 @@ def _get_default_options():
567567
del _get_default_options
568568

569569

570-
VERSION = "2.19.2"
570+
VERSION = "2.20.0"
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
from typing import TYPE_CHECKING
2-
31
import sentry_sdk
42
from sentry_sdk._lru_cache import LRUCache
53

4+
from typing import TYPE_CHECKING
5+
66
if TYPE_CHECKING:
7-
from typing import TypedDict, Optional
8-
from sentry_sdk._types import Event, ExcInfo
7+
from typing import TypedDict
98

109
FlagData = TypedDict("FlagData", {"flag": str, "result": bool})
1110

@@ -33,8 +32,11 @@ def set(self, flag, result):
3332
self.buffer.set(flag, result)
3433

3534

36-
def flag_error_processor(event, exc_info):
37-
# type: (Event, ExcInfo) -> Optional[Event]
38-
scope = sentry_sdk.get_current_scope()
39-
event["contexts"]["flags"] = {"values": scope.flags.get()}
40-
return event
35+
def add_feature_flag(flag, result):
36+
# type: (str, bool) -> None
37+
"""
38+
Records a flag and its value to be sent on subsequent error events.
39+
We recommend you do this on flag evaluations. Flags are buffered per Sentry scope.
40+
"""
41+
flags = sentry_sdk.get_current_scope().flags
42+
flags.set(flag, result)

sentry_sdk/integrations/aws_lambda.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from copy import deepcopy
66
from datetime import datetime, timedelta, timezone
77
from os import environ
8+
from urllib.parse import urlencode
89

910
import sentry_sdk
1011
from sentry_sdk.consts import OP
@@ -120,6 +121,9 @@ def sentry_handler(aws_event, aws_context, *args, **kwargs):
120121
configured_time = aws_context.get_remaining_time_in_millis()
121122

122123
with sentry_sdk.isolation_scope() as scope:
124+
scope.set_transaction_name(
125+
aws_context.function_name, source=TRANSACTION_SOURCE_COMPONENT
126+
)
123127
timeout_thread = None
124128
with capture_internal_exceptions():
125129
scope.clear_breadcrumbs()
@@ -333,7 +337,7 @@ def event_processor(sentry_event, hint, start_time=start_time):
333337
request["url"] = _get_url(aws_event, aws_context)
334338

335339
if "queryStringParameters" in aws_event:
336-
request["query_string"] = aws_event["queryStringParameters"]
340+
request["query_string"] = urlencode(aws_event["queryStringParameters"])
337341

338342
if "headers" in aws_event:
339343
request["headers"] = _filter_headers(aws_event["headers"])
@@ -373,7 +377,9 @@ def _get_url(aws_event, aws_context):
373377
path = aws_event.get("path", None)
374378

375379
headers = aws_event.get("headers")
376-
if headers is None:
380+
# Some AWS Services (ie. EventBridge) set headers as a list
381+
# or None, so we must ensure it is a dict
382+
if not isinstance(headers, dict):
377383
headers = {}
378384

379385
host = headers.get("Host", None)
@@ -478,7 +484,10 @@ def _prepopulate_attributes(aws_event, aws_context):
478484

479485
for prop, attr in EVENT_TO_ATTRIBUTES.items():
480486
if aws_event.get(prop) is not None:
481-
attributes[attr] = aws_event[prop]
487+
if prop == "queryStringParameters":
488+
attributes[attr] = urlencode(aws_event[prop])
489+
else:
490+
attributes[attr] = aws_event[prop]
482491

483492
for prop, attr in CONTEXT_TO_ATTRIBUTES.items():
484493
if getattr(aws_context, prop, None) is not None:
@@ -487,7 +496,7 @@ def _prepopulate_attributes(aws_event, aws_context):
487496
url = _get_url(aws_event, aws_context)
488497
if url:
489498
if aws_event.get("queryStringParameters"):
490-
url += f"?{aws_event['queryStringParameters']}"
499+
url += f"?{urlencode(aws_event['queryStringParameters'])}"
491500
attributes["url.full"] = url
492501

493502
headers = {}

0 commit comments

Comments
 (0)