Skip to content

Commit 64f7284

Browse files
committed
Merge branch 'master' into servusdei2018/master
2 parents 5e3f606 + 8d56b30 commit 64f7284

File tree

21 files changed

+1840
-414
lines changed

21 files changed

+1840
-414
lines changed

.claude/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@
2727
"WebFetch(domain:docs.sentry.io)",
2828
"WebFetch(domain:develop.sentry.dev)",
2929
"Bash(grep:*)",
30-
"Bash(mv:*)"
30+
"Bash(mv:*)",
31+
"Bash(source .venv/bin/activate)",
32+
"Bash(tox:*)",
33+
"Bash(tox.venv/bin/tox:*)",
34+
"Bash(.tox/*/bin/python:*)",
35+
"Bash(.tox/*/bin/pytest:*)",
36+
"Bash(.tox/*/bin/ruff:*)"
3137
],
3238
"deny": []
3339
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ sentry-python-serverless*.zip
2121
.eggs
2222
venv
2323
.venv
24+
tox.venv
25+
toxgen.venv
2426
.vscode/tags
2527
.pytest_cache
2628
.hypothesis

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Use **tox** for testing (not pytest directly):
1111
- Test matrix configuration is in `tox.ini`
1212
- Integration tests: `tox -e py3.14-{integration}-v{version}`
1313
- Common tests: `tox -e py3.14-common`
14+
- Run specific test file: `TESTPATH=tests/integrations/logging/test_logging.py tox -e py3.14-common`
15+
- Run single test: `TESTPATH=tests/path/to/test_file.py tox -e py3.14-common -- -k "test_name"`
1416

1517
## Type Checking
1618

CHANGELOG.md

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

3+
## 2.55.0
4+
5+
### New Features ✨
6+
7+
#### Anthropic
8+
9+
- Record finish reasons in AI monitoring spans by @ericapisani in [#5678](https://github.com/getsentry/sentry-python/pull/5678)
10+
- Emit `gen_ai.chat` spans for asynchronous `messages.stream()` by @alexander-alderman-webb in [#5572](https://github.com/getsentry/sentry-python/pull/5572)
11+
- Emit AI Client Spans for synchronous `messages.stream()` by @alexander-alderman-webb in [#5565](https://github.com/getsentry/sentry-python/pull/5565)
12+
- Set gen_ai.response.id span attribute by @ericapisani in [#5662](https://github.com/getsentry/sentry-python/pull/5662)
13+
- Add `gen_ai.system` attribute to spans by @ericapisani in [#5661](https://github.com/getsentry/sentry-python/pull/5661)
14+
15+
#### Pydantic Ai
16+
17+
- Support ImageUrl content type in span instrumentation by @ericapisani in [#5629](https://github.com/getsentry/sentry-python/pull/5629)
18+
- Add tool description to execute_tool spans by @ericapisani in [#5596](https://github.com/getsentry/sentry-python/pull/5596)
19+
20+
#### Other
21+
22+
- (crons) Add owner field to MonitorConfig by @julwhitney13 in [#5610](https://github.com/getsentry/sentry-python/pull/5610)
23+
- (otlp) Add collector_url option to OTLPIntegration by @sl0thentr0py in [#5603](https://github.com/getsentry/sentry-python/pull/5603)
24+
25+
### Bug Fixes 🐛
26+
27+
- (ai) Truncate list-based message content in AI monitoring by @ericapisani in [#5631](https://github.com/getsentry/sentry-python/pull/5631)
28+
- (anthropic) Close span on `GeneratorExit` by @alexander-alderman-webb in [#5643](https://github.com/getsentry/sentry-python/pull/5643)
29+
- (celery) Propagate user-set headers by @sentrivana in [#5581](https://github.com/getsentry/sentry-python/pull/5581)
30+
- (langchain) Wrap finish_reason in array for gen_ai span attribute by @ericapisani in [#5666](https://github.com/getsentry/sentry-python/pull/5666)
31+
- (logging) Fix deadlock in log batcher by @sentrivana in [#5684](https://github.com/getsentry/sentry-python/pull/5684)
32+
- (profiler) Prevent buffer race condition during rapid start/stop cycles by @ericapisani in [#5622](https://github.com/getsentry/sentry-python/pull/5622)
33+
- (utils) Avoid double serialization of strings in safe_serialize by @ericapisani in [#5587](https://github.com/getsentry/sentry-python/pull/5587)
34+
- Enable unused import ruff check and fix unused imports by @sentrivana in [#5652](https://github.com/getsentry/sentry-python/pull/5652)
35+
36+
### Documentation 📚
37+
38+
- (openai-agents) Remove inapplicable comment by @alexander-alderman-webb in [#5495](https://github.com/getsentry/sentry-python/pull/5495)
39+
- Add AGENTS.md by @sentrivana in [#5579](https://github.com/getsentry/sentry-python/pull/5579)
40+
- Add `set_attribute` example to changelog by @sentrivana in [#5578](https://github.com/getsentry/sentry-python/pull/5578)
41+
42+
### Internal Changes 🔧
43+
44+
#### Anthropic
45+
46+
- Check system and response ID attributes on spans created by `stream()` by @alexander-alderman-webb in [#5665](https://github.com/getsentry/sentry-python/pull/5665)
47+
- Skip accumulation logic for unexpected types in streamed response by @alexander-alderman-webb in [#5564](https://github.com/getsentry/sentry-python/pull/5564)
48+
- Factor out streamed result handling by @alexander-alderman-webb in [#5563](https://github.com/getsentry/sentry-python/pull/5563)
49+
- Stream valid JSON by @alexander-alderman-webb in [#5641](https://github.com/getsentry/sentry-python/pull/5641)
50+
- Stop mocking response iterator by @alexander-alderman-webb in [#5573](https://github.com/getsentry/sentry-python/pull/5573)
51+
52+
#### Openai Agents
53+
54+
- Do not fail on new tool fields by @alexander-alderman-webb in [#5625](https://github.com/getsentry/sentry-python/pull/5625)
55+
- Stop expecting a specific function name by @alexander-alderman-webb in [#5623](https://github.com/getsentry/sentry-python/pull/5623)
56+
- Set streaming header when library uses `with_streaming_response()` by @alexander-alderman-webb in [#5583](https://github.com/getsentry/sentry-python/pull/5583)
57+
- Replace mocks with `httpx` for streamed responses by @alexander-alderman-webb in [#5580](https://github.com/getsentry/sentry-python/pull/5580)
58+
- Replace mocks with `httpx` in non-MCP tool tests by @alexander-alderman-webb in [#5602](https://github.com/getsentry/sentry-python/pull/5602)
59+
- Replace mocks with `httpx` in MCP tool tests by @alexander-alderman-webb in [#5605](https://github.com/getsentry/sentry-python/pull/5605)
60+
- Replace mocks with `httpx` in handoff tests by @alexander-alderman-webb in [#5604](https://github.com/getsentry/sentry-python/pull/5604)
61+
- Replace mocks with `httpx` in API error test by @alexander-alderman-webb in [#5601](https://github.com/getsentry/sentry-python/pull/5601)
62+
- Replace mocks with `httpx` in non-error single-response tests by @alexander-alderman-webb in [#5600](https://github.com/getsentry/sentry-python/pull/5600)
63+
- Remove test for unreachable state by @alexander-alderman-webb in [#5584](https://github.com/getsentry/sentry-python/pull/5584)
64+
- Expect `namespace` tool field for new `openai` versions by @alexander-alderman-webb in [#5599](https://github.com/getsentry/sentry-python/pull/5599)
65+
66+
#### Other
67+
68+
- (graphene) Simplify span creation by @sentrivana in [#5648](https://github.com/getsentry/sentry-python/pull/5648)
69+
- (httpx) Resolve type checking failures by @alexander-alderman-webb in [#5626](https://github.com/getsentry/sentry-python/pull/5626)
70+
- (pyramid) Support alpha suffixes in version parsing by @alexander-alderman-webb in [#5618](https://github.com/getsentry/sentry-python/pull/5618)
71+
- (rust) Don't implement separate scope management by @sentrivana in [#5639](https://github.com/getsentry/sentry-python/pull/5639)
72+
- (strawberry) Simplify span creation by @sentrivana in [#5647](https://github.com/getsentry/sentry-python/pull/5647)
73+
- 🤖 Update test matrix with new releases (03/16) by @github-actions in [#5671](https://github.com/getsentry/sentry-python/pull/5671)
74+
- Remove custom warden action by @sentrivana in [#5653](https://github.com/getsentry/sentry-python/pull/5653)
75+
- Add `httpx` to linting requirements by @alexander-alderman-webb in [#5644](https://github.com/getsentry/sentry-python/pull/5644)
76+
- Remove CodeQL action by @sentrivana in [#5616](https://github.com/getsentry/sentry-python/pull/5616)
77+
- Normalize dots in package names in `populate_tox.py` by @alexander-alderman-webb in [#5574](https://github.com/getsentry/sentry-python/pull/5574)
78+
- Do not run actions on `potel-base` by @sentrivana in [#5614](https://github.com/getsentry/sentry-python/pull/5614)
79+
380
## 2.54.0
481

582
### New Features ✨

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ Please search the [issue tracker](https://github.com/getsentry/sentry-python/iss
1717

1818
We will review your pull request as soon as possible. Thank you for contributing!
1919

20+
### AI Use
21+
22+
You are welcome to use whatever tools you prefer for making a contribution. However, any changes you propose have to be reviewed and tested by you, a human, first, before you submit a pull request with them for the Sentry team to review. If we feel like that didn't happen, we will close the PR outright. For example, we won't review visibly AI-generated PRs from an agent instructed to look for and "fix" open issues in the repo.
23+
2024
## Development Environment
2125

2226
### Set up Python

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.54.0"
34+
release = "2.55.0"
3535
version = ".".join(release.split(".")[:2]) # The short X.Y version.
3636

3737

requirements-testing.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ tomli;python_version<"3.11" # Only needed for pytest on Python < 3.11
44
pytest-cov
55
pytest-forked
66
pytest-localserver
7+
pytest-timeout
78
pytest-watch
89
jsonschema
910
executing

scripts/populate_tox/package_dependencies.jsonl

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

scripts/populate_tox/tox.jinja

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -168,29 +168,30 @@ setenv =
168168
gevent: PYTEST_ADDOPTS="--ignore=tests/test_shadowed_module.py"
169169
170170
# TESTPATH definitions for test suites not managed by toxgen
171-
common: TESTPATH=tests
172-
gevent: TESTPATH=tests
173-
integration_deactivation: TESTPATH=tests/test_ai_integration_deactivation.py
174-
shadowed_module: TESTPATH=tests/test_shadowed_module.py
175-
asgi: TESTPATH=tests/integrations/asgi
176-
aws_lambda: TESTPATH=tests/integrations/aws_lambda
177-
cloud_resource_context: TESTPATH=tests/integrations/cloud_resource_context
178-
gcp: TESTPATH=tests/integrations/gcp
179-
opentelemetry: TESTPATH=tests/integrations/opentelemetry
180-
otlp: TESTPATH=tests/integrations/otlp
181-
potel: TESTPATH=tests/integrations/opentelemetry
182-
socket: TESTPATH=tests/integrations/socket
171+
common: _TESTPATH=tests
172+
gevent: _TESTPATH=tests
173+
integration_deactivation: _TESTPATH=tests/test_ai_integration_deactivation.py
174+
shadowed_module: _TESTPATH=tests/test_shadowed_module.py
175+
asgi: _TESTPATH=tests/integrations/asgi
176+
aws_lambda: _TESTPATH=tests/integrations/aws_lambda
177+
cloud_resource_context: _TESTPATH=tests/integrations/cloud_resource_context
178+
gcp: _TESTPATH=tests/integrations/gcp
179+
opentelemetry: _TESTPATH=tests/integrations/opentelemetry
180+
otlp: _TESTPATH=tests/integrations/otlp
181+
potel: _TESTPATH=tests/integrations/opentelemetry
182+
socket: _TESTPATH=tests/integrations/socket
183183
184184
# These TESTPATH definitions are auto-generated by toxgen
185185
{% for integration, testpath in testpaths %}
186-
{{ integration }}: TESTPATH={{ testpath }}
186+
{{ integration }}: _TESTPATH={{ testpath }}
187187
{% endfor %}
188188
189189
passenv =
190190
SENTRY_PYTHON_TEST_POSTGRES_HOST
191191
SENTRY_PYTHON_TEST_POSTGRES_USER
192192
SENTRY_PYTHON_TEST_POSTGRES_PASSWORD
193193
SENTRY_PYTHON_TEST_POSTGRES_NAME
194+
TESTPATH
194195
195196
usedevelop = True
196197
@@ -228,7 +229,7 @@ commands =
228229
; Running `pytest` as an executable suffers from an import error
229230
; when loading tests in scenarios. In particular, django fails to
230231
; load the settings from the test module.
231-
python -m pytest -W error::pytest.PytestUnraisableExceptionWarning {env:TESTPATH} -o junit_suite_name={envname} {posargs}
232+
python -m pytest -W error::pytest.PytestUnraisableExceptionWarning {env:TESTPATH:{env:_TESTPATH}} -o junit_suite_name={envname} {posargs}
232233
233234
[testenv:linters]
234235
commands =

sentry_sdk/_batcher.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def __init__(
3131
self._record_lost_func = record_lost_func
3232
self._running = True
3333
self._lock = threading.Lock()
34+
self._active: "threading.local" = threading.local()
3435

3536
self._flush_event: "threading.Event" = threading.Event()
3637

@@ -70,23 +71,40 @@ def _ensure_thread(self) -> bool:
7071
return True
7172

7273
def _flush_loop(self) -> None:
74+
# Mark the flush-loop thread as active for its entire lifetime so
75+
# that any re-entrant add() triggered by GC warnings during wait(),
76+
# flush(), or Event operations is silently dropped instead of
77+
# deadlocking on internal locks.
78+
self._active.flag = True
7379
while self._running:
7480
self._flush_event.wait(self.FLUSH_WAIT_TIME + random.random())
7581
self._flush_event.clear()
7682
self._flush()
7783

7884
def add(self, item: "T") -> None:
79-
if not self._ensure_thread() or self._flusher is None:
85+
# Bail out if the current thread is already executing batcher code.
86+
# This prevents deadlocks when code running inside the batcher (e.g.
87+
# _add_to_envelope during flush, or _flush_event.wait/set) triggers
88+
# a GC-emitted warning that routes back through the logging
89+
# integration into add().
90+
if getattr(self._active, "flag", False):
8091
return None
8192

82-
with self._lock:
83-
if len(self._buffer) >= self.MAX_BEFORE_DROP:
84-
self._record_lost(item)
93+
self._active.flag = True
94+
try:
95+
if not self._ensure_thread() or self._flusher is None:
8596
return None
8697

87-
self._buffer.append(item)
88-
if len(self._buffer) >= self.MAX_BEFORE_FLUSH:
89-
self._flush_event.set()
98+
with self._lock:
99+
if len(self._buffer) >= self.MAX_BEFORE_DROP:
100+
self._record_lost(item)
101+
return None
102+
103+
self._buffer.append(item)
104+
if len(self._buffer) >= self.MAX_BEFORE_FLUSH:
105+
self._flush_event.set()
106+
finally:
107+
self._active.flag = False
90108

91109
def kill(self) -> None:
92110
if self._flusher is None:
@@ -97,7 +115,12 @@ def kill(self) -> None:
97115
self._flusher = None
98116

99117
def flush(self) -> None:
100-
self._flush()
118+
was_active = getattr(self._active, "flag", False)
119+
self._active.flag = True
120+
try:
121+
self._flush()
122+
finally:
123+
self._active.flag = was_active
101124

102125
def _add_to_envelope(self, envelope: "Envelope") -> None:
103126
envelope.add_item(

0 commit comments

Comments
 (0)