From b6ee7e332b9bb0233c09c80c58ee399aefea2d14 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 11 Sep 2024 12:56:18 +0200
Subject: [PATCH 01/24] feat(python): Start the 3.x migration guide

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 docs/platforms/python/migration/2.x-to-3.x.mdx

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
new file mode 100644
index 00000000000000..c00145ecacda35
--- /dev/null
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -0,0 +1,20 @@
+---
+title: Migrate from 2.x to 3.x
+sidebar_order: 8997
+description: "Learn about migrating from sentry-python 2.x to 3.x"
+---
+
+This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md).
+
+## Python Version Support
+
+Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an older Python version, you'll need to stay on an older version of the SDK:
+
+- Python 2.7-3.5: SDK `1.x`
+- Python 3.6: SDK `2.x`
+
+## API Changes
+
+### Metrics
+
+The `sentry_sdk.metrics` API doesn't exist anymore in SDK `3.x` as the [metrics beta has come to an end](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End). The associated experimental options `enable_metrics`, `before_emit_metric` and `metric_code_locations` have been removed as well.

From 9aa5b800fa541de4f40aac87e0075645c44611f7 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 23 Apr 2025 15:22:10 +0200
Subject: [PATCH 02/24] start with custom tracing

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 34 ++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index c00145ecacda35..c87e6b25a5e373 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -15,6 +15,38 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 ## API Changes
 
-### Metrics
+### Custom Tracing Instrumentation
+
+Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
+
+```python diff
+- with sentry_sdk.start_transaction():
++ with sentry_sdk.start_span():
+    ...
+```
+
+Any spans without a parent span will become transactions by default. If you want to avoid promoting a span without a parent to a transaction, you can pass the `only_if_parent=True` keyword argument to `sentry_sdk.start_span()`.
+
+`sentry_sdk.start_transaction()` and `sentry_sdk.start_span()` no longer take the following arguments: `trace_id`, `baggage`, `span_id`, `parent_span_id`. Use `sentry_sdk.continue_trace()` for propagating trace data.
+
+`sentry_sdk.continue_trace()` no longer returns a `Transaction` and is now a context manager. To continue a trace from headers or environment variables, start a new span inside `sentry_sdk.continue_trace()`:
+
+```python diff
+- transaction = sentry_sdk.continue_trace(...)
+- with sentry_sdk.start_transaction(transaction=transaction):
+-     ...
++ with sentry_sdk.continue_trace(...):
++     with sentry_sdk.start_span(...):
++         ...
+```
+
+## Integrations
+
+
+## Metrics
 
 The `sentry_sdk.metrics` API doesn't exist anymore in SDK `3.x` as the [metrics beta has come to an end](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End). The associated experimental options `enable_metrics`, `before_emit_metric` and `metric_code_locations` have been removed as well.
+
+## Internals
+
+There is no concept of a hub anymore and all APIs and attributes that were connected to hubs have been removed.

From b33676c2f075ec2b42002149c0a0258dac1afc36 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 23 Apr 2025 16:40:10 +0200
Subject: [PATCH 03/24] more stuff

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 66 +++++++++++++++++--
 1 file changed, 61 insertions(+), 5 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index c87e6b25a5e373..d2993c0d5e026c 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -13,9 +13,11 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 - Python 2.7-3.5: SDK `1.x`
 - Python 3.6: SDK `2.x`
 
-## API Changes
+## Configuration
 
-### Custom Tracing Instrumentation
+The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least propagate incoming tracing information, even though it will not sample any spans.
+
+## Tracing API
 
 Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
 
@@ -32,16 +34,70 @@ Any spans without a parent span will become transactions by default. If you want
 `sentry_sdk.continue_trace()` no longer returns a `Transaction` and is now a context manager. To continue a trace from headers or environment variables, start a new span inside `sentry_sdk.continue_trace()`:
 
 ```python diff
-- transaction = sentry_sdk.continue_trace(...)
+- transaction = sentry_sdk.continue_trace({...})
 - with sentry_sdk.start_transaction(transaction=transaction):
 -     ...
-+ with sentry_sdk.continue_trace(...):
-+     with sentry_sdk.start_span(...):
++ with sentry_sdk.continue_trace({...}):
++     with sentry_sdk.start_span():
 +         ...
 ```
 
+## Span Data
+
+In OpenTelemetry, there is no concept of separate categories of data on a span: everything is simply a span attribute. This is a world the Sentry SDK is moving towards as well. We deprecated `set_data()` and added a new span method called `set_attribute()`:
+
+```python diff
+with sentry_sdk.start_span(...) as span:
+-    span.set_data("my_attribute", "my_value")
++    span.set_attribute("my_attribute", "my_value")
+```
+
+You can also set attributes directly when creating the span. This has the advantage that these initial attributes will be accessible in the sampling context in your `traces_sampler`/`profiles_sampler` (see also the [Sampling section](#Sampling)).
+
+```python
+with sentry_sdk.start_span(attributes={"my_attribute": "my_value"}):
+    ...
+```
+
+<Alert title="Important" level="warning">
+
+There are important type restrictions to consider when setting attributes on a span via `span.set_attribute()` and `start_span(attributes={...})`. The keys must be non-empty strings and the values can only be several primitive types (excluding `None`) or a list of a single primitive type. See [the OpenTelemetry specification](https://opentelemetry.io/docs/specs/otel/common/#attribute) for the details.
+
+</Alert>
+
+## Sampling
+
+It is no longer possible to change the sampling decision of a span by setting `span.sampled` directly. Please use a custom `traces_sampler` for determining whether a root span should be sampled.
+
+The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data, preventing us from making custom objects, like for example the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md) for details on what data is available.
+
+The ability to set `custom_sampling_context` on `start_transaction` was removed. If there is custom data that you want to have accessible in the `sampling_context` of a `traces_sampler` or `profiles_sampler`, set it on the span via the `attributes` argument, as all span attributes are now included in the `sampling_context` by default:
+
+```python diff
+- with start_transaction(custom_sampling_context={"custom_attribute": "custom_value"}):
++ with start_span(attributes={"custom_attribute": "custom_value"}) as span:
+    # custom_attribute will now be accessible in the sampling context
+    # of your traces_sampler/profiles_sampler
+    ...
+```
+
+
 ## Integrations
 
+### Logging
+
+The logging integration which implements out-of-the-box support for the Python standard library `logging` framework doesn't capture error logs as events anymore by default. The original behavior can still be achieved by providing a custom `event_level` to the `LoggingIntegration`:
+
+```python
+sentry_sdk.init(
+    integrations=[
+        # capture error, critical, exception logs
+        # and send them to Sentry as errors
+        LoggingIntegration(event_level="ERROR"),
+    ]
+)
+```
+
 
 ## Metrics
 

From 4910c684d21337c31fae37730f219d0a0aaa8581 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 23 Apr 2025 16:49:19 +0200
Subject: [PATCH 04/24] more stuff

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index d2993c0d5e026c..b1b1df341e8125 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -4,6 +4,11 @@ sidebar_order: 8997
 description: "Learn about migrating from sentry-python 2.x to 3.x"
 ---
 
+TODOS:
+- exceptiongroups
+- ...?
+
+
 This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md).
 
 ## Python Version Support
@@ -84,6 +89,10 @@ The ability to set `custom_sampling_context` on `start_transaction` was removed.
 
 ## Integrations
 
+Additional integrations will now be activated automatically if the SDK detects the respective package is installed: Ariadne, ARQ, asyncpg, Chalice, clickhouse-driver, GQL, Graphene, huey, Loguru, PyMongo, Quart, Starlite, Strawberry. You can [opt-out of specific integrations with the `disabled_integrations` option](https://docs.sentry.io/platforms/python/integrations/#disabling-integrations).
+
+We no longer support Django older than 2.0, trytond older than 5.0, and Falcon older than 3.0.
+
 ### Logging
 
 The logging integration which implements out-of-the-box support for the Python standard library `logging` framework doesn't capture error logs as events anymore by default. The original behavior can still be achieved by providing a custom `event_level` to the `LoggingIntegration`:
@@ -98,6 +107,21 @@ sentry_sdk.init(
 )
 ```
 
+### clickhouse-driver
+
+The query is now available under the `db.query.text` span attribute (only if `send_default_pii` is `True`).
+
+### PyMongo
+
+The PyMongo integration no longer sets tags automatically. The data is still accessible via span attributes.
+
+The PyMongo integration doesn't set `operation_ids` anymore. The individual IDs (`operation_id`, `request_id`, `session_id`) are now accessible as separate span attributes.
+
+
+### Redis
+
+In Redis pipeline spans there is no `span["data"]["redis.commands"]` that contains a dict `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}` but instead `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
+
 
 ## Metrics
 

From 0ed2c28ca284df31b5f9db37b660a13dd52e57a9 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 10:37:58 +0200
Subject: [PATCH 05/24] more

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 21 +++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index b1b1df341e8125..6a7c1ca8d08908 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -20,7 +20,7 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 ## Configuration
 
-The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least propagate incoming tracing information, even though it will not sample any spans.
+The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least continue incoming traces.
 
 ## Tracing API
 
@@ -64,15 +64,28 @@ with sentry_sdk.start_span(attributes={"my_attribute": "my_value"}):
     ...
 ```
 
-<Alert title="Important" level="warning">
+<Alert title="Span attribute type restrictions" level="warning">
 
-There are important type restrictions to consider when setting attributes on a span via `span.set_attribute()` and `start_span(attributes={...})`. The keys must be non-empty strings and the values can only be several primitive types (excluding `None`) or a list of a single primitive type. See [the OpenTelemetry specification](https://opentelemetry.io/docs/specs/otel/common/#attribute) for the details.
+There are important type restrictions to consider when setting attributes on a span via `span.set_attribute()` and `start_span(attributes={...})`. The keys must be non-empty strings and the values can only be several primitive types (excluding `None`) or a list of a single primitive type. See [the OpenTelemetry specification](https://opentelemetry.io/docs/specs/otel/common/#attribute) for details.
+
+Note that since the SDK is now exclusively using span attributes, this restriction applies to other ways of setting data on a span as well like `span.set_data()`, `span.set_measurement()`, `span.set_context()`.
 
 </Alert>
 
 ## Sampling
 
-It is no longer possible to change the sampling decision of a span by setting `span.sampled` directly. Please use a custom `traces_sampler` for determining whether a root span should be sampled.
+It's no longer possible to change the sampling decision of a span by setting `span.sampled` directly after the span has been created. Please use either a custom `traces_sampler` (preferred) or the `sampled` argument to `start_span()` for determining whether a span should be sampled.
+
+```python
+with sentry_sdk.start_span(sampled=True) as span:
+    ...
+```
+
+<Alert title="Sampling non-root spans" level="warning">
+
+Both `traces_sampler` and the `sampled` argument will only influence whether root spans (transactions) are sampled. They can't be used for sampling child spans.
+
+</Alert>
 
 The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data, preventing us from making custom objects, like for example the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md) for details on what data is available.
 

From eea95f123fca8d4b78657d8134b8ba95d731d361 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 11:54:46 +0200
Subject: [PATCH 06/24] .

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 6a7c1ca8d08908..b7d9885600f590 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -11,6 +11,7 @@ TODOS:
 
 This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md).
 
+
 ## Python Version Support
 
 Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an older Python version, you'll need to stay on an older version of the SDK:
@@ -18,10 +19,45 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 - Python 2.7-3.5: SDK `1.x`
 - Python 3.6: SDK `2.x`
 
+
 ## Configuration
 
 The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least continue incoming traces.
 
+The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](https://docs.sentry.io/platforms/python/configuration/options/#traces_sampler) for more fine-grained tuning.
+
+```python diff
+sentry_sdk.init(
+-     enable_tracing=True,
++     traces_sample_rate=1.0,
+)
+```
+
+The deprecated `propagate_traces` option was removed. Use [`trace_propagation_targets`](/platforms/python/configuration/options/#trace_propagation_targets) instead.
+
+```python diff
+sentry_sdk.init(
+    # don't propagate trace info downstream
+-     propagate_traces=False,
++     trace_propagation_targets=[],
+)
+```
+
+Note that this only affects the global SDK option. The `propagate_traces` option of the Celery integration remains unchanged.
+
+The `profiles_sample_rate` and `profiler_more` options previously accessible via `_experiments` have been removed. They're superceded by top-level options of the same name:
+
+```python diff
+sentry_sdk.init(
+-     _experiments={
+-         "profiles_sample_rate": 1.0,
+-         "profiler_mode": "thread",
+-     },
++     profiles_sample_rate=1.0,
++     profiler_mode="thread",
+)
+```
+
 ## Tracing API
 
 Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
@@ -47,6 +83,9 @@ Any spans without a parent span will become transactions by default. If you want
 +         ...
 ```
 
+The functions `continue_from_headers`, `continue_from_environ` and `from_traceparent` have been removed. Use the `sentry_sdk.continue_trace()` context manager instead.
+
+
 ## Span Data
 
 In OpenTelemetry, there is no concept of separate categories of data on a span: everything is simply a span attribute. This is a world the Sentry SDK is moving towards as well. We deprecated `set_data()` and added a new span method called `set_attribute()`:
@@ -72,6 +111,7 @@ Note that since the SDK is now exclusively using span attributes, this restricti
 
 </Alert>
 
+
 ## Sampling
 
 It's no longer possible to change the sampling decision of a span by setting `span.sampled` directly after the span has been created. Please use either a custom `traces_sampler` (preferred) or the `sampled` argument to `start_span()` for determining whether a span should be sampled.
@@ -136,10 +176,15 @@ The PyMongo integration doesn't set `operation_ids` anymore. The individual IDs
 In Redis pipeline spans there is no `span["data"]["redis.commands"]` that contains a dict `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}` but instead `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
 
 
+## Sessions
+
+The `auto_session_tracing()` context manager was removed. Use `track_session()` instead.
+
 ## Metrics
 
 The `sentry_sdk.metrics` API doesn't exist anymore in SDK `3.x` as the [metrics beta has come to an end](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End). The associated experimental options `enable_metrics`, `before_emit_metric` and `metric_code_locations` have been removed as well.
 
+
 ## Internals
 
 There is no concept of a hub anymore and all APIs and attributes that were connected to hubs have been removed.

From fbde46eaab092c41827882fb7cc4bdb20b5521cd Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 12:50:36 +0200
Subject: [PATCH 07/24] .

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index b7d9885600f590..d8d61d38d50d0a 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -140,6 +140,11 @@ The ability to set `custom_sampling_context` on `start_transaction` was removed.
 ```
 
 
+## Errors
+
+We've updated how we handle `ExceptionGroup`s. You will now get more data if `ExceptionGroup`s appear in chained exceptions. As an indirect consequence, you might notice a change in how issues are grouped in Sentry.
+
+
 ## Integrations
 
 Additional integrations will now be activated automatically if the SDK detects the respective package is installed: Ariadne, ARQ, asyncpg, Chalice, clickhouse-driver, GQL, Graphene, huey, Loguru, PyMongo, Quart, Starlite, Strawberry. You can [opt-out of specific integrations with the `disabled_integrations` option](https://docs.sentry.io/platforms/python/integrations/#disabling-integrations).
@@ -184,7 +189,6 @@ The `auto_session_tracing()` context manager was removed. Use `track_session()`
 
 The `sentry_sdk.metrics` API doesn't exist anymore in SDK `3.x` as the [metrics beta has come to an end](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End). The associated experimental options `enable_metrics`, `before_emit_metric` and `metric_code_locations` have been removed as well.
 
-
 ## Internals
 
 There is no concept of a hub anymore and all APIs and attributes that were connected to hubs have been removed.

From 3414be057d594eb505ff979df3664610a740515c Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 12:55:03 +0200
Subject: [PATCH 08/24] remove todo

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index d8d61d38d50d0a..6b7689384fcaaf 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -4,11 +4,6 @@ sidebar_order: 8997
 description: "Learn about migrating from sentry-python 2.x to 3.x"
 ---
 
-TODOS:
-- exceptiongroups
-- ...?
-
-
 This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md).
 
 

From d724fb2ff244d5ef3fbedf2bf3a4600b94296f6e Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 13:36:00 +0200
Subject: [PATCH 09/24] improvements

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 49 +++++++++++--------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 6b7689384fcaaf..930a9333656ccd 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -4,7 +4,7 @@ sidebar_order: 8997
 description: "Learn about migrating from sentry-python 2.x to 3.x"
 ---
 
-This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md).
+This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md).
 
 
 ## Python Version Support
@@ -19,12 +19,12 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least continue incoming traces.
 
-The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](https://docs.sentry.io/platforms/python/configuration/options/#traces_sampler) for more fine-grained tuning.
+The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](/platforms/python/configuration/options/#traces_sampler) for more fine-grained control over which spans should be sampled.
 
 ```python diff
 sentry_sdk.init(
--     enable_tracing=True,
-+     traces_sample_rate=1.0,
+-   enable_tracing=True,
++   traces_sample_rate=1.0,
 )
 ```
 
@@ -33,23 +33,23 @@ The deprecated `propagate_traces` option was removed. Use [`trace_propagation_ta
 ```python diff
 sentry_sdk.init(
     # don't propagate trace info downstream
--     propagate_traces=False,
-+     trace_propagation_targets=[],
+-   propagate_traces=False,
++   trace_propagation_targets=[],
 )
 ```
 
 Note that this only affects the global SDK option. The `propagate_traces` option of the Celery integration remains unchanged.
 
-The `profiles_sample_rate` and `profiler_more` options previously accessible via `_experiments` have been removed. They're superceded by top-level options of the same name:
+The `profiles_sample_rate` and `profiler_mode` options previously accessible via `_experiments` have been removed. They're superceded by top-level options of the same name:
 
 ```python diff
 sentry_sdk.init(
--     _experiments={
--         "profiles_sample_rate": 1.0,
--         "profiler_mode": "thread",
--     },
-+     profiles_sample_rate=1.0,
-+     profiler_mode="thread",
+-   _experiments={
+-       "profiles_sample_rate": 1.0,
+-       "profiler_mode": "thread",
+-   },
++   profiles_sample_rate=1.0,
++   profiler_mode="thread",
 )
 ```
 
@@ -91,7 +91,7 @@ with sentry_sdk.start_span(...) as span:
 +    span.set_attribute("my_attribute", "my_value")
 ```
 
-You can also set attributes directly when creating the span. This has the advantage that these initial attributes will be accessible in the sampling context in your `traces_sampler`/`profiles_sampler` (see also the [Sampling section](#Sampling)).
+You can also set attributes directly when creating the span. This has the advantage that these initial attributes will be accessible in the sampling context in your `traces_sampler`/`profiles_sampler` (see also the [Sampling section](#sampling)).
 
 ```python
 with sentry_sdk.start_span(attributes={"my_attribute": "my_value"}):
@@ -109,7 +109,7 @@ Note that since the SDK is now exclusively using span attributes, this restricti
 
 ## Sampling
 
-It's no longer possible to change the sampling decision of a span by setting `span.sampled` directly after the span has been created. Please use either a custom `traces_sampler` (preferred) or the `sampled` argument to `start_span()` for determining whether a span should be sampled.
+It's no longer possible to change the sampling decision of a span by setting `span.sampled` directly after the span has been created. Use either a custom `traces_sampler` (preferred) or the `sampled` argument to `start_span()` for determining whether a span should be sampled.
 
 ```python
 with sentry_sdk.start_span(sampled=True) as span:
@@ -122,7 +122,7 @@ Both `traces_sampler` and the `sampled` argument will only influence whether roo
 
 </Alert>
 
-The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data, preventing us from making custom objects, like for example the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/master/MIGRATION_GUIDE.md) for details on what data is available.
+The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data, preventing us from making custom objects, like for example the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md) for details on what data is available.
 
 The ability to set `custom_sampling_context` on `start_transaction` was removed. If there is custom data that you want to have accessible in the `sampling_context` of a `traces_sampler` or `profiles_sampler`, set it on the span via the `attributes` argument, as all span attributes are now included in the `sampling_context` by default:
 
@@ -134,6 +134,12 @@ The ability to set `custom_sampling_context` on `start_transaction` was removed.
     ...
 ```
 
+<Alert title="Span attribute type restrictions" level="warning">
+
+As mentioned above, span attribute keys must be non-empty strings and values can only be several primitive types (excluding `None`) or a list of a single primitive type. See [the OpenTelemetry specification](https://opentelemetry.io/docs/specs/otel/common/#attribute) for details.
+
+</Alert>
+
 
 ## Errors
 
@@ -142,7 +148,7 @@ We've updated how we handle `ExceptionGroup`s. You will now get more data if `Ex
 
 ## Integrations
 
-Additional integrations will now be activated automatically if the SDK detects the respective package is installed: Ariadne, ARQ, asyncpg, Chalice, clickhouse-driver, GQL, Graphene, huey, Loguru, PyMongo, Quart, Starlite, Strawberry. You can [opt-out of specific integrations with the `disabled_integrations` option](https://docs.sentry.io/platforms/python/integrations/#disabling-integrations).
+Additional integrations will now be activated automatically if the SDK detects the respective package is installed: Ariadne, ARQ, asyncpg, Chalice, clickhouse-driver, GQL, Graphene, huey, Loguru, PyMongo, Quart, Starlite, Strawberry. You can [opt-out of specific integrations with the `disabled_integrations` option](/platforms/python/integrations/#disabling-integrations).
 
 We no longer support Django older than 2.0, trytond older than 5.0, and Falcon older than 3.0.
 
@@ -156,13 +162,13 @@ sentry_sdk.init(
         # capture error, critical, exception logs
         # and send them to Sentry as errors
         LoggingIntegration(event_level="ERROR"),
-    ]
+    ],
 )
 ```
 
 ### clickhouse-driver
 
-The query is now available under the `db.query.text` span attribute (only if `send_default_pii` is `True`).
+The query being executed is now available under the `db.query.text` span attribute (only if `send_default_pii` is `True`).
 
 ### PyMongo
 
@@ -170,20 +176,21 @@ The PyMongo integration no longer sets tags automatically. The data is still acc
 
 The PyMongo integration doesn't set `operation_ids` anymore. The individual IDs (`operation_id`, `request_id`, `session_id`) are now accessible as separate span attributes.
 
-
 ### Redis
 
-In Redis pipeline spans there is no `span["data"]["redis.commands"]` that contains a dict `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}` but instead `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
+In Redis pipeline spans, there is no `span["data"]["redis.commands"]` that contains a dictionary `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}`. Instead, there is `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
 
 
 ## Sessions
 
 The `auto_session_tracing()` context manager was removed. Use `track_session()` instead.
 
+
 ## Metrics
 
 The `sentry_sdk.metrics` API doesn't exist anymore in SDK `3.x` as the [metrics beta has come to an end](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End). The associated experimental options `enable_metrics`, `before_emit_metric` and `metric_code_locations` have been removed as well.
 
+
 ## Internals
 
 There is no concept of a hub anymore and all APIs and attributes that were connected to hubs have been removed.

From f4986b191adaef79b3687fcb213e57fe3b7bbe47 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 13:41:07 +0200
Subject: [PATCH 10/24] formatting

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 42 +++++++++----------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 930a9333656ccd..93fa9c575730a0 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -22,19 +22,19 @@ The default of the `traces_sample_rate` option was changed from `None` to `0`. T
 The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](/platforms/python/configuration/options/#traces_sampler) for more fine-grained control over which spans should be sampled.
 
 ```python diff
-sentry_sdk.init(
--   enable_tracing=True,
-+   traces_sample_rate=1.0,
+  sentry_sdk.init(
+-     enable_tracing=True,
++     traces_sample_rate=1.0,
 )
 ```
 
 The deprecated `propagate_traces` option was removed. Use [`trace_propagation_targets`](/platforms/python/configuration/options/#trace_propagation_targets) instead.
 
 ```python diff
-sentry_sdk.init(
-    # don't propagate trace info downstream
--   propagate_traces=False,
-+   trace_propagation_targets=[],
+  sentry_sdk.init(
+      # don't propagate trace info downstream
+-     propagate_traces=False,
++     trace_propagation_targets=[],
 )
 ```
 
@@ -43,13 +43,13 @@ Note that this only affects the global SDK option. The `propagate_traces` option
 The `profiles_sample_rate` and `profiler_mode` options previously accessible via `_experiments` have been removed. They're superceded by top-level options of the same name:
 
 ```python diff
-sentry_sdk.init(
--   _experiments={
--       "profiles_sample_rate": 1.0,
--       "profiler_mode": "thread",
--   },
-+   profiles_sample_rate=1.0,
-+   profiler_mode="thread",
+  sentry_sdk.init(
+-     _experiments={
+-         "profiles_sample_rate": 1.0,
+-         "profiler_mode": "thread",
+-     },
++     profiles_sample_rate=1.0,
++     profiler_mode="thread",
 )
 ```
 
@@ -60,7 +60,7 @@ Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the backgr
 ```python diff
 - with sentry_sdk.start_transaction():
 + with sentry_sdk.start_span():
-    ...
+      ...
 ```
 
 Any spans without a parent span will become transactions by default. If you want to avoid promoting a span without a parent to a transaction, you can pass the `only_if_parent=True` keyword argument to `sentry_sdk.start_span()`.
@@ -86,9 +86,9 @@ The functions `continue_from_headers`, `continue_from_environ` and `from_tracepa
 In OpenTelemetry, there is no concept of separate categories of data on a span: everything is simply a span attribute. This is a world the Sentry SDK is moving towards as well. We deprecated `set_data()` and added a new span method called `set_attribute()`:
 
 ```python diff
-with sentry_sdk.start_span(...) as span:
--    span.set_data("my_attribute", "my_value")
-+    span.set_attribute("my_attribute", "my_value")
+  with sentry_sdk.start_span(...) as span:
+-      span.set_data("my_attribute", "my_value")
++      span.set_attribute("my_attribute", "my_value")
 ```
 
 You can also set attributes directly when creating the span. This has the advantage that these initial attributes will be accessible in the sampling context in your `traces_sampler`/`profiles_sampler` (see also the [Sampling section](#sampling)).
@@ -129,9 +129,9 @@ The ability to set `custom_sampling_context` on `start_transaction` was removed.
 ```python diff
 - with start_transaction(custom_sampling_context={"custom_attribute": "custom_value"}):
 + with start_span(attributes={"custom_attribute": "custom_value"}) as span:
-    # custom_attribute will now be accessible in the sampling context
-    # of your traces_sampler/profiles_sampler
-    ...
+      # custom_attribute will now be accessible in the sampling context
+      # of your traces_sampler/profiles_sampler
+      ...
 ```
 
 <Alert title="Span attribute type restrictions" level="warning">

From 6ca947fbb1afaaebd55bb932422bf09c63b0ffe3 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Thu, 24 Apr 2025 13:43:31 +0200
Subject: [PATCH 11/24] .

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 93fa9c575730a0..2c41869dda322c 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -183,7 +183,12 @@ In Redis pipeline spans, there is no `span["data"]["redis.commands"]` that conta
 
 ## Sessions
 
-The `auto_session_tracing()` context manager was removed. Use `track_session()` instead.
+The `auto_session_tracking()` context manager was removed. Use `track_session()` instead.
+
+
+## Scope
+
+Setting `Scope.user` directly is no longer supported. Use `Scope.set_user()` instead.
 
 
 ## Metrics

From 10857a00062977570b2a0b2d51177fcc6c327546 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 10:04:47 +0200
Subject: [PATCH 12/24] Apply suggestions from code review

Co-authored-by: Shannon Anahata <shannon.anahata@gmail.com>
---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 2c41869dda322c..fd602a803e4da3 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -40,7 +40,7 @@ The deprecated `propagate_traces` option was removed. Use [`trace_propagation_ta
 
 Note that this only affects the global SDK option. The `propagate_traces` option of the Celery integration remains unchanged.
 
-The `profiles_sample_rate` and `profiler_mode` options previously accessible via `_experiments` have been removed. They're superceded by top-level options of the same name:
+The `profiles_sample_rate` and `profiler_mode` options previously nested under `_experiments` have been removed. They're replaced by top-level options of the same name:
 
 ```python diff
   sentry_sdk.init(
@@ -83,7 +83,7 @@ The functions `continue_from_headers`, `continue_from_environ` and `from_tracepa
 
 ## Span Data
 
-In OpenTelemetry, there is no concept of separate categories of data on a span: everything is simply a span attribute. This is a world the Sentry SDK is moving towards as well. We deprecated `set_data()` and added a new span method called `set_attribute()`:
+In OpenTelemetry, there is no concept of separate categories of data on a span: everything is simply a span attribute. This is a concept the Sentry SDK is also adopting. We deprecated `set_data()` and added a new span method called `set_attribute()`:
 
 ```python diff
   with sentry_sdk.start_span(...) as span:
@@ -122,7 +122,7 @@ Both `traces_sampler` and the `sampled` argument will only influence whether roo
 
 </Alert>
 
-The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data, preventing us from making custom objects, like for example the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md) for details on what data is available.
+The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md) for details on what data is available.
 
 The ability to set `custom_sampling_context` on `start_transaction` was removed. If there is custom data that you want to have accessible in the `sampling_context` of a `traces_sampler` or `profiles_sampler`, set it on the span via the `attributes` argument, as all span attributes are now included in the `sampling_context` by default:
 
@@ -154,7 +154,7 @@ We no longer support Django older than 2.0, trytond older than 5.0, and Falcon o
 
 ### Logging
 
-The logging integration which implements out-of-the-box support for the Python standard library `logging` framework doesn't capture error logs as events anymore by default. The original behavior can still be achieved by providing a custom `event_level` to the `LoggingIntegration`:
+The logging integration, which implements out-of-the-box support for the Python standard library `logging` framework, doesn't capture error logs as events anymore by default. The original behavior can still be achieved by providing a custom `event_level` to the `LoggingIntegration`:
 
 ```python
 sentry_sdk.init(

From 72c2daea17216f1f26fbde210e2dc3fadb6baae5 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 10:22:02 +0200
Subject: [PATCH 13/24] wording

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index fd602a803e4da3..82e109f51165b6 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -55,7 +55,7 @@ The `profiles_sample_rate` and `profiler_mode` options previously nested under `
 
 ## Tracing API
 
-Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
+Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions and towards a span-only future. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
 
 ```python diff
 - with sentry_sdk.start_transaction():

From 3ed11af4bd09d69843a04acf53f8eaeddbbca7f2 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 10:31:16 +0200
Subject: [PATCH 14/24] wording

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 82e109f51165b6..d7b6349e6f72ec 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -17,7 +17,7 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 ## Configuration
 
-The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate`, the SDK will, at minimum, at least continue incoming traces.
+The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate` or `traces_sampler`, if your app receives requests with tracing information incldued, those traces will be continued and the Python SDK will honor the incoming sampling decision. See also our documentation on [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate).
 
 The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](/platforms/python/configuration/options/#traces_sampler) for more fine-grained control over which spans should be sampled.
 

From 57f14b82265cacf12e3063899aaac5ab54331961 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 10:32:00 +0200
Subject: [PATCH 15/24] fix typo

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index d7b6349e6f72ec..07cca3e04d1946 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -17,7 +17,7 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 ## Configuration
 
-The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate` or `traces_sampler`, if your app receives requests with tracing information incldued, those traces will be continued and the Python SDK will honor the incoming sampling decision. See also our documentation on [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate).
+The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate` or `traces_sampler`, if your app receives requests with tracing information included, those traces will be continued and the Python SDK will honor the incoming sampling decision. See also our documentation on [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate).
 
 The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](/platforms/python/configuration/options/#traces_sampler) for more fine-grained control over which spans should be sampled.
 

From fb1f29e43909f27d988bedf815d369506c3f592a Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 14:46:10 +0200
Subject: [PATCH 16/24] code formatting

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 07cca3e04d1946..fd3b20ec3ae835 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -25,7 +25,7 @@ The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/p
   sentry_sdk.init(
 -     enable_tracing=True,
 +     traces_sample_rate=1.0,
-)
+  )
 ```
 
 The deprecated `propagate_traces` option was removed. Use [`trace_propagation_targets`](/platforms/python/configuration/options/#trace_propagation_targets) instead.
@@ -35,7 +35,7 @@ The deprecated `propagate_traces` option was removed. Use [`trace_propagation_ta
       # don't propagate trace info downstream
 -     propagate_traces=False,
 +     trace_propagation_targets=[],
-)
+  )
 ```
 
 Note that this only affects the global SDK option. The `propagate_traces` option of the Celery integration remains unchanged.
@@ -50,7 +50,7 @@ The `profiles_sample_rate` and `profiler_mode` options previously nested under `
 -     },
 +     profiles_sample_rate=1.0,
 +     profiler_mode="thread",
-)
+  )
 ```
 
 ## Tracing API

From 98af38ec1159e9a2201ea3cf9226c9b18b30c2c0 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 28 Apr 2025 14:49:17 +0200
Subject: [PATCH 17/24] add set_measurement

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index fd3b20ec3ae835..5712149f3f5462 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -181,6 +181,11 @@ The PyMongo integration doesn't set `operation_ids` anymore. The individual IDs
 In Redis pipeline spans, there is no `span["data"]["redis.commands"]` that contains a dictionary `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}`. Instead, there is `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
 
 
+## Measurements
+
+The `set_measurement()` API was removed. You can set custom attributes on the span instead with `set_attribute()`.
+
+
 ## Sessions
 
 The `auto_session_tracking()` context manager was removed. Use `track_session()` instead.

From ec37656bc73d1c05eac7509a66ce004f7cd31d92 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Tue, 29 Apr 2025 11:49:58 +0200
Subject: [PATCH 18/24] remove traces_sample_rate change

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 5712149f3f5462..d595fc6a970885 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -17,8 +17,6 @@ Sentry Python SDK `3.x` only supports Python 3.7 and higher. If you're on an old
 
 ## Configuration
 
-The default of the `traces_sample_rate` option was changed from `None` to `0`. This means that even if you don't provide a custom `traces_sample_rate` or `traces_sampler`, if your app receives requests with tracing information included, those traces will be continued and the Python SDK will honor the incoming sampling decision. See also our documentation on [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate).
-
 The `enable_tracing` option was removed. Use [`traces_sample_rate`](/platforms/python/configuration/options/#traces_sample_rate) directly, or configure a [`traces_sampler`](/platforms/python/configuration/options/#traces_sampler) for more fine-grained control over which spans should be sampled.
 
 ```python diff

From cb7d6cb7dc732c893ede326b36d9bd883e278f8d Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 30 Apr 2025 11:22:43 +0200
Subject: [PATCH 19/24] Add a note about sdk being pre-release

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index d595fc6a970885..c725bba3d43327 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -4,6 +4,12 @@ sidebar_order: 8997
 description: "Learn about migrating from sentry-python 2.x to 3.x"
 ---
 
+<Alert title="Python SDK 3.0 pre-release">
+
+Version 3.0 of the Sentry Python SDK is currently in pre-release. If you feel like giving the latest 3.0 pre-release a spin, check out [our most recent releases](https://pypi.org/project/sentry-sdk/#history). Your feedback at this stage is invaluable, so please let us know about your experience, whether positive or negative, [on GitHub](https://github.com/getsentry/sentry-python/discussions/3936) or [on Discord](https://discord.gg/wdNEHETs87): How did the migration go? Did you encounter any issues? Is everything as expected?
+
+</Alert>
+
 This guide describes the common patterns involved in migrating to version `3.x` of the `sentry-python` SDK. For the full list of changes, check out the [detailed migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md).
 
 

From a9f2d17753781be484106bee24bf0b2cb019429d Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Wed, 30 Apr 2025 11:26:25 +0200
Subject: [PATCH 20/24] wording

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index c725bba3d43327..fe339b30385559 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -6,7 +6,7 @@ description: "Learn about migrating from sentry-python 2.x to 3.x"
 
 <Alert title="Python SDK 3.0 pre-release">
 
-Version 3.0 of the Sentry Python SDK is currently in pre-release. If you feel like giving the latest 3.0 pre-release a spin, check out [our most recent releases](https://pypi.org/project/sentry-sdk/#history). Your feedback at this stage is invaluable, so please let us know about your experience, whether positive or negative, [on GitHub](https://github.com/getsentry/sentry-python/discussions/3936) or [on Discord](https://discord.gg/wdNEHETs87): How did the migration go? Did you encounter any issues? Is everything as expected?
+Version 3.0 of the Sentry Python SDK is currently in pre-release. If you feel like giving it a spin, check out [our most recent releases](https://pypi.org/project/sentry-sdk/#history). Your feedback at this stage is invaluable, so please let us know about your experience, whether positive or negative, [on GitHub](https://github.com/getsentry/sentry-python/discussions/3936) or [on Discord](https://discord.gg/wdNEHETs87): How did the migration go? Did you encounter any issues? Is everything working as expected?
 
 </Alert>
 

From 83665728f135dbbc90769026e1d0a54aa80749bf Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 5 May 2025 12:47:13 +0200
Subject: [PATCH 21/24] add expandable sampling context sections

---
 .../platforms/python/migration/2.x-to-3.x.mdx | 118 +++++++++++++++++-
 1 file changed, 117 insertions(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index fe339b30385559..a3b58955bf5641 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -126,7 +126,123 @@ Both `traces_sampler` and the `sampled` argument will only influence whether roo
 
 </Alert>
 
-The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span. See the [migration guide in the repository](https://github.com/getsentry/sentry-python/blob/potel-base/MIGRATION_GUIDE.md) for details on what data is available.
+The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span.
+
+<Expandable title='AIOHTTP `sampling_context` changes'>
+  The AIOHTTP integration doesn't add the `aiohttp_request` object anymore. Instead, some of the individual properties of the request are accessible, if available, as follows:
+
+    | Request property  | Sampling context key(s)         |
+    | ----------------- | ------------------------------- |
+    | `path`            | `url.path`                      |
+    | `query_string`    | `url.query`                     |
+    | `method`          | `http.request.method`           |
+    | `host`            | `server.address`, `server.port` |
+    | `scheme`          | `url.scheme`                    |
+    | full URL          | `url.full`                      |
+    | `request.headers` | `http.request.header.{header}`  |
+</Expandable>
+
+<Expandable title='Celery `sampling_context` changes'>
+  The Celery integration doesn't add the `celery_job` dictionary anymore. Instead, the individual keys are now available as:
+
+  | Dictionary keys        | Sampling context key        | Example                        |
+  | ---------------------- | --------------------------- | ------------------------------ |
+  | `celery_job["args"]`   | `celery.job.args.{index}`   | `celery.job.args.0`            |
+  | `celery_job["kwargs"]` | `celery.job.kwargs.{kwarg}` | `celery.job.kwargs.kwarg_name` |
+  | `celery_job["task"]`   | `celery.job.task`           |                                |
+</Expandable>
+
+<Expandable title='Tornado `sampling_context` changes'>
+  The Tornado integration doesn't add the `tornado_request` object anymore. Instead, some of the individual properties of the request are accessible, if available, as follows:
+
+    | Request property  | Sampling context key(s)                             |
+    | ----------------- | --------------------------------------------------- |
+    | `path`            | `url.path`                                          |
+    | `query`           | `url.query`                                         |
+    | `protocol`        | `url.scheme`                                        |
+    | `method`          | `http.request.method`                               |
+    | `host`            | `server.address`, `server.port`                     |
+    | `version`         | `network.protocol.name`, `network.protocol.version` |
+    | full URL          | `url.full`                                          |
+    | `request.headers` | `http.request.header.{header}`                      |
+</Expandable>
+
+<Expandable title='WSGI `sampling_context` changes'>
+  The WSGI integration doesn't add the `wsgi_environ` object anymore. Instead, the individual properties of the environment are accessible, if available, as follows:
+
+    | Env property      | Sampling context key(s)                           |
+    | ----------------- | ------------------------------------------------- |
+    | `PATH_INFO`       | `url.path`                                        |
+    | `QUERY_STRING`    | `url.query`                                       |
+    | `REQUEST_METHOD`  | `http.request.method`                             |
+    | `SERVER_NAME`     | `server.address`                                  |
+    | `SERVER_PORT`     | `server.port`                                     |
+    | `SERVER_PROTOCOL` | `server.protocol.name`, `server.protocol.version` |
+    | `wsgi.url_scheme` | `url.scheme`                                      |
+    | full URL          | `url.full`                                        |
+    | `HTTP_*`          | `http.request.header.{header}`                    |
+</Expandable>
+
+<Expandable title='ASGI `sampling_context` changes'>
+  The ASGI integration doesn't add the `asgi_scope` object anymore. Instead, the individual properties of the scope, if available, are accessible as follows:
+
+    | Scope property | Sampling context key(s)         |
+    | -------------- | ------------------------------- |
+    | `type`         | `network.protocol.name`         |
+    | `scheme`       | `url.scheme`                    |
+    | `path`         | `url.path`                      |
+    | `query`        | `url.query`                     |
+    | `http_version` | `network.protocol.version`      |
+    | `method`       | `http.request.method`           |
+    | `server`       | `server.address`, `server.port` |
+    | `client`       | `client.address`, `client.port` |
+    | full URL       | `url.full`                      |
+    | `headers`      | `http.request.header.{header}`  |
+</Expandable>
+
+<Expandable title='RQ `sampling_context` changes'>
+  The RQ integration doesn't add the `rq_job` object anymore. Instead, the individual properties of the job and the queue, if available, are accessible as follows:
+
+    | RQ property     | Sampling context key         | Example                |
+    | --------------- | ---------------------------- | ---------------------- |
+    | `rq_job.args`   | `rq.job.args.{index}`        | `rq.job.args.0`        |
+    | `rq_job.kwargs` | `rq.job.kwargs.{kwarg}`      | `rq.job.args.my_kwarg` |
+    | `rq_job.func`   | `rq.job.func`                |                        |
+    | `queue.name`    | `messaging.destination.name` |                        |
+    | `rq_job.id`     | `messaging.message.id`       |                        |
+
+    Note that `rq.job.args`, `rq.job.kwargs`, and `rq.job.func` are serialized and not the actual objects on the job.
+</Expandable>
+
+<Expandable title='AWS Lambda `sampling_context` changes'>
+  The AWS Lambda integration doesn't add the `aws_event` and `aws_context` objects anymore. Instead, the following, if available, is accessible:
+
+    | AWS property                                | Sampling context key(s)         |
+    | ------------------------------------------- | ------------------------------- |
+    | `aws_event["httpMethod"]`                   | `http.request.method`           |
+    | `aws_event["queryStringParameters"]`        | `url.query`                     |
+    | `aws_event["path"]`                         | `url.path`                      |
+    | full URL                                    | `url.full`                      |
+    | `aws_event["headers"]["X-Forwarded-Proto"]` | `network.protocol.name`         |
+    | `aws_event["headers"]["Host"]`              | `server.address`                |
+    | `aws_context["function_name"]`              | `faas.name`                     |
+    | `aws_event["headers"]`                      | `http.request.headers.{header}` |
+</Expandable>
+
+<Expandable title='GCP `sampling_context` changes'>
+  The GCP integration doesn't add the `gcp_env` and `gcp_event` keys anymore. Instead, the following, if available, is accessible:
+
+    | Old sampling context key          | New sampling context key       |
+    | --------------------------------- | ------------------------------ |
+    | `gcp_env["function_name"]`        | `faas.name`                    |
+    | `gcp_env["function_region"]`      | `faas.region`                  |
+    | `gcp_env["function_project"]`     | `gcp.function.project`         |
+    | `gcp_env["function_identity"]`    | `gcp.function.identity`        |
+    | `gcp_env["function_entry_point"]` | `gcp.function.entry_point`     |
+    | `gcp_event.method`                | `http.request.method`          |
+    | `gcp_event.query_string`          | `url.query`                    |
+    | `gcp_event.headers`               | `http.request.header.{header}` |
+</Expandable>
 
 The ability to set `custom_sampling_context` on `start_transaction` was removed. If there is custom data that you want to have accessible in the `sampling_context` of a `traces_sampler` or `profiles_sampler`, set it on the span via the `attributes` argument, as all span attributes are now included in the `sampling_context` by default:
 

From 34091c26ddc5e9dc3d6e956c7ce5cf10ce5ecf5e Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 5 May 2025 13:21:38 +0200
Subject: [PATCH 22/24] formatting

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index a3b58955bf5641..4a824c9c6fa979 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -128,7 +128,7 @@ Both `traces_sampler` and the `sampled` argument will only influence whether roo
 
 The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span.
 
-<Expandable title='AIOHTTP `sampling_context` changes'>
+<Expandable title='AIOHTTP sampling context changes'>
   The AIOHTTP integration doesn't add the `aiohttp_request` object anymore. Instead, some of the individual properties of the request are accessible, if available, as follows:
 
     | Request property  | Sampling context key(s)         |
@@ -142,7 +142,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     | `request.headers` | `http.request.header.{header}`  |
 </Expandable>
 
-<Expandable title='Celery `sampling_context` changes'>
+<Expandable title='Celery sampling context changes'>
   The Celery integration doesn't add the `celery_job` dictionary anymore. Instead, the individual keys are now available as:
 
   | Dictionary keys        | Sampling context key        | Example                        |
@@ -152,7 +152,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
   | `celery_job["task"]`   | `celery.job.task`           |                                |
 </Expandable>
 
-<Expandable title='Tornado `sampling_context` changes'>
+<Expandable title='Tornado sampling context changes'>
   The Tornado integration doesn't add the `tornado_request` object anymore. Instead, some of the individual properties of the request are accessible, if available, as follows:
 
     | Request property  | Sampling context key(s)                             |
@@ -167,7 +167,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     | `request.headers` | `http.request.header.{header}`                      |
 </Expandable>
 
-<Expandable title='WSGI `sampling_context` changes'>
+<Expandable title='WSGI sampling context changes'>
   The WSGI integration doesn't add the `wsgi_environ` object anymore. Instead, the individual properties of the environment are accessible, if available, as follows:
 
     | Env property      | Sampling context key(s)                           |
@@ -183,7 +183,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     | `HTTP_*`          | `http.request.header.{header}`                    |
 </Expandable>
 
-<Expandable title='ASGI `sampling_context` changes'>
+<Expandable title='ASGI sampling context changes'>
   The ASGI integration doesn't add the `asgi_scope` object anymore. Instead, the individual properties of the scope, if available, are accessible as follows:
 
     | Scope property | Sampling context key(s)         |
@@ -200,7 +200,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     | `headers`      | `http.request.header.{header}`  |
 </Expandable>
 
-<Expandable title='RQ `sampling_context` changes'>
+<Expandable title='RQ sampling context changes'>
   The RQ integration doesn't add the `rq_job` object anymore. Instead, the individual properties of the job and the queue, if available, are accessible as follows:
 
     | RQ property     | Sampling context key         | Example                |
@@ -214,7 +214,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     Note that `rq.job.args`, `rq.job.kwargs`, and `rq.job.func` are serialized and not the actual objects on the job.
 </Expandable>
 
-<Expandable title='AWS Lambda `sampling_context` changes'>
+<Expandable title='AWS Lambda sampling context changes'>
   The AWS Lambda integration doesn't add the `aws_event` and `aws_context` objects anymore. Instead, the following, if available, is accessible:
 
     | AWS property                                | Sampling context key(s)         |
@@ -229,7 +229,7 @@ The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has c
     | `aws_event["headers"]`                      | `http.request.headers.{header}` |
 </Expandable>
 
-<Expandable title='GCP `sampling_context` changes'>
+<Expandable title='GCP sampling context changes'>
   The GCP integration doesn't add the `gcp_env` and `gcp_event` keys anymore. Instead, the following, if available, is accessible:
 
     | Old sampling context key          | New sampling context key       |

From 1c6c2afb26668f7a1dff77cfa11fb61d77a46ae3 Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Mon, 5 May 2025 14:47:48 +0200
Subject: [PATCH 23/24] Add add_attachment

---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 4a824c9c6fa979..0852600b0e44ad 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -57,7 +57,21 @@ The `profiles_sample_rate` and `profiler_mode` options previously nested under `
   )
 ```
 
-## Tracing API
+## API Changes
+
+`add_attachment()` is now a part of the top-level level API and can be imported and used directly from `sentry_sdk`.
+
+```python diff
+  import sentry_sdk
+
+- scope = sentry_sdk.get_current_scope()
+- scope.add_attachment(bytes=b"Hello World!", filename="attachment.txt")
++ sentry_sdk.add_attachment(bytes=b"Hello World!", filename="attachment.txt")
+```
+
+Using `sentry_sdk.add_attachment()` directly also makes sure the attachment is added to the correct scope internally.
+
+### Custom Tracing API
 
 Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions and towards a span-only future. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
 

From bda77c92fe3383b5c09e46bc261cd4abe1b61b4f Mon Sep 17 00:00:00 2001
From: Ivana Kellyer <ivana.kellyer@sentry.io>
Date: Tue, 6 May 2025 09:48:00 +0200
Subject: [PATCH 24/24] Apply suggestions from code review

Co-authored-by: Anton Pirker <anton.pirker@sentry.io>
---
 docs/platforms/python/migration/2.x-to-3.x.mdx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/platforms/python/migration/2.x-to-3.x.mdx b/docs/platforms/python/migration/2.x-to-3.x.mdx
index 0852600b0e44ad..cd0ac66ae9b8eb 100644
--- a/docs/platforms/python/migration/2.x-to-3.x.mdx
+++ b/docs/platforms/python/migration/2.x-to-3.x.mdx
@@ -42,7 +42,7 @@ The deprecated `propagate_traces` option was removed. Use [`trace_propagation_ta
   )
 ```
 
-Note that this only affects the global SDK option. The `propagate_traces` option of the Celery integration remains unchanged.
+Note that this only affects the global SDK option. The [`propagate_traces`](/platforms/python/integrations/celery/#options) option of the Celery integration remains unchanged.
 
 The `profiles_sample_rate` and `profiler_mode` options previously nested under `_experiments` have been removed. They're replaced by top-level options of the same name:
 
@@ -59,7 +59,7 @@ The `profiles_sample_rate` and `profiler_mode` options previously nested under `
 
 ## API Changes
 
-`add_attachment()` is now a part of the top-level level API and can be imported and used directly from `sentry_sdk`.
+`add_attachment()` is now a part of the top-level level API and should be imported and used directly from `sentry_sdk`.
 
 ```python diff
   import sentry_sdk
@@ -73,7 +73,7 @@ Using `sentry_sdk.add_attachment()` directly also makes sure the attachment is a
 
 ### Custom Tracing API
 
-Tracing in the Sentry Python SDK `3.x` is powered by OpenTelemetry in the background, which also means we're moving away from the Sentry-specific concept of transactions and towards a span-only future. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
+Tracing in the Sentry Python SDK `3.x` is powered by [OpenTelemetry](https://opentelemetry.io/) in the background, which also means we're moving away from the Sentry-specific concept of transactions and towards a span-only future. `sentry_sdk.start_transaction()` is now deprecated in favor of `sentry_sdk.start_span()`.
 
 ```python diff
 - with sentry_sdk.start_transaction():
@@ -140,7 +140,7 @@ Both `traces_sampler` and the `sampled` argument will only influence whether roo
 
 </Alert>
 
-The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, simple types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span.
+The `sampling_context` argument of `traces_sampler` and `profiles_sampler` has changed considerably for spans coming from our auto-instrumented integrations. As a consequence of using OpenTelemetry under the hood, spans can only carry specific, primitive types of data. This prevents us from making custom objects, for example, the `Request` object for several web frameworks, accessible on the span.
 
 <Expandable title='AIOHTTP sampling context changes'>
   The AIOHTTP integration doesn't add the `aiohttp_request` object anymore. Instead, some of the individual properties of the request are accessible, if available, as follows:
