diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 1efa4a7529..6db4948a01 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -15,6 +15,18 @@ Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of wh - The `reraise` function was moved from `sentry_sdk._compat` to `sentry_sdk.utils`. - Moved the contents of `tracing_utils_py3.py` to `tracing_utils.py`. The `start_child_span_decorator` is now in `sentry_sdk.tracing_utils`. - The actual implementation of `get_current_span` was moved to `sentry_sdk.tracing_utils`. `sentry_sdk.get_current_span` is still accessible as part of the top-level API. +- The classes listed in the table below are now abstract base classes. Therefore, they can no longer be instantiated. Subclasses can only be instantiated if they implement all of the abstract methods. +
+ Show table + + | Class | Abstract methods | + | ------------------------------------- | -------------------------------------- | + | `sentry_sdk.integrations.Integration` | `setup_once` | + | `sentry_sdk.metrics.Metric` | `add`, `serialize_value`, and `weight` | + | `sentry_sdk.profiler.Scheduler` | `setup` and `teardown` | + | `sentry_sdk.transport.Transport` | `capture_envelope` | + +
## Removed @@ -33,16 +45,17 @@ Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of wh - Removed `sentry_sdk.utils.Auth.store_api_url`. - `sentry_sdk.utils.Auth.get_api_url`'s now accepts a `sentry_sdk.consts.EndpointType` enum instead of a string as its only parameter. We recommend omitting this argument when calling the function, since the parameter's default value is the only possible `sentry_sdk.consts.EndpointType` value. The parameter exists for future compatibility. - Removed `tracing_utils_py2.py`. The `start_child_span_decorator` is now in `sentry_sdk.tracing_utils`. +- Removed the `sentry_sdk.profiler.Scheduler.stop_profiling` method. Any calls to this method can simply be removed, since this was a no-op method. ## Deprecated - `profiler_mode` and `profiles_sample_rate` have been deprecated as `_experiments` options. Use them as top level options instead: - ```python - sentry_sdk.init( - ..., - profiler_mode="thread", - profiles_sample_rate=1.0, - ) - ``` + ```python + sentry_sdk.init( + ..., + profiler_mode="thread", + profiles_sample_rate=1.0, + ) + ``` - Deprecated `sentry_sdk.transport.Transport.capture_event`. Please use `sentry_sdk.transport.Transport.capture_envelope`, instead. - Passing a function to `sentry_sdk.init`'s `transport` keyword argument has been deprecated. If you wish to provide a custom transport, please pass a `sentry_sdk.transport.Transport` instance or a subclass. diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index cd60ea110b..f28ea47072 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod from threading import Lock from sentry_sdk._types import TYPE_CHECKING @@ -177,7 +178,7 @@ class DidNotEnable(Exception): # noqa: N818 """ -class Integration: +class Integration(ABC): """Baseclass for all integrations. To accept options for an integration, implement your own constructor that @@ -191,6 +192,7 @@ class Integration: """String unique ID of integration type""" @staticmethod + @abstractmethod def setup_once(): # type: () -> None """ @@ -203,4 +205,4 @@ def setup_once(): Inside those hooks `Integration.current` can be used to access the instance again. """ - raise NotImplementedError() + pass diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 3be2f22ee6..287f4cf0c5 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -51,6 +51,15 @@ def request_body_within_bounds(client, content_length): class RequestExtractor: + """ + Base class for request extraction. + """ + + # It does not make sense to make this class an ABC because it is not used + # for typing, only so that child classes can inherit common methods from + # it. Only some child classes implement all methods that raise + # NotImplementedError in this class. + def __init__(self, request): # type: (Any) -> None self.request = request diff --git a/sentry_sdk/metrics.py b/sentry_sdk/metrics.py index 47264de0f1..9616567667 100644 --- a/sentry_sdk/metrics.py +++ b/sentry_sdk/metrics.py @@ -6,6 +6,7 @@ import threading import time import zlib +from abc import ABC, abstractmethod from contextlib import contextmanager from datetime import datetime, timezone from functools import wraps, partial @@ -119,23 +120,29 @@ def new_func(*args, **kwargs): return new_func -class Metric: +class Metric(ABC): __slots__ = () + @abstractmethod + def __init__(self, first): + # type: (MetricValue) -> None + pass + @property + @abstractmethod def weight(self): - # type: (...) -> int - raise NotImplementedError() + # type: () -> int + pass - def add( - self, value # type: MetricValue - ): - # type: (...) -> None - raise NotImplementedError() + @abstractmethod + def add(self, value): + # type: (MetricValue) -> None + pass + @abstractmethod def serialize_value(self): - # type: (...) -> Iterable[FlushedMetricValue] - raise NotImplementedError() + # type: () -> Iterable[FlushedMetricValue] + pass class CounterMetric(Metric): @@ -333,7 +340,7 @@ def _encode_locations(timestamp, code_locations): "g": GaugeMetric, "d": DistributionMetric, "s": SetMetric, -} +} # type: dict[MetricType, type[Metric]] # some of these are dumb TIMING_FUNCTIONS = { diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index 2e10435675..dda64d7c28 100644 --- a/sentry_sdk/profiler.py +++ b/sentry_sdk/profiler.py @@ -33,6 +33,7 @@ import threading import time import uuid +from abc import ABC, abstractmethod from collections import deque import sentry_sdk @@ -587,7 +588,6 @@ def stop(self): assert self.scheduler, "No scheduler specified" logger.debug("[Profiling] Stopping profile") self.active = False - self.scheduler.stop_profiling(self) self.stop_ns = nanosecond_time() def __enter__(self): @@ -756,7 +756,7 @@ def valid(self): return True -class Scheduler: +class Scheduler(ABC): mode = "unknown" # type: ProfilerMode def __init__(self, frequency): @@ -778,27 +778,30 @@ def __exit__(self, ty, value, tb): # type: (Optional[Any], Optional[Any], Optional[Any]) -> None self.teardown() + @abstractmethod def setup(self): # type: () -> None - raise NotImplementedError + pass + @abstractmethod def teardown(self): # type: () -> None - raise NotImplementedError + pass def ensure_running(self): # type: () -> None - raise NotImplementedError + """ + Ensure the scheduler is running. By default, this method is a no-op. + The method should be overridden by any implementation for which it is + relevant. + """ + return None def start_profiling(self, profile): # type: (Profile) -> None self.ensure_running() self.new_profiles.append(profile) - def stop_profiling(self, profile): - # type: (Profile) -> None - pass - def make_sampler(self): # type: () -> Callable[..., None] cwd = os.getcwd() diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py index 1a4d02dc04..bb412a4d86 100644 --- a/sentry_sdk/transport.py +++ b/sentry_sdk/transport.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod import io import warnings import urllib3 @@ -33,7 +34,7 @@ DataCategory = Optional[str] -class Transport: +class Transport(ABC): """Baseclass for all transports. A transport is used to send an event to sentry. @@ -72,6 +73,7 @@ def capture_event( envelope.add_event(event) self.capture_envelope(envelope) + @abstractmethod def capture_envelope( self, envelope # type: Envelope ): @@ -83,7 +85,7 @@ def capture_envelope( submitted to Sentry. We use it to send all event data (including errors, transactions, crons checkins, etc.) to Sentry. """ - raise NotImplementedError() + pass def flush( self,