From abf297638e106d060457956b98c071d68066ddf9 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 25 Mar 2025 10:55:15 +0100 Subject: [PATCH 1/4] chore: Drop even more deprecated stuff --- MIGRATION_GUIDE.md | 4 + sentry_sdk/integrations/_wsgi_common.py | 38 +--------- sentry_sdk/integrations/starlette.py | 27 +------ sentry_sdk/scope.py | 41 ---------- .../integrations/starlette/test_starlette.py | 76 ------------------- 5 files changed, 10 insertions(+), 176 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index d57696d910..9453445449 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -156,6 +156,10 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - `profiles_sample_rate` and `profiler_mode` were removed from options available via `_experiments`. Use the top-level `profiles_sample_rate` and `profiler_mode` options instead. - `Transport.capture_event` has been removed. Use `Transport.capture_envelope` instead. - Function transports are no longer supported. Subclass the `Transport` instead. +- Setting `Scope.transaction` directly is no longer supported. Use `Scope.set_transaction_name()` instead. +- Passing a list or `None` for `failed_request_status_codes` in the Starlette integration is no longer supported. Pass a set of integers instead. +- The `span` argument of `Scope.trace_propagation_meta` is no longer supported. +- Setting `Scope.user` directly is no longer supported. Use `Scope.set_user()` instead. ### Deprecated diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 65801476d5..2d4a5f7b73 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -3,7 +3,7 @@ import sentry_sdk from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.utils import AnnotatedValue, logger, SENSITIVE_DATA_SUBSTITUTE +from sentry_sdk.utils import AnnotatedValue, SENSITIVE_DATA_SUBSTITUTE try: from django.http.request import RawPostDataException @@ -19,7 +19,7 @@ from typing import MutableMapping from typing import Optional from typing import Union - from sentry_sdk._types import Event, HttpStatusCodeRange + from sentry_sdk._types import Event SENSITIVE_ENV_KEYS = ( @@ -240,37 +240,3 @@ def _request_headers_to_span_attributes(headers): attributes[f"http.request.header.{header.lower()}"] = value return attributes - - -def _in_http_status_code_range(code, code_ranges): - # type: (object, list[HttpStatusCodeRange]) -> bool - for target in code_ranges: - if isinstance(target, int): - if code == target: - return True - continue - - try: - if code in target: - return True - except TypeError: - logger.warning( - "failed_request_status_codes has to be a list of integers or containers" - ) - - return False - - -class HttpCodeRangeContainer: - """ - Wrapper to make it possible to use list[HttpStatusCodeRange] as a Container[int]. - Used for backwards compatibility with the old `failed_request_status_codes` option. - """ - - def __init__(self, code_ranges): - # type: (list[HttpStatusCodeRange]) -> None - self._code_ranges = code_ranges - - def __contains__(self, item): - # type: (object) -> bool - return _in_http_status_code_range(item, self._code_ranges) diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index c308441dc0..9bb902b2ca 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -1,6 +1,5 @@ import asyncio import functools -import warnings from collections.abc import Set from copy import deepcopy @@ -13,7 +12,6 @@ ) from sentry_sdk.integrations._wsgi_common import ( DEFAULT_HTTP_METHODS_TO_CAPTURE, - HttpCodeRangeContainer, _is_json_content_type, request_body_within_bounds, ) @@ -36,9 +34,9 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Awaitable, Callable, Container, Dict, Optional, Tuple, Union + from typing import Any, Awaitable, Callable, Dict, Optional, Tuple - from sentry_sdk._types import Event, HttpStatusCodeRange + from sentry_sdk._types import Event try: import starlette # type: ignore @@ -88,7 +86,7 @@ class StarletteIntegration(Integration): def __init__( self, transaction_style="url", # type: str - failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Union[Set[int], list[HttpStatusCodeRange], None] + failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int] middleware_spans=True, # type: bool http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: tuple[str, ...] ): @@ -102,24 +100,7 @@ def __init__( self.middleware_spans = middleware_spans self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture)) - if isinstance(failed_request_status_codes, Set): - self.failed_request_status_codes = ( - failed_request_status_codes - ) # type: Container[int] - else: - warnings.warn( - "Passing a list or None for failed_request_status_codes is deprecated. " - "Please pass a set of int instead.", - DeprecationWarning, - stacklevel=2, - ) - - if failed_request_status_codes is None: - self.failed_request_status_codes = _DEFAULT_FAILED_REQUEST_STATUS_CODES - else: - self.failed_request_status_codes = HttpCodeRangeContainer( - failed_request_status_codes - ) + self.failed_request_status_codes = failed_request_status_codes @staticmethod def setup_once(): diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 1784b6c5b3..5205ce5d15 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -561,14 +561,6 @@ def trace_propagation_meta(self, *args, **kwargs): Return meta tags which should be injected into HTML templates to allow propagation of trace information. """ - span = kwargs.pop("span", None) - if span is not None: - warnings.warn( - "The parameter `span` in trace_propagation_meta() is deprecated and will be removed in the future.", - DeprecationWarning, - stacklevel=2, - ) - meta = "" sentry_trace = self.get_traceparent() @@ -719,33 +711,6 @@ def transaction(self): # transaction) or a non-orphan span on the scope return self._span.containing_transaction - @transaction.setter - def transaction(self, value): - # type: (Any) -> None - # would be type: (Optional[str]) -> None, see https://github.com/python/mypy/issues/3004 - """When set this forces a specific transaction name to be set. - - Deprecated: use set_transaction_name instead.""" - - # XXX: the docstring above is misleading. The implementation of - # apply_to_event prefers an existing value of event.transaction over - # anything set in the scope. - # XXX: note that with the introduction of the Scope.transaction getter, - # there is a semantic and type mismatch between getter and setter. The - # getter returns a Span, the setter sets a transaction name. - # Without breaking version compatibility, we could make the setter set a - # transaction name or transaction (self._span) depending on the type of - # the value argument. - - warnings.warn( - "Assigning to scope.transaction directly is deprecated: use scope.set_transaction_name() instead.", - DeprecationWarning, - stacklevel=2, - ) - self._transaction = value - if self._span and self._span.containing_transaction: - self._span.containing_transaction.name = value - def set_transaction_name(self, name, source=None): # type: (str, Optional[str]) -> None """Set the transaction name and optionally the transaction source.""" @@ -769,12 +734,6 @@ def transaction_source(self): # type: () -> Optional[str] return self._transaction_info.get("source") - @_attr_setter - def user(self, value): - # type: (Optional[Dict[str, Any]]) -> None - """When set a specific user is bound to the scope. Deprecated in favor of set_user.""" - self.set_user(value) - def set_user(self, value): # type: (Optional[Dict[str, Any]]) -> None """Sets a user for the scope.""" diff --git a/tests/integrations/starlette/test_starlette.py b/tests/integrations/starlette/test_starlette.py index f3f9027264..29f94c4404 100644 --- a/tests/integrations/starlette/test_starlette.py +++ b/tests/integrations/starlette/test_starlette.py @@ -1182,82 +1182,6 @@ def test_span_origin(sentry_init, capture_events): assert span["origin"] == "auto.http.starlette" -class NonIterableContainer: - """Wraps any container and makes it non-iterable. - - Used to test backwards compatibility with our old way of defining failed_request_status_codes, which allowed - passing in a list of (possibly non-iterable) containers. The Python standard library does not provide any built-in - non-iterable containers, so we have to define our own. - """ - - def __init__(self, inner): - self.inner = inner - - def __contains__(self, item): - return item in self.inner - - -parametrize_test_configurable_status_codes_deprecated = pytest.mark.parametrize( - "failed_request_status_codes,status_code,expected_error", - [ - (None, 500, True), - (None, 400, False), - ([500, 501], 500, True), - ([500, 501], 401, False), - ([range(400, 499)], 401, True), - ([range(400, 499)], 500, False), - ([range(400, 499), range(500, 599)], 300, False), - ([range(400, 499), range(500, 599)], 403, True), - ([range(400, 499), range(500, 599)], 503, True), - ([range(400, 403), 500, 501], 401, True), - ([range(400, 403), 500, 501], 405, False), - ([range(400, 403), 500, 501], 501, True), - ([range(400, 403), 500, 501], 503, False), - ([], 500, False), - ([NonIterableContainer(range(500, 600))], 500, True), - ([NonIterableContainer(range(500, 600))], 404, False), - ], -) -"""Test cases for configurable status codes (deprecated API). -Also used by the FastAPI tests. -""" - - -@parametrize_test_configurable_status_codes_deprecated -def test_configurable_status_codes_deprecated( - sentry_init, - capture_events, - failed_request_status_codes, - status_code, - expected_error, -): - with pytest.warns(DeprecationWarning): - starlette_integration = StarletteIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - sentry_init(integrations=[starlette_integration]) - - events = capture_events() - - async def _error(request): - raise HTTPException(status_code) - - app = starlette.applications.Starlette( - routes=[ - starlette.routing.Route("/error", _error, methods=["GET"]), - ], - ) - - client = TestClient(app) - client.get("/error") - - if expected_error: - assert len(events) == 1 - else: - assert not events - - @pytest.mark.skipif( STARLETTE_VERSION < (0, 21), reason="Requires Starlette >= 0.21, because earlier versions do not support HTTP 'HEAD' requests", From fcf8a24112e1dd72b9d11e77da8ff5c64042b5e3 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 4 Apr 2025 13:23:50 +0200 Subject: [PATCH 2/4] fix --- sentry_sdk/integrations/django/__init__.py | 6 +++--- sentry_sdk/integrations/starlette.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index 99cb7704fa..e9a3786171 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -415,10 +415,10 @@ def _set_transaction_name_and_source(scope, transaction_style, request): if hasattr(urlconf, "handler404"): handler = urlconf.handler404 if isinstance(handler, str): - scope.transaction = handler + scope.set_transaction_name(handler) else: - scope.transaction = transaction_from_function( - getattr(handler, "view_class", handler) + scope.set_transaction_name( + transaction_from_function(getattr(handler, "view_class", handler)) ) except Exception: pass diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index 9bb902b2ca..fe9983812a 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -312,7 +312,7 @@ def _add_user_to_sentry_scope(scope): user_info.setdefault("email", starlette_user.email) sentry_scope = sentry_sdk.get_isolation_scope() - sentry_scope.user = user_info + sentry_scope.set_user(user_info) def patch_authentication_middleware(middleware_class): From f5a5900168a1951879d2cf7180d9cd638d7f0f2f Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 4 Apr 2025 13:26:28 +0200 Subject: [PATCH 3/4] . --- sentry_sdk/integrations/django/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index e9a3786171..5dd45e5b18 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -417,9 +417,11 @@ def _set_transaction_name_and_source(scope, transaction_style, request): if isinstance(handler, str): scope.set_transaction_name(handler) else: - scope.set_transaction_name( - transaction_from_function(getattr(handler, "view_class", handler)) + name = transaction_from_function( + getattr(handler, "view_class", handler) ) + if isinstance(name, str): + scope.set_transaction_name(name) except Exception: pass From e3da71f8bc62dee6391b0b0cf9c7b6ac63b40fa9 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 4 Apr 2025 13:27:15 +0200 Subject: [PATCH 4/4] . --- tests/integrations/fastapi/test_fastapi.py | 43 ---------------------- 1 file changed, 43 deletions(-) diff --git a/tests/integrations/fastapi/test_fastapi.py b/tests/integrations/fastapi/test_fastapi.py index 95838b1009..1c40abedcb 100644 --- a/tests/integrations/fastapi/test_fastapi.py +++ b/tests/integrations/fastapi/test_fastapi.py @@ -20,7 +20,6 @@ FASTAPI_VERSION = parse_version(fastapi.__version__) from tests.integrations.conftest import parametrize_test_configurable_status_codes -from tests.integrations.starlette import test_starlette def fastapi_app_factory(): @@ -528,48 +527,6 @@ def test_transaction_name_in_middleware( ) -@test_starlette.parametrize_test_configurable_status_codes_deprecated -def test_configurable_status_codes_deprecated( - sentry_init, - capture_events, - failed_request_status_codes, - status_code, - expected_error, -): - with pytest.warns(DeprecationWarning): - starlette_integration = StarletteIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - with pytest.warns(DeprecationWarning): - fast_api_integration = FastApiIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - sentry_init( - integrations=[ - starlette_integration, - fast_api_integration, - ] - ) - - events = capture_events() - - app = FastAPI() - - @app.get("/error") - async def _error(): - raise HTTPException(status_code) - - client = TestClient(app) - client.get("/error") - - if expected_error: - assert len(events) == 1 - else: - assert not events - - @pytest.mark.skipif( FASTAPI_VERSION < (0, 80), reason="Requires FastAPI >= 0.80, because earlier versions do not support HTTP 'HEAD' requests",