From 73a66abb2ee29cb68a9cea35812e5d540757e033 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 7 Aug 2024 13:24:17 +0200 Subject: [PATCH] feat(api): Remove `sentry_sdk.configure_scope` Also, remove any tests for `sentry_sdk.configure_scope`. Since Strawberry's deprecated [Sentry tracing extensions](https://strawberry.rocks/docs/extensions/sentry-tracing) import `sentry_sdk.configure_scope`, importing `strawberry.extensions.tracing.SentryTracingExtension` (or `SentryTracingExtensionSync`) will result in an unhandled exception. Therefore, these imports, and any functionality associated with them, have also been removed. This itself is not a breaking change, as it is necessitated by the removal of `sentry_sdk.configure_scope`. BREAKING CHANGE: Remove `sentry_sdk.configure_scope`. Closes: #3402 --- docs/api.rst | 2 - sentry_sdk/__init__.py | 1 - sentry_sdk/api.py | 53 --------- sentry_sdk/integrations/strawberry.py | 17 --- .../strawberry/test_strawberry.py | 22 ---- .../test_new_scopes_compat.py | 29 ----- .../test_new_scopes_compat_event.py | 103 +----------------- tests/test_api.py | 7 -- tests/test_client.py | 52 +-------- 9 files changed, 2 insertions(+), 284 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 034652e05c..fe069c22d6 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -51,8 +51,6 @@ Client Management Managing Scope (advanced) ========================= -.. autofunction:: sentry_sdk.api.configure_scope .. autofunction:: sentry_sdk.api.push_scope .. autofunction:: sentry_sdk.api.new_scope - diff --git a/sentry_sdk/__init__.py b/sentry_sdk/__init__.py index 1c9cedec5f..4332c706c4 100644 --- a/sentry_sdk/__init__.py +++ b/sentry_sdk/__init__.py @@ -19,7 +19,6 @@ "capture_event", "capture_exception", "capture_message", - "configure_scope", "continue_trace", "flush", "get_baggage", diff --git a/sentry_sdk/api.py b/sentry_sdk/api.py index 9c11031fbb..98899feb22 100644 --- a/sentry_sdk/api.py +++ b/sentry_sdk/api.py @@ -1,6 +1,5 @@ import inspect import warnings -from contextlib import contextmanager from sentry_sdk import tracing_utils, Client from sentry_sdk._init_implementation import init @@ -16,7 +15,6 @@ from typing import Any from typing import Dict - from typing import Generator from typing import Optional from typing import overload from typing import Callable @@ -55,7 +53,6 @@ def overload(x): "capture_event", "capture_exception", "capture_message", - "configure_scope", "continue_trace", "flush", "get_baggage", @@ -194,56 +191,6 @@ def add_breadcrumb( return get_isolation_scope().add_breadcrumb(crumb, hint, **kwargs) -@overload -def configure_scope(): - # type: () -> ContextManager[Scope] - pass - - -@overload -def configure_scope( # noqa: F811 - callback, # type: Callable[[Scope], None] -): - # type: (...) -> None - pass - - -def configure_scope( # noqa: F811 - callback=None, # type: Optional[Callable[[Scope], None]] -): - # type: (...) -> Optional[ContextManager[Scope]] - """ - Reconfigures the scope. - - :param callback: If provided, call the callback with the current scope. - - :returns: If no callback is provided, returns a context manager that returns the scope. - """ - warnings.warn( - "sentry_sdk.configure_scope is deprecated and will be removed in the next major version. " - "Please consult our migration guide to learn how to migrate to the new API: " - "https://docs.sentry.io/platforms/python/migration/1.x-to-2.x#scope-configuring", - DeprecationWarning, - stacklevel=2, - ) - - scope = get_isolation_scope() - scope.generate_propagation_context() - - if callback is not None: - # TODO: used to return None when client is None. Check if this changes behavior. - callback(scope) - - return None - - @contextmanager - def inner(): - # type: () -> Generator[Scope, None, None] - yield scope - - return inner() - - @overload def push_scope(): # type: () -> ContextManager[Scope] diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index 148edac334..32dfd35876 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -31,10 +31,6 @@ from strawberry import Schema from strawberry.extensions import SchemaExtension # type: ignore from strawberry.extensions.tracing.utils import should_skip_tracing as strawberry_should_skip_tracing # type: ignore - from strawberry.extensions.tracing import ( # type: ignore - SentryTracingExtension as StrawberrySentryAsyncExtension, - SentryTracingExtensionSync as StrawberrySentrySyncExtension, - ) from strawberry.http import async_base_view, sync_base_view # type: ignore except ImportError: raise DidNotEnable("strawberry-graphql is not installed") @@ -104,14 +100,6 @@ def _sentry_patched_schema_init(self, *args, **kwargs): "False" if should_use_async_extension else "True", ) - # remove the built in strawberry sentry extension, if present - extensions = [ - extension - for extension in extensions - if extension - not in (StrawberrySentryAsyncExtension, StrawberrySentrySyncExtension) - ] - # add our extension extensions.append( SentryAsyncExtension if should_use_async_extension else SentrySyncExtension @@ -412,11 +400,6 @@ def inner(event, hint): def _guess_if_using_async(extensions): # type: (List[SchemaExtension]) -> bool - if StrawberrySentryAsyncExtension in extensions: - return True - elif StrawberrySentrySyncExtension in extensions: - return False - return bool( {"starlette", "starlite", "litestar", "fastapi"} & set(_get_installed_modules()) ) diff --git a/tests/integrations/strawberry/test_strawberry.py b/tests/integrations/strawberry/test_strawberry.py index dcc6632bdb..977aadc0cd 100644 --- a/tests/integrations/strawberry/test_strawberry.py +++ b/tests/integrations/strawberry/test_strawberry.py @@ -10,10 +10,6 @@ from fastapi import FastAPI from fastapi.testclient import TestClient from flask import Flask -from strawberry.extensions.tracing import ( - SentryTracingExtension, - SentryTracingExtensionSync, -) from strawberry.fastapi import GraphQLRouter from strawberry.flask.views import GraphQLView @@ -143,24 +139,6 @@ def test_infer_execution_type_from_installed_packages_sync(sentry_init): assert SentrySyncExtension in schema.extensions -def test_replace_existing_sentry_async_extension(sentry_init): - sentry_init(integrations=[StrawberryIntegration()]) - - schema = strawberry.Schema(Query, extensions=[SentryTracingExtension]) - assert SentryTracingExtension not in schema.extensions - assert SentrySyncExtension not in schema.extensions - assert SentryAsyncExtension in schema.extensions - - -def test_replace_existing_sentry_sync_extension(sentry_init): - sentry_init(integrations=[StrawberryIntegration()]) - - schema = strawberry.Schema(Query, extensions=[SentryTracingExtensionSync]) - assert SentryTracingExtensionSync not in schema.extensions - assert SentryAsyncExtension not in schema.extensions - assert SentrySyncExtension in schema.extensions - - @parameterize_strawberry_test def test_capture_request_if_available_and_send_pii_is_on( request, diff --git a/tests/new_scopes_compat/test_new_scopes_compat.py b/tests/new_scopes_compat/test_new_scopes_compat.py index 21e2ac27d3..3c7d2fced2 100644 --- a/tests/new_scopes_compat/test_new_scopes_compat.py +++ b/tests/new_scopes_compat/test_new_scopes_compat.py @@ -11,35 +11,6 @@ """ -def test_configure_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with configure_scope` block. - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with sentry_sdk.configure_scope() as scope: # configure scope - sentry_sdk.set_tag("B1", 1) - scope.set_tag("B2", 1) - sentry_sdk.capture_message("Event B") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1} - assert event_z["tags"] == {"A": 1, "B1": 1, "B2": 1, "Z": 1} - - def test_push_scope_sdk1(sentry_init, capture_events): """ Mutate data in a `with push_scope` block diff --git a/tests/new_scopes_compat/test_new_scopes_compat_event.py b/tests/new_scopes_compat/test_new_scopes_compat_event.py index db1e5fec4b..af4f0c6efb 100644 --- a/tests/new_scopes_compat/test_new_scopes_compat_event.py +++ b/tests/new_scopes_compat/test_new_scopes_compat_event.py @@ -335,71 +335,6 @@ def test_event(sentry_init, capture_envelopes, expected_error, expected_transact envelopes = capture_envelopes() - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event2(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub.current: # with hub - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event3(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - with Hub(Hub.current): sentry_sdk.set_tag("A", 1) # will not be added @@ -431,43 +366,7 @@ def test_event3(sentry_init, capture_envelopes, expected_error, expected_transac assert attachment.payload.bytes == b"Hello World" -def test_event4(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub(Hub.current): # with hub clone - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event5(sentry_init, capture_envelopes, expected_error, expected_transaction): +def test_event2(sentry_init, capture_envelopes, expected_error, expected_transaction): _init_sentry_sdk(sentry_init) envelopes = capture_envelopes() diff --git a/tests/test_api.py b/tests/test_api.py index ae194af7fd..35c0576027 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -11,7 +11,6 @@ is_initialized, start_transaction, set_tags, - configure_scope, push_scope, get_global_scope, get_current_scope, @@ -185,12 +184,6 @@ def test_set_tags(sentry_init, capture_events): }, "Updating tags with empty dict changed tags" -def test_configure_scope_deprecation(): - with pytest.warns(DeprecationWarning): - with configure_scope(): - ... - - def test_push_scope_deprecation(): with pytest.warns(DeprecationWarning): with push_scope(): diff --git a/tests/test_client.py b/tests/test_client.py index f6c2cec05c..7393991af7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,10 +12,8 @@ import sentry_sdk from sentry_sdk import ( - Hub, Client, add_breadcrumb, - configure_scope, capture_message, capture_exception, capture_event, @@ -557,39 +555,12 @@ def capture_envelope(self, envelope): ) start = time.time() - output = subprocess.check_output([sys.executable, str(app)]) + subprocess.check_output([sys.executable, str(app)]) end = time.time() # Each message takes at least 0.1 seconds to process assert int(end - start) >= num_messages / 10 - assert output.count(b"HI") == num_messages - - -def test_configure_scope_available( - sentry_init, request, monkeypatch, suppress_deprecation_warnings -): - """ - Test that scope is configured if client is configured - - This test can be removed once configure_scope and the Hub are removed. - """ - sentry_init() - - with configure_scope() as scope: - assert scope is Hub.current.scope - scope.set_tag("foo", "bar") - - calls = [] - - def callback(scope): - calls.append(scope) - scope.set_tag("foo", "bar") - - assert configure_scope(callback) is None - assert len(calls) == 1 - assert calls[0] is Hub.current.scope - @pytest.mark.tests_internal_exceptions def test_client_debug_option_enabled(sentry_init, caplog): @@ -609,27 +580,6 @@ def test_client_debug_option_disabled(with_client, sentry_init, caplog): assert "OK" not in caplog.text -@pytest.mark.skip( - reason="New behavior in SDK 2.0: You have a scope before init and add data to it." -) -def test_scope_initialized_before_client(sentry_init, capture_events): - """ - This is a consequence of how configure_scope() works. We must - make `configure_scope()` a noop if no client is configured. Even - if the user later configures a client: We don't know that. - """ - with configure_scope() as scope: - scope.set_tag("foo", 42) - - sentry_init() - - events = capture_events() - capture_message("hi") - (event,) = events - - assert "tags" not in event - - def test_weird_chars(sentry_init, capture_events): sentry_init() events = capture_events()