Skip to content

Commit

Permalink
feat(hub): Emit deprecation warnings from Hub API
Browse files Browse the repository at this point in the history
`sentry_sdk.Hub` has been deprecated since Sentry SDK version 2.0.0 per our docs; however, we waited with adding deprecation warnings because the SDK itself was still using `Hub` APIs until recently.

Since we no longer use `Hub` APIs in the SDK (except in `Hub` APIs which are themselves deprecated), we can now start emitting deprecation warnings.

Closes #3265
  • Loading branch information
szokeasaurusrex committed Jul 16, 2024
1 parent 41e4bb4 commit da15b63
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 8 deletions.
30 changes: 28 additions & 2 deletions sentry_sdk/hub.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import warnings
from contextlib import contextmanager

from sentry_sdk._compat import with_metaclass
Expand Down Expand Up @@ -55,6 +56,23 @@ def overload(x):
return x


_HUB_DEPRECATION_MESSAGE = (
"`sentry_sdk.Hub` is deprecated and will be removed in a future major release. "
"Please consult our 1.x to 2.x migration guide for details on how to migrate "
"`Hub` usage to the new API: "
"https://docs.sentry.io/platforms/python/migration/1.x-to-2.x"
)


@contextmanager
def _suppress_hub_deprecation_warning():
# type: () -> Generator[None, None, None]
"""Utility function to suppress deprecation warnings for the Hub."""
with warnings.catch_warnings():
warnings.filterwarnings("ignore", _HUB_DEPRECATION_MESSAGE, DeprecationWarning)
yield


_local = ContextVar("sentry_current_hub")


Expand All @@ -63,16 +81,20 @@ class HubMeta(type):
def current(cls):
# type: () -> Hub
"""Returns the current instance of the hub."""
warnings.warn(_HUB_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2)
rv = _local.get(None)
if rv is None:
rv = Hub(GLOBAL_HUB)
with _suppress_hub_deprecation_warning():
# This will raise a deprecation warning; supress it since we already warned above.
rv = Hub(GLOBAL_HUB)
_local.set(rv)
return rv

@property
def main(cls):
# type: () -> Hub
"""Returns the main instance of the hub."""
warnings.warn(_HUB_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2)
return GLOBAL_HUB


Expand Down Expand Up @@ -103,6 +125,7 @@ def __init__(
scope=None, # type: Optional[Any]
):
# type: (...) -> None
warnings.warn(_HUB_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2)

current_scope = None

Expand Down Expand Up @@ -689,7 +712,10 @@ def trace_propagation_meta(self, span=None):
)


GLOBAL_HUB = Hub()
with _suppress_hub_deprecation_warning():
# Suppress deprecation warning for the Hub here, since we still always
# import this module.
GLOBAL_HUB = Hub()
_local.set(GLOBAL_HUB)


Expand Down
12 changes: 12 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import os
import socket
import warnings
from threading import Thread
from contextlib import contextmanager
from http.server import BaseHTTPRequestHandler, HTTPServer
Expand Down Expand Up @@ -561,6 +562,17 @@ def teardown_profiling():
teardown_continuous_profiler()


@pytest.fixture()
def suppress_deprecation_warnings():
"""
Use this fixture to suppress deprecation warnings in a test.
Useful for testing deprecated SDK features.
"""
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
yield


class MockServerRequestHandler(BaseHTTPRequestHandler):
def do_GET(self): # noqa: N802
# Process an HTTP GET request and return a response with an HTTP 200 status.
Expand Down
2 changes: 1 addition & 1 deletion tests/new_scopes_compat/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@


@pytest.fixture(autouse=True)
def isolate_hub():
def isolate_hub(suppress_deprecation_warnings):
with sentry_sdk.Hub(None):
yield
2 changes: 1 addition & 1 deletion tests/profiler/test_transaction_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ def test_profile_processing(
assert processed["samples"] == expected["samples"]


def test_hub_backwards_compatibility():
def test_hub_backwards_compatibility(suppress_deprecation_warnings):
hub = sentry_sdk.Hub()

with pytest.warns(DeprecationWarning):
Expand Down
18 changes: 18 additions & 0 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,3 +839,21 @@ def test_last_event_id_scope(sentry_init):
# Should not crash
with isolation_scope() as scope:
assert scope.last_event_id() is None


def test_hub_constructor_deprecation_warning():
with pytest.warns(DeprecationWarning):
Hub()


def test_hub_current_deprecation_warning():
with pytest.warns(DeprecationWarning) as warning_records:
Hub.current

# Make sure we only issue one deprecation warning
assert len(warning_records) == 1


def test_hub_main_deprecation_warnings():
with pytest.warns(DeprecationWarning):
Hub.main
20 changes: 16 additions & 4 deletions tests/tracing/test_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,29 @@ def test_start_span_to_start_transaction(sentry_init, capture_events):
assert events[1]["transaction"] == "/2/"


@pytest.mark.parametrize("parameter_value", (sentry_sdk.Hub(), sentry_sdk.Scope()))
def test_passing_hub_parameter_to_transaction_finish(parameter_value):
@pytest.mark.parametrize(
"parameter_value_getter",
# Use lambda to avoid Hub deprecation warning here (will suppress it in the test)
(lambda: sentry_sdk.Hub(), lambda: sentry_sdk.Scope()),
)
def test_passing_hub_parameter_to_transaction_finish(
suppress_deprecation_warnings, parameter_value_getter
):
parameter_value = parameter_value_getter()
transaction = sentry_sdk.tracing.Transaction()
with pytest.warns(DeprecationWarning):
transaction.finish(hub=parameter_value)


def test_passing_hub_object_to_scope_transaction_finish():
def test_passing_hub_object_to_scope_transaction_finish(suppress_deprecation_warnings):
transaction = sentry_sdk.tracing.Transaction()

# Do not move the following line under the `with` statement. Otherwise, the Hub.__init__ deprecation
# warning will be confused with the transaction.finish deprecation warning that we are testing.
hub = sentry_sdk.Hub()

with pytest.warns(DeprecationWarning):
transaction.finish(sentry_sdk.Hub())
transaction.finish(hub)


def test_no_warnings_scope_to_transaction_finish():
Expand Down

0 comments on commit da15b63

Please sign in to comment.