Skip to content

Next Python SDK major - #5005

Draft
sentrivana wants to merge 423 commits into
masterfrom
major/3.0
Draft

sentrivana wants to merge 423 commits into
masterfrom
major/3.0

Conversation

@sentrivana

@sentrivana sentrivana commented Oct 24, 2025 •

Copy link
Copy Markdown
Contributor

We're preparing our next major on this branch.

The project is tracked in Linear. If you don't have access, we'll try to tag issues belonging to the project with the SDK 3.0 label on GitHub so that you can follow along.

Notable changes

  • Transaction-based tracing will be removed. Span streaming will be the default tracing model.
  • Python 3.6 support will be removed.

Context

You might have read this announcement about us discontinuing work on a 3.0. This is referring to the work done on the potel-base branch, which included two types of changes: a huge refactor of our tracing code on the one hand, and various unrelated changes, improvements and fixes on the other. We're dropping the huge refactor part, and only porting the rest, to a new branch and eventually a new 3.0 release.

@codecov

codecov Bot commented Oct 24, 2025 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.76%. Comparing base (14aff96) to head (d864ba0).
⚠️ Report is 4 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #5005       +/-   ##
===========================================
+ Coverage   70.55%   83.76%   +13.21%     
===========================================
  Files         180      180               
  Lines       18077    18080        +3     
  Branches     3008     3009        +1     
===========================================
+ Hits        12754    15145     +2391     
+ Misses       4432     1943     -2489     
- Partials      891      992      +101     
Files with missing lines Coverage Δ
sentry_sdk/integrations/__init__.py 88.42% <100.00%> (+0.37%) ⬆️

... and 61 files with indirect coverage changes

@github-actions

github-actions Bot commented Mar 19, 2026 •

Copy link
Copy Markdown
Contributor

Codecov Results 📊

✅ 55725 passed | ⏭️ 2872 skipped | Total: 58597 | Pass Rate: 95.1% | Execution Time: 153m 13s

📊 Comparison with Base Branch

Metric Change
Total Tests 📉 -79240
Passed Tests 📉 -74835
Failed Tests 📉 -1
Skipped Tests 📉 -4404

➖ Removed Tests (1)

View removed tests
  • test_no_integration[False-False]
    • File: tests.integrations.litellm.test_litellm

All tests are passing successfully.

✅ Patch coverage is 90.10%. Project has 2070 uncovered lines.
❌ Project coverage is 90.1%. Comparing base (f1441bf) to head (7ed3e35).

Coverage diff
@@            Coverage Diff             @@
##        master       #PR       +/-##
==========================================
- Coverage    90.28%    90.10%    -0.18%
==========================================
  Files          202       193        -9
  Lines        26639     20902     -5737
  Branches      9926      7206     -2720
==========================================
+ Hits         24050     18832     -5218
- Misses        2589      2070      -519
- Partials      1509      1232      -277

Generated by Codecov Action

@github-actions

github-actions Bot commented Mar 19, 2026 •

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

⚪ None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (logging) Separate ignore lists for events/breadcrumbs and sentry logs by sl0thentr0py in #5698

Bug Fixes 🐛

Anthropic

  • Set exception info on streaming span when applicable by alexander-alderman-webb in #5683
  • Patch AsyncStream.close() and AsyncMessageStream.close() to finish spans by alexander-alderman-webb in #5675
  • Patch Stream.close() and MessageStream.close() to finish spans by alexander-alderman-webb in #5674

Documentation 📚

  • Add note on AI PRs to CONTRIBUTING.md by sentrivana in #5696

Internal Changes 🔧

  • Add -latest alias for each integration test suite by sentrivana in #5706
  • Use date-based branch names for toxgen PRs by sentrivana in #5704
  • 🤖 Update test matrix with new releases (03/19) by github-actions in #5703
  • Add client report tests for span streaming by sentrivana in #5677

Other

  • Next Python SDK major by sentrivana in #5005
  • Update CHANGELOG.md by sentrivana in #5685

🤖 This preview updates automatically when you update the PR.

Comment thread sentry_sdk/consts.py
Comment thread sentry_sdk/integrations/otlp.py
Comment thread tests/integrations/django/asgi/test_asgi.py
Comment thread sentry_sdk/integrations/otlp.py
Comment thread tests/integrations/threading/test_threading.py Outdated
Comment thread sentry_sdk/integrations/launchdarkly.py Outdated
Comment thread sentry_sdk/scope.py Outdated
Comment thread sentry_sdk/integrations/trytond.py
Comment thread sentry_sdk/integrations/chalice.py
Comment thread sentry_sdk/integrations/openai_agents/__init__.py
Comment thread sentry_sdk/integrations/pydantic_ai/__init__.py
Comment thread sentry_sdk/integrations/spark/spark_driver.py
Comment thread tests/integrations/launchdarkly/test_launchdarkly.py
Comment thread sentry_sdk/integrations/__init__.py Outdated
Comment thread sentry_sdk/integrations/openai_agents/__init__.py
Comment thread sentry_sdk/integrations/starlette.py
sentrivana added a commit that referenced this pull request Aug 6, 2026
Fixes for things that the bots
[surfaced](#5005) on the
major branch:
- some version checks were too late (after patching)
- fix TrytondWSGI integration name/`_MIN_VERSIONS` entry mismatch

Also, changed the warning of the `DidNotEnable` message from "X not
installed" to "X not installed or incompatible".
Comment thread sentry_sdk/integrations/redis/modules/queries.py
Comment thread sentry_sdk/integrations/langchain.py
Comment thread sentry_sdk/spotlight.py
Comment thread sentry_sdk/spotlight.py
Comment thread sentry_sdk/integrations/otlp.py
Comment thread sentry_sdk/integrations/aiomysql.py
Comment thread sentry_sdk/integrations/aiomysql.py Outdated
Comment thread MIGRATION_GUIDE.md Outdated
Comment thread sentry_sdk/integrations/otlp.py
Comment thread sentry_sdk/integrations/pyramid.py Outdated
Comment thread sentry_sdk/integrations/strawberry.py Outdated
Comment thread tests/integrations/aiomysql/test_aiomysql.py
Comment thread tests/integrations/aiomysql/test_aiomysql.py
Comment thread tests/integrations/aiomysql/test_aiomysql.py
Comment thread sentry_sdk/integrations/stdlib.py Outdated
Comment thread sentry_sdk/integrations/stdlib.py Outdated
Comment thread sentry_sdk/integrations/__init__.py
Comment thread sentry_sdk/integrations/threading.py
Comment thread tests/integrations/bottle/test_bottle.py
Comment thread tests/integrations/httpx/test_httpx.py Outdated
sentrivana added a commit that referenced this pull request Aug 26, 2026
Originally raised by a bot
[here](#5005 (comment)):
the `parse_version` function parses version strings as is (e.g. 3.1
becomes `(3, 1)`). We use these parsed version tuples in integrations to
compare the installed version against the minimum (defined in
`integrations/__init__.py`). The minimum versions are often three-part,
e.g. `(3, 1, 0)`.

This means that we can mistakenly consider a valid version to be below
the minimum, because in pure tuple terms, `(3, 1) < (3, 1, 0)` is true.

This can also happen in reverse (package version has three parts, while
our min version boundary has two).

In this PR, we make the internal version comparison work as expected
regardless of mismatches in the length of the version strings/tuples.
Comment thread sentry_sdk/integrations/typer.py
Comment thread sentry_sdk/_init_implementation.py
Comment thread sentry_sdk/integrations/arq.py Outdated
Comment thread sentry_sdk/integrations/asgi.py Outdated
Comment thread sentry_sdk/integrations/strawberry.py Outdated
Comment thread sentry_sdk/integrations/redis/redis.py
Comment thread sentry_sdk/integrations/stdlib.py Outdated
Comment thread MIGRATION_GUIDE.md Outdated
Comment thread MIGRATION_GUIDE.md Outdated
Comment thread sentry_sdk/consts.py
ericapisani and others added 16 commits October 7, 2026 07:14
…undant empty `data_collection` from sentry_init (#7907)

Refs PY-2936
…d, requests, rq, starlette, starlite, stdlib, strawberry, wsgi): Remove redundant empty `data_collection` from sentry_init (#7908)

Refs PY-2936

---------

Co-authored-by: Pablo Deputter <71842639+pabloDeputter@users.noreply.github.com>
…n section (#7893)

Fixes PY-2800
Fixes #7568

---------

Co-authored-by: Ivana Kellyer <ivana.kellyer@sentry.io>
### Description
Adds the following request/response attributes: `aws.s3.bucket`,
`aws.s3.key`, `aws.s3.upload_id`, `aws.s3.copy_source`, `aws.s3.delete`,
`aws.s3.part_number`, `http.response.body.size` (number of bytes in
payload), `file.size` (represents the total file/object size)

Following tests were removed/moved from old `test_s3.py` (old boto3
integration only added s3 streaming responses support):
- `test_basic()` removed - basically only tests botocore xml parsing
behavior; generic span behavior is already tested in `test_client.py`.
- `test_streaming()` / `test_streaming_close()` removed - behavior is
already tested in `test_client.py` with mock HTTP server.
- `test_span_origin()` removed - overlaps with existing tests.
- `test_omit_url_data_if_parsing_fails()` moved to `test_client.py` and
simplified since it's generic instrumentation.
- `test_breadcrumb()` and `test_url_query_data_collection_breadcrumb()`
moved and combined to `test_client.py`, once again since it's generic
instrumentation.

#### Issues
Resolves #7576
)

Group the TracingTestClass tracing tests into a class whose
setup/teardown restores the `static` and `class_` attributes that
`functions_to_trace` patches.

Resolves warnings like these
https://github.com/getsentry/sentry-python/actions/runs/37602693189/job/112730646420#step:6:3739

Refs PY-2637
Refs #6949
The task factory tests build the Sentry wrapper coroutine but never run
it, so it is garbage-collected unawaited. This surfaces as a "coroutine
was never awaited" RuntimeWarning attributed to an unrelated later test
(e.g. test_span_origin). Close the coroutine once the assertions are
done.

Fixes PY-2943
Fixes #7923
Comment thread MIGRATION_GUIDE.md
Comment thread sentry_sdk/_compat.py
Comment on lines +34 to +40
if getattr(exc, "_handled_by_sentry", False):
logger.info("DedupeIntegration dropped duplicated error event %s", exc)
return None

# we can only weakref non builtin types
try:
integration._last_seen.set(weakref.ref(exc))
except TypeError:
integration._last_seen.set(exc)

return event

@staticmethod
def reset_last_seen() -> None:
integration = sentry_sdk.get_client().get_integration(DedupeIntegration)
if integration is None:
return

integration._last_seen.set(None)
else:
with capture_internal_exceptions():
exc._handled_by_sentry = True
return event

@sentry-warden sentry-warden Bot Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dedupe suppresses a repeated exception after before_send drops it

The dedupe processor marks an exception as handled before before_send runs. If before_send drops the event, the marker remains; capturing that same exception instance again causes the processor to drop it as a duplicate. Reset the marker when the event is dropped, or mark the exception only after the event is accepted.

Evidence
  • DedupeIntegration.processor() sets exc._handled_by_sentry = True for an exception hint before returning the event.
  • Client._prepare_event() runs scope event processors before calling before_send; when that callback returns None, it records the loss but does not clear the exception marker.
  • A later capture_exception() of the same instance passes it in hint["exc_info"], so the dedupe processor sees the marker and returns None.
  • The existing dropped-exception test creates a new ValueError on each iteration, so it does not cover recapturing the same instance.
Also found at 1 additional location
  • sentry_sdk/client.py:558-566

Identified by Warden · find-bugs, code-review · FQ4-JUB

Comment thread sentry_sdk/integrations/gcp.py
Comment thread sentry_sdk/integrations/litellm.py
#7930)

### Description
Expand boto3 instrumentation with resource identity attributes; new
service-extensions (and tests) are added as well (mostly boilerplate,
but will be filled in the future).

- add `cloud.account.id` and `cloud.resource_id`
(https://opentelemetry.io/docs/specs/semconv/resource/cloud/) attributes
whenever a request contains a valid AWS ARN; these are extracted using
the common helper `_get_aws_arn_attributes()` in `boto3/_utils.py`; the
resource's AWS account is used here, not the caller's. It accepts
multiple request params. since operations may expose the same resource
under different names (the first matching ARN is used).
- additionally, following service extensions are registered: DynamoDB,
Kinesis, Lambda (file is called `lambda_.py` since it clashes with
`lambda` keyword, open for suggestions on renaming it), Secrets Manager,
SNS, SQS, and Step Functions.
- for SQS, `cloud.account.id` is extracted from `QueueURL` when no ARN
is available, e.g.
`https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue`
(https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-queue-message-identifiers.html)

#### Issues
Resolves #7929
Comment thread MIGRATION_GUIDE.md
Comment on lines +232 to +234
"cookies": { "mode": "denylist", "terms": ["forwarded", "-ip", "remote-", "via", "-user"] },
"url_query_params": {
"mode": "denylist", "terms": ["forwarded", "-ip", "remote-", "via", "-user"],

@sentry-warden sentry-warden Bot Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cookie denylist in migration sample still sends ordinary cookie values

The example is presented as roughly matching send_default_pii=False, but its cookie denylist only redacts keys matching the listed terms or the built-in sensitive-key list. Ordinary cookie values such as theme and lang are still attached to events. Use "cookies": {"mode": "off"} (or an appropriate allowlist) if the goal is not to collect those cookies.

Evidence
  • MIGRATION_GUIDE.md presents the configuration as roughly matching send_default_pii=False, but configures cookies with a denylist of header-oriented terms.
  • data_collection._apply_key_value_collection_filtering() preserves unmatched key/value pairs in denylist mode; mode off returns an empty mapping.
  • Request extractors attach nonempty filtered cookies, and test_cookie_data_collection confirms theme and lang survive denylist mode while mode: off omits cookies.

Identified by Warden · find-bugs, code-review · JSW-CZZ

Comment thread sentry_sdk/integrations/django/caching.py
pabloDeputter and others added 2 commits October 12, 2026 13:32
### Description
Remove whitespace from services whose `service_id` contain spaces; since
span names are formed using `str(service_id)` they are incorrect:
* `service_id = "API Gateway"` => `service_id= "API Gateway"`
* `span_name = "API Gateway.GetRestApis"` => `span_name =
"APIGateway.GetRestApis"`

#### Issues
Resolves #7954
Comment on lines +117 to 122
name = _get_transaction_name(bottle_request)
if name:
sentry_sdk.get_current_scope().set_transaction_name(
name,
source=SegmentNameSource.ROUTE,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Post-handler set_transaction_name always overwrites user custom names

Only set the route transaction name when the segment still has the default name/source; otherwise a handler call to set_transaction_name(..., CUSTOM) is clobbered after return.

Evidence
  • Name is applied unconditionally after the handler returns via set_transaction_name(name, source=SegmentNameSource.ROUTE).
  • Flask/Pyramid/Falcon set the route name before the handler, so user overrides stick; Bottle sets it after and always wins.
  • ASGI explicitly skips overwrite when source is already COMPONENT/ROUTE/CUSTOM (see already_set in asgi.py).
  • No Bottle test covers preserving a custom transaction name set inside the route handler.

Identified by Warden · find-bugs · H4U-BL9

Comment thread sentry_sdk/integrations/gcp.py

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants