From 40afba721ed285c01f47053c36569cb5dcac1d72 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Aug 2026 11:22:37 +0200 Subject: [PATCH 1/3] ref: Change warnings --- sentry_sdk/_compat.py | 34 ++++++++++++--------------- sentry_sdk/_init_implementation.py | 11 +++------ sentry_sdk/client.py | 19 +++++---------- sentry_sdk/data_collection.py | 6 ++--- sentry_sdk/debug.py | 7 ++---- sentry_sdk/integrations/langchain.py | 6 ++--- sentry_sdk/integrations/sanic.py | 5 ++-- sentry_sdk/integrations/strawberry.py | 5 ++-- sentry_sdk/integrations/threading.py | 5 ++-- sentry_sdk/scope.py | 26 ++++++-------------- sentry_sdk/traces.py | 13 ++++------ sentry_sdk/tracing.py | 6 ++--- sentry_sdk/tracing_utils.py | 16 ++++--------- sentry_sdk/transport.py | 10 +++----- sentry_sdk/utils.py | 10 ++++++++ 15 files changed, 67 insertions(+), 112 deletions(-) diff --git a/sentry_sdk/_compat.py b/sentry_sdk/_compat.py index f62175c09f..6a016c22d5 100644 --- a/sentry_sdk/_compat.py +++ b/sentry_sdk/_compat.py @@ -61,30 +61,26 @@ def enabled(option: str) -> bool: lazy_mode = enabled("lazy-apps") or enabled("lazy") if lazy_mode and not threads_enabled: - from warnings import warn - - warn( - Warning( - "IMPORTANT: " - "We detected the use of uWSGI without thread support. " - "This might lead to unexpected issues. " - 'Please run uWSGI with "--enable-threads" for full support.' - ) + from sentry_sdk.utils import logger + + logger.warning( + "IMPORTANT: " + "We detected the use of uWSGI without thread support. " + "This might lead to unexpected issues. " + 'Please run uWSGI with "--enable-threads" for full support.' ) return False elif not lazy_mode and (not threads_enabled or not fork_hooks_on): - from warnings import warn - - warn( - Warning( - "IMPORTANT: " - "We detected the use of uWSGI in preforking mode without " - "thread support. This might lead to crashing workers. " - 'Please run uWSGI with both "--enable-threads" and ' - '"--py-call-uwsgi-fork-hooks" for full support.' - ) + from sentry_sdk.utils import logger + + logger.warning( + "IMPORTANT: " + "We detected the use of uWSGI in preforking mode without " + "thread support. This might lead to crashing workers. " + 'Please run uWSGI with both "--enable-threads" and ' + '"--py-call-uwsgi-fork-hooks" for full support.' ) return False diff --git a/sentry_sdk/_init_implementation.py b/sentry_sdk/_init_implementation.py index 3051ae010b..aa4f224a36 100644 --- a/sentry_sdk/_init_implementation.py +++ b/sentry_sdk/_init_implementation.py @@ -1,9 +1,8 @@ import re -import warnings from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.utils import logger, parse_version +from sentry_sdk.utils import deprecation_warning, logger, parse_version if TYPE_CHECKING: from typing import Any, ContextManager, Optional @@ -23,19 +22,15 @@ def __init__(self, client: "sentry_sdk.Client") -> None: self._client = client def __enter__(self) -> "_InitGuard": - warnings.warn( + deprecation_warning( self._CONTEXT_MANAGER_DEPRECATION_WARNING_MESSAGE, - stacklevel=2, - category=DeprecationWarning, ) return self def __exit__(self, exc_type: "Any", exc_value: "Any", tb: "Any") -> None: - warnings.warn( + deprecation_warning( self._CONTEXT_MANAGER_DEPRECATION_WARNING_MESSAGE, - stacklevel=2, - category=DeprecationWarning, ) c = self._client diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index ec29ee895b..8c18d53831 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -5,7 +5,6 @@ import socket import sys import uuid -import warnings from collections.abc import Iterable, Mapping from contextvars import ContextVar from datetime import datetime, timezone @@ -348,9 +347,8 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": else rv["send_default_pii"] ) elif has_data_collection_enabled(rv) and rv["event_scrubber"]: - warnings.warn( + logger.warning( "Event scrubbers are not enabled when data collection configuration is provided. Ignoring event_scrubber...", - stacklevel=2, ) rv["event_scrubber"] = None @@ -366,21 +364,18 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": ) if rv["trace_ignore_status_codes"] and has_span_streaming_enabled(rv): - warnings.warn( + logger.warning( "The `trace_ignore_status_codes` parameter is ignored in span streaming mode.", - stacklevel=2, ) if rv["ignore_spans"] and not has_span_streaming_enabled(rv): - warnings.warn( + logger.warning( "The `ignore_spans` parameter only works when `trace_lifecycle` is set to `stream`.", - stacklevel=2, ) if rv["before_send_span"] and not has_span_streaming_enabled(rv): - warnings.warn( + logger.warning( "The `before_send_span` parameter only works when `trace_lifecycle` is set to `stream`.", - stacklevel=2, ) return rv @@ -1334,9 +1329,8 @@ def close( """ if self.transport is not None: if self._has_async_transport(): - warnings.warn( + logger.warning( "close() used with AsyncHttpTransport. Use close_async() instead.", - stacklevel=2, ) self._flush_components() else: @@ -1381,9 +1375,8 @@ def flush( """ if self.transport is not None: if self._has_async_transport(): - warnings.warn( + logger.warning( "flush() used with AsyncHttpTransport. Use flush_async() instead.", - stacklevel=2, ) return if timeout is None: diff --git a/sentry_sdk/data_collection.py b/sentry_sdk/data_collection.py index 4b130da1fb..4a6889ef7d 100644 --- a/sentry_sdk/data_collection.py +++ b/sentry_sdk/data_collection.py @@ -22,11 +22,11 @@ ``DeprecationWarning`` is emitted for ``send_default_pii``. """ -import warnings from typing import TYPE_CHECKING, List, Mapping, Optional, Union, cast from urllib.parse import parse_qs, urlencode from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE +from sentry_sdk.utils import deprecation_warning if TYPE_CHECKING: from typing import Any, Dict @@ -315,11 +315,9 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": ) ) if send_default_pii is not None: - warnings.warn( + deprecation_warning( "`send_default_pii` is deprecated and ignored when " "`data_collection` is set.", - DeprecationWarning, - stacklevel=2, ) return _resolve_explicit( user_dc, diff --git a/sentry_sdk/debug.py b/sentry_sdk/debug.py index 795882e9ef..1b10cd68cc 100644 --- a/sentry_sdk/debug.py +++ b/sentry_sdk/debug.py @@ -1,11 +1,10 @@ import logging import sys -import warnings from logging import LogRecord from sentry_sdk import get_client from sentry_sdk.client import _client_init_debug -from sentry_sdk.utils import logger +from sentry_sdk.utils import deprecation_warning, logger class _DebugFilter(logging.Filter): @@ -30,8 +29,6 @@ def configure_logger() -> None: def configure_debug_hub() -> None: - warnings.warn( + deprecation_warning( "configure_debug_hub is deprecated. Please remove calls to it, as it is a no-op.", - DeprecationWarning, - stacklevel=2, ) diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index 25a6ae2467..95e9f07789 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -1,7 +1,6 @@ import itertools import json import sys -import warnings from collections import OrderedDict from functools import wraps from typing import TYPE_CHECKING, NamedTuple @@ -26,6 +25,7 @@ ) from sentry_sdk.utils import ( capture_internal_exceptions, + deprecation_warning, has_data_collection_enabled, logger, parse_version, @@ -242,11 +242,9 @@ def __init__( self.max_spans = max_spans if max_spans is not None: - warnings.warn( + deprecation_warning( "The `max_spans` parameter of `LangchainIntegration` is " "deprecated and will be removed in version 3.0 of sentry-sdk.", - DeprecationWarning, - stacklevel=2, ) @staticmethod diff --git a/sentry_sdk/integrations/sanic.py b/sentry_sdk/integrations/sanic.py index ff7eda64c0..4caf3988cf 100644 --- a/sentry_sdk/integrations/sanic.py +++ b/sentry_sdk/integrations/sanic.py @@ -1,5 +1,4 @@ import sys -import warnings import weakref from inspect import isawaitable from typing import TYPE_CHECKING @@ -22,6 +21,7 @@ ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + logger, parse_version, reraise, ) @@ -155,9 +155,8 @@ async def _context_enter(request: "Request") -> None: isinstance(integration, SanicIntegration) and integration._unsampled_statuses ): - warnings.warn( + logger.warning( "The `unsampled_statuses` option of SanicIntegration has no effect when span streaming is enabled.", - stacklevel=2, ) sentry_sdk.traces.continue_trace(dict(request.headers)) diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index d1b4e613a5..4e298f3b95 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -1,5 +1,4 @@ import functools -import warnings from inspect import isawaitable import sentry_sdk @@ -13,6 +12,7 @@ ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + logger, package_version, ) @@ -95,9 +95,8 @@ def _sentry_patched_schema_init( should_use_async_extension = _guess_if_using_async(extensions) if should_use_async_extension is None: - warnings.warn( + logger.warning( "Assuming strawberry is running sync. If not, initialize the integration as StrawberryIntegration(async_execution=True).", - stacklevel=2, ) should_use_async_extension = False diff --git a/sentry_sdk/integrations/threading.py b/sentry_sdk/integrations/threading.py index 606caa852e..3c299deef0 100644 --- a/sentry_sdk/integrations/threading.py +++ b/sentry_sdk/integrations/threading.py @@ -1,5 +1,4 @@ import sys -import warnings from concurrent.futures import Future, ThreadPoolExecutor from functools import wraps from threading import Thread, current_thread @@ -11,6 +10,7 @@ from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, + logger, reraise, ) @@ -62,12 +62,11 @@ def sentry_start(self: "Thread", *a: "Any", **kw: "Any") -> "Any": if integration.propagate_scope: if is_async_emulated_with_threads: - warnings.warn( + logger.warning( "There is a known issue with Django channels 2.x and 3.x when using Python 3.8 or older. " "(Async support is emulated using threads and some Sentry data may be leaked between those threads.) " "Please either upgrade to Django channels 4.0+, use Django's async features " "available in Django 3.1+ instead of Django channels, or upgrade to Python 3.9+.", - stacklevel=2, ) isolation_scope = sentry_sdk.get_isolation_scope() current_scope = sentry_sdk.get_current_scope() diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 5ad644b2d8..f245b953c2 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1,7 +1,6 @@ import os import platform import sys -import warnings from collections import deque from contextlib import contextmanager from contextvars import ContextVar @@ -51,6 +50,7 @@ capture_internal_exception, capture_internal_exceptions, datetime_from_isoformat, + deprecation_warning, disable_capture_event, event_from_exception, exc_info_from_error, @@ -798,10 +798,8 @@ def transaction(self) -> "Any": return None if isinstance(self._span, StreamedSpan): - warnings.warn( + deprecation_warning( "Scope.transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, ) return None @@ -836,10 +834,8 @@ def transaction(self, value: "Any") -> None: self._transaction = value if self._span: if isinstance(self._span, StreamedSpan): - warnings.warn( + deprecation_warning( "Scope.transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, ) return None @@ -868,10 +864,8 @@ def set_transaction_name(self, name: str, source: "Optional[str]" = None) -> Non @_attr_setter def user(self, value: "Optional[Dict[str, Any]]") -> None: """When set a specific user is bound to the scope. Deprecated in favor of set_user.""" - warnings.warn( + deprecation_warning( "The `Scope.user` setter is deprecated in favor of `Scope.set_user()`.", - DeprecationWarning, - stacklevel=2, ) self.set_user(value) @@ -1131,10 +1125,8 @@ def start_transaction( """ client = self.get_client() if has_span_streaming_enabled(client.options): - warnings.warn( + deprecation_warning( "Scope.start_transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, ) return NoOpSpan() @@ -1208,18 +1200,14 @@ def start_span(self, **kwargs: "Any") -> "Span": """ client = sentry_sdk.get_client() if has_span_streaming_enabled(client.options): - warnings.warn( + deprecation_warning( "Scope.start_span is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, ) return NoOpSpan() if kwargs.get("description") is not None: - warnings.warn( + deprecation_warning( "The `description` parameter is deprecated. Please use `name` instead.", - DeprecationWarning, - stacklevel=2, ) with new_scope(): diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index b02167672d..0799f7cba0 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -9,7 +9,6 @@ import sys import uuid -import warnings from datetime import datetime, timedelta, timezone from enum import Enum from typing import TYPE_CHECKING @@ -24,6 +23,7 @@ from sentry_sdk.tracing_utils import Baggage from sentry_sdk.utils import ( capture_internal_exceptions, + deprecation_warning, format_attribute, get_current_thread_meta, logger, @@ -170,11 +170,10 @@ def start_span( client = sentry_sdk.get_client() if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( + logger.warning( "Using span streaming API in non-span-streaming mode. Use " "sentry_sdk.start_transaction() and sentry_sdk.start_span() " "instead.", - stacklevel=2, ) return NoOpStreamedSpan() @@ -349,10 +348,8 @@ def end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: self._end(end_timestamp) def finish(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: - warnings.warn( + deprecation_warning( "span.finish() is deprecated. Use span.end() instead.", - stacklevel=2, - category=DeprecationWarning, ) self.end(end_timestamp) @@ -718,10 +715,8 @@ def end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: self._end() def finish(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: - warnings.warn( + deprecation_warning( "span.finish() is deprecated. Use span.end() instead.", - stacklevel=2, - category=DeprecationWarning, ) self._end() diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index f8b46829fa..895b2a0671 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -1,5 +1,4 @@ import uuid -import warnings from datetime import datetime, timedelta, timezone from enum import Enum from typing import TYPE_CHECKING, cast @@ -9,6 +8,7 @@ from sentry_sdk.profiler.continuous_profiler import get_profiler_id from sentry_sdk.utils import ( capture_internal_exceptions, + deprecation_warning, get_current_thread_meta, is_valid_sample_rate, logger, @@ -417,10 +417,8 @@ def start_child(self, **kwargs: "Any") -> "Span": inherited from the current span/transaction. """ if kwargs.get("description") is not None: - warnings.warn( + deprecation_warning( "The `description` parameter is deprecated. Please use `name` instead.", - DeprecationWarning, - stacklevel=2, ) kwargs.setdefault("sampled", self.sampled) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index c7ed24ba56..3e189579e4 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -5,7 +5,6 @@ import re import sys import uuid -import warnings from collections.abc import Mapping, MutableMapping from datetime import datetime, timedelta, timezone from random import Random @@ -20,6 +19,7 @@ _is_in_project_root, _module_in_list, capture_internal_exceptions, + deprecation_warning, filename_for_module, has_data_collection_enabled, is_sentry_url, @@ -1047,10 +1047,8 @@ async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": return await f(*args, **kwargs) if isinstance(current_span, StreamedSpan): - warnings.warn( + deprecation_warning( "Use the @sentry_sdk.traces.trace decorator in span streaming mode.", - DeprecationWarning, - stacklevel=2, ) return await f(*args, **kwargs) @@ -1092,10 +1090,8 @@ def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any": return f(*args, **kwargs) if isinstance(current_span, StreamedSpan): - warnings.warn( + deprecation_warning( "Use the @sentry_sdk.traces.trace decorator in span streaming mode.", - DeprecationWarning, - stacklevel=2, ) return f(*args, **kwargs) @@ -1153,10 +1149,9 @@ def span_decorator(f: "Any") -> "Any": async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": client = sentry_sdk.get_client() if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( + logger.warning( "Using span streaming API in non-span-streaming mode. Use " "@sentry_sdk.trace instead.", - stacklevel=2, ) span_name = name or qualname_from_function(f) or "" @@ -1176,10 +1171,9 @@ async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any": client = sentry_sdk.get_client() if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( + logger.warning( "Using span streaming API in non-span-streaming mode. Use " "@sentry_sdk.trace instead.", - stacklevel=2, ) span_name = name or qualname_from_function(f) or "" diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py index d98b8597fa..de6b54693c 100644 --- a/sentry_sdk/transport.py +++ b/sentry_sdk/transport.py @@ -7,7 +7,6 @@ import socket import ssl import time -import warnings from abc import ABC, abstractmethod from collections import defaultdict from datetime import datetime, timedelta, timezone @@ -47,6 +46,7 @@ from sentry_sdk.utils import ( Dsn, capture_internal_exceptions, + deprecation_warning, logger, mark_sentry_task_internal, ) @@ -121,10 +121,8 @@ def capture_event(self: "Self", event: "Event") -> None: be sent to sentry. """ - warnings.warn( + deprecation_warning( "capture_event is deprecated, please use capture_envelope instead!", - DeprecationWarning, - stacklevel=2, ) envelope = Envelope() @@ -1209,11 +1207,9 @@ def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": elif isinstance(ref_transport, type) and issubclass(ref_transport, Transport): transport_cls = ref_transport elif callable(ref_transport): - warnings.warn( + deprecation_warning( "Function transports are deprecated and will be removed in a future release." "Please provide a Transport instance or subclass, instead.", - DeprecationWarning, - stacklevel=2, ) transport = _FunctionTransport(ref_transport) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 5974266826..1da9a4e3f6 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -10,6 +10,7 @@ import sys import threading import time +import warnings from collections import namedtuple from contextlib import contextmanager from contextvars import ContextVar @@ -2023,3 +2024,12 @@ def serialize_attribute(val: "AttributeValue") -> "SerializedAttributeValue": # Coerce to string if we don't know what to do with the value. This should # never happen as we pre-format early in format_attribute, but let's be safe. return {"value": safe_repr(val), "type": "string"} + + +def deprecation_warning(msg: str) -> None: + """ + Emit a warnings.warn about a deprecation. + + For other types of warnings, use logger.warning(). + """ + warnings.warn(msg, stacklevel=2, category=DeprecationWarning) From f52c667ae71fe87eb6ec118a73bad0c200f69280 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Aug 2026 11:56:48 +0200 Subject: [PATCH 2/3] . --- MIGRATION_GUIDE.md | 1 + tests/integrations/django/asgi/test_asgi.py | 16 ++++--- tests/test_client.py | 52 +++++++++++---------- tests/tracing/test_span_streaming.py | 25 +++++----- 4 files changed, 50 insertions(+), 44 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 8aceffb8e8..87b788a35a 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -24,6 +24,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - The UnraisableHookIntegration is now enabled by default. - We now don't suppress chained exceptions in the ASGI and asyncio integrations by default. The related `suppress_asgi_chained_exceptions` experimental option was removed. - In the AWS Lambda and GCP integrations, the message of the warning the SDK optionally emits if a function is about to time out has changed. +- We changed the way we emit warnings. Deprecations will from now on be always emitted using `warnings.warn()`, while all other warnings will be emitted using `logger.warning()`. ### Logging diff --git a/tests/integrations/django/asgi/test_asgi.py b/tests/integrations/django/asgi/test_asgi.py index 0424c965ec..bbdf693ddb 100644 --- a/tests/integrations/django/asgi/test_asgi.py +++ b/tests/integrations/django/asgi/test_asgi.py @@ -59,6 +59,8 @@ async def test_basic( trace_lifecycle="stream" if span_streaming else "static", ) + from unittest import mock + import channels # type: ignore[import-not-found] if span_streaming: @@ -70,13 +72,14 @@ async def test_basic( and django.VERSION >= (3, 0) and django.VERSION < (4, 0) ): - # We emit a UserWarning for channels 2.x and 3.x on Python 3.8 and older + # We log a warning for channels 2.x and 3.x on Python 3.8 and older # because the async support was not really good back then and there is a known issue. - # See the TreadingIntegration for details. - with pytest.warns(UserWarning): + # See the ThreadingIntegration for details. + with mock.patch("sentry_sdk.integrations.threading.logger") as mock_logger: comm = HttpCommunicator(application, "GET", "/view-exc?test=query") response = await comm.get_response() await comm.wait() + mock_logger.warning.assert_called() else: comm = HttpCommunicator(application, "GET", "/view-exc?test=query") response = await comm.get_response() @@ -111,13 +114,14 @@ async def test_basic( and django.VERSION >= (3, 0) and django.VERSION < (4, 0) ): - # We emit a UserWarning for channels 2.x and 3.x on Python 3.8 and older + # We log a warning for channels 2.x and 3.x on Python 3.8 and older # because the async support was not really good back then and there is a known issue. - # See the TreadingIntegration for details. - with pytest.warns(UserWarning): + # See the ThreadingIntegration for details. + with mock.patch("sentry_sdk.integrations.threading.logger") as mock_logger: comm = HttpCommunicator(application, "GET", "/view-exc?test=query") response = await comm.get_response() await comm.wait() + mock_logger.warning.assert_called() else: comm = HttpCommunicator(application, "GET", "/view-exc?test=query") response = await comm.get_response() diff --git a/tests/test_client.py b/tests/test_client.py index 47a76764cb..e4f453b1d8 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,7 +4,6 @@ import subprocess import sys import time -import warnings from collections import Counter, defaultdict from collections.abc import Mapping from textwrap import dedent @@ -1280,18 +1279,19 @@ def test_error_sampler(_, sentry_init, capture_events, test_config): [{"py-call-uwsgi-fork-hooks": True}, ["--enable-threads"]], ], ) -def test_uwsgi_warnings(sentry_init, recwarn, opt, missing_flags): +def test_uwsgi_warnings(sentry_init, opt, missing_flags): uwsgi = mock.MagicMock() uwsgi.opt = opt - with mock.patch.dict("sys.modules", uwsgi=uwsgi): - sentry_init() - if missing_flags: - assert len(recwarn) == 1 - record = recwarn.pop() - for flag in missing_flags: - assert flag in str(record.message) - else: - assert not recwarn + with mock.patch("sentry_sdk.utils.logger") as mock_logger: + with mock.patch.dict("sys.modules", uwsgi=uwsgi): + sentry_init() + if missing_flags: + assert mock_logger.warning.call_count == 1 + message = mock_logger.warning.call_args[0][0] + for flag in missing_flags: + assert flag in message + else: + mock_logger.warning.assert_not_called() class TestSpanClientReports: @@ -1453,8 +1453,11 @@ def test_dropped_transaction(sentry_init, capture_record_lost_event_calls, test_ def test_ignore_spans_warns_without_streaming(sentry_init): - with pytest.warns(UserWarning, match=r"`ignore_spans` parameter only works"): + with mock.patch("sentry_sdk.client.logger") as mock_logger: sentry_init(ignore_spans=["/health"], trace_lifecycle="static") + mock_logger.warning.assert_any_call( + "The `ignore_spans` parameter only works when `trace_lifecycle` is set to `stream`.", + ) @pytest.mark.parametrize( @@ -1466,11 +1469,12 @@ def test_ignore_spans_warns_without_streaming(sentry_init): ], ) def test_ignore_spans_does_not_warn(sentry_init, options): - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: sentry_init(**options) - ignore_spans_warnings = [w for w in caught if "ignore_spans" in str(w.message)] + ignore_spans_warnings = [ + c for c in mock_logger.warning.call_args_list if "ignore_spans" in str(c) + ] assert ignore_spans_warnings == [] @@ -1596,8 +1600,6 @@ async def test_async_proxy(monkeypatch, testcase): @pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") async def test_close_with_async_transport_warns(): """Test close() with AsyncHttpTransport emits a warning.""" - import warnings as _warnings - client = Client( "https://foo@sentry.io/123", _experiments={"transport_async": True}, @@ -1605,10 +1607,11 @@ async def test_close_with_async_transport_warns(): ) assert isinstance(client.transport, AsyncHttpTransport) - with _warnings.catch_warnings(record=True) as w: - _warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: client.close() - assert any("close_async()" in str(warning.message) for warning in w) + assert any( + "close_async()" in str(c) for c in mock_logger.warning.call_args_list + ) @skip_under_gevent @@ -1661,8 +1664,6 @@ async def test_close_async_no_transport(): @pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") async def test_flush_with_async_transport_warns(): """Test flush() with AsyncHttpTransport emits a warning and returns.""" - import warnings as _warnings - client = Client( "https://foo@sentry.io/123", _experiments={"transport_async": True}, @@ -1670,10 +1671,11 @@ async def test_flush_with_async_transport_warns(): ) assert isinstance(client.transport, AsyncHttpTransport) - with _warnings.catch_warnings(record=True) as w: - _warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: client.flush(timeout=1.0) - assert any("flush_async()" in str(warning.message) for warning in w) + assert any( + "flush_async()" in str(c) for c in mock_logger.warning.call_args_list + ) await client.close_async() diff --git a/tests/tracing/test_span_streaming.py b/tests/tracing/test_span_streaming.py index 8aef2f7d17..9c45ece905 100644 --- a/tests/tracing/test_span_streaming.py +++ b/tests/tracing/test_span_streaming.py @@ -1,7 +1,6 @@ import re import sys import time -import warnings from unittest import mock import pytest @@ -446,20 +445,22 @@ def experimental(span, hint): def test_before_send_span_warns_without_span_streaming(sentry_init): - import warnings + from unittest import mock def before_send_span(span, hint): return span - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: sentry_init( traces_sample_rate=1.0, before_send_span=before_send_span, ) - (warning,) = [x for x in w if "before_send_span" in str(x.message)] - assert "trace_lifecycle" in str(warning.message) + warnings = [ + c for c in mock_logger.warning.call_args_list if "before_send_span" in str(c) + ] + assert len(warnings) == 1 + assert "trace_lifecycle" in str(warnings[0]) def test_span_attributes(sentry_init, capture_items): @@ -2023,13 +2024,11 @@ def test_top_level_trace_lifecycle_takes_precedence_over_experiments( items = capture_items("span") - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - with sentry_sdk.traces.start_span(name="segment") as segment: - if streaming_enabled: - assert isinstance(segment, StreamedSpan) - else: - assert isinstance(segment, NoOpStreamedSpan) + with sentry_sdk.traces.start_span(name="segment") as segment: + if streaming_enabled: + assert isinstance(segment, StreamedSpan) + else: + assert isinstance(segment, NoOpStreamedSpan) sentry_sdk.get_client().flush() spans = [item.payload for item in items] From bff3b82a6c5267bedf0f5e0c252082c770bb1c84 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Aug 2026 12:42:34 +0200 Subject: [PATCH 3/3] .. --- sentry_sdk/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 1da9a4e3f6..bc839d763b 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -2032,4 +2032,4 @@ def deprecation_warning(msg: str) -> None: For other types of warnings, use logger.warning(). """ - warnings.warn(msg, stacklevel=2, category=DeprecationWarning) + warnings.warn(msg, stacklevel=3, category=DeprecationWarning)