From 64a9bf368390496fd2e452582b939ee97eca3cf2 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 22 Jan 2024 18:03:07 +0100 Subject: [PATCH 01/12] Convert `Transport` class into an ABC --- sentry_sdk/transport.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py index cd33956f54..4abb9388be 100644 --- a/sentry_sdk/transport.py +++ b/sentry_sdk/transport.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod import io import urllib3 import certifi @@ -35,7 +36,7 @@ from urllib import getproxies # type: ignore -class Transport: +class Transport(ABC): """Baseclass for all transports. A transport is used to send an event to sentry. @@ -63,6 +64,7 @@ def capture_event( """ raise NotImplementedError() + @abstractmethod def capture_envelope( self, envelope # type: Envelope ): @@ -75,7 +77,7 @@ def capture_envelope( regular "error" events should go through `capture_event` for backwards compat. """ - raise NotImplementedError() + pass def flush( self, From e478c589d60d9122cf90a7323bdbd893f62c8846 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 12:43:18 +0100 Subject: [PATCH 02/12] ABC metrics --- sentry_sdk/metrics.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sentry_sdk/metrics.py b/sentry_sdk/metrics.py index 47264de0f1..7a2296127a 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,24 @@ def new_func(*args, **kwargs): return new_func -class Metric: +class Metric(ABC): __slots__ = () @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): From e311007888136ac6df8cd8034a350c4180b8c8f6 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 12:50:28 +0100 Subject: [PATCH 03/12] ABC scheduler --- sentry_sdk/profiler.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index 2e10435675..1f7fa98413 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 @@ -756,7 +757,7 @@ def valid(self): return True -class Scheduler: +class Scheduler(ABC): mode = "unknown" # type: ProfilerMode def __init__(self, frequency): @@ -778,17 +779,20 @@ 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 + @abstractmethod def ensure_running(self): # type: () -> None - raise NotImplementedError + pass def start_profiling(self, profile): # type: (Profile) -> None From 88a1b27c239f7d707f243a2043317e229caf8644 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 12:56:34 +0100 Subject: [PATCH 04/12] ABC integration --- sentry_sdk/integrations/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 From 4f00d6dce8c152afcc1b5b55a6ba98a5b2734014 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 14:24:12 +0100 Subject: [PATCH 05/12] RequestExtractor comment --- sentry_sdk/integrations/_wsgi_common.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 3be2f22ee6..2ccbc9afba 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -51,6 +51,12 @@ def request_body_within_bounds(client, content_length): class RequestExtractor: + """ + Base class for request extraction. It does not make sense to make this 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 From 36c95b397afba842c1818b0fb5165c22c452bd5b Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 15:17:10 +0100 Subject: [PATCH 06/12] Deprecate `stop_profiling` and stop calling it This change is required because otherwise, the linter complains about the `stop_profiling` being an empty concrete method in an abstract class. --- sentry_sdk/profiler.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index 1f7fa98413..d1d70197ce 100644 --- a/sentry_sdk/profiler.py +++ b/sentry_sdk/profiler.py @@ -32,6 +32,7 @@ import sys import threading import time +import warnings import uuid from abc import ABC, abstractmethod from collections import deque @@ -588,7 +589,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): @@ -799,9 +799,14 @@ def start_profiling(self, profile): self.ensure_running() self.new_profiles.append(profile) - def stop_profiling(self, profile): - # type: (Profile) -> None - pass + def stop_profiling(self, _): + # type: (...) -> None + warnings.warn( + "stop_profiling is deprecated and will be removed in the next major release. " + "This method does nothing, so please remove any calls to it from your code.", + DeprecationWarning, + stacklevel=2, + ) def make_sampler(self): # type: () -> Callable[..., None] From 3b0bcba2112f3476145b8722399c2d977600a4c7 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 15:24:11 +0100 Subject: [PATCH 07/12] Actually, let's remove `stop_profiling` --- MIGRATION_GUIDE.md | 17 +++++++++-------- sentry_sdk/profiler.py | 10 ---------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 9a24e8d11d..042ab17690 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -22,7 +22,7 @@ Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of wh - Removed support for Celery 3.\*. - Removed support for Django 1.8, 1.9, 1.10. - Removed support for Flask 0.\*. -- Removed `last_event_id()` top level API. The last event Id is still returned by `capture_event()`, `capture_exception()` and `capture_message()` but the top level api `sentry_sdk.last_event_id()` has been removed. +- Removed `last_event_id()` top level API. The last event Id is still returned by `capture_event()`, `capture_exception()` and `capture_message()` but the top level api `sentry_sdk.last_event_id()` has been removed. - `sentry_sdk._functools` was removed. - A number of compatibility utilities were removed from `sentry_sdk._compat`: the constants `PY2` and `PY33`; the functions `datetime_utcnow`, `utc_from_timestamp`, `implements_str`, `contextmanager`; and the aliases `text_type`, `string_types`, `number_types`, `int_types`, `iteritems`, `binary_sequence_types`. - The deprecated `with_locals` configuration option was removed. Use `include_local_variables` instead. See https://docs.sentry.io/platforms/python/configuration/options/#include-local-variables. @@ -34,16 +34,17 @@ Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of wh - Removed `sentry_sdk.tracing.Span.new_span`. Use `sentry_sdk.tracing.Span.start_child` instead. - Removed `sentry_sdk.tracing.Transaction.new_span`. Use `sentry_sdk.tracing.Transaction.start_child` instead. - Removed support for `user.segment`. It was also removed from the trace header as well as from the dynamic sampling context. +- 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 - 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. - `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, + ) + ``` diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index d1d70197ce..fc16a03c0f 100644 --- a/sentry_sdk/profiler.py +++ b/sentry_sdk/profiler.py @@ -32,7 +32,6 @@ import sys import threading import time -import warnings import uuid from abc import ABC, abstractmethod from collections import deque @@ -799,15 +798,6 @@ def start_profiling(self, profile): self.ensure_running() self.new_profiles.append(profile) - def stop_profiling(self, _): - # type: (...) -> None - warnings.warn( - "stop_profiling is deprecated and will be removed in the next major release. " - "This method does nothing, so please remove any calls to it from your code.", - DeprecationWarning, - stacklevel=2, - ) - def make_sampler(self): # type: () -> Callable[..., None] cwd = os.getcwd() From ba7e4dff14cfdb330d6e2e409903a44cf32fd876 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 15:41:35 +0100 Subject: [PATCH 08/12] Add ABCs to migration guide --- MIGRATION_GUIDE.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 042ab17690..8807ec8cef 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 Pyramid integration will not capture errors that might happen in `authenticated_userid()` in a custom `AuthenticationPolicy` class. - Setting the parameter `propagate_hub` to `True` in `ThreadingIntegration(propagate_hub=True)` only works on Python 3.7+. - The method `need_code_loation` of the `MetricsAggregator` was renamed to `need_code_location`. +- 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` | `ensure_running`, `setup`, and `teardown` | + | `sentry_sdk.transport.Transport` | `capture_envelope` | + +
## Removed From 768798f451d691f35841c42b6d4053991b5f5402 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 21 Feb 2024 16:02:19 +0100 Subject: [PATCH 09/12] fix mypy --- sentry_sdk/metrics.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/metrics.py b/sentry_sdk/metrics.py index 7a2296127a..9616567667 100644 --- a/sentry_sdk/metrics.py +++ b/sentry_sdk/metrics.py @@ -123,6 +123,11 @@ def new_func(*args, **kwargs): class Metric(ABC): __slots__ = () + @abstractmethod + def __init__(self, first): + # type: (MetricValue) -> None + pass + @property @abstractmethod def weight(self): @@ -335,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 = { From 760adbe54b3d78c6b9c43653a8151e3f0efaf793 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 26 Feb 2024 11:50:29 +0100 Subject: [PATCH 10/12] Make docstring more relevant to users --- sentry_sdk/integrations/_wsgi_common.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 2ccbc9afba..287f4cf0c5 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -52,11 +52,14 @@ def request_body_within_bounds(client, content_length): class RequestExtractor: """ - Base class for request extraction. It does not make sense to make this 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. + 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 From 9f90b6096c24e0423f040b1f9febea10f02e5891 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 26 Feb 2024 11:52:10 +0100 Subject: [PATCH 11/12] `ensure_running` no longer abstract --- MIGRATION_GUIDE.md | 12 ++++++------ sentry_sdk/profiler.py | 8 ++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 8807ec8cef..4b5d385d2a 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -19,12 +19,12 @@ Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of wh
Show table - | Class | Abstract methods | - | ------------------------------------- | ----------------------------------------- | - | `sentry_sdk.integrations.Integration` | `setup_once` | - | `sentry_sdk.metrics.Metric` | `add`, `serialize_value`, and `weight` | - | `sentry_sdk.profiler.Scheduler` | `ensure_running`, `setup`, and `teardown` | - | `sentry_sdk.transport.Transport` | `capture_envelope` | + | 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` |
diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index fc16a03c0f..74362bfe33 100644 --- a/sentry_sdk/profiler.py +++ b/sentry_sdk/profiler.py @@ -788,10 +788,14 @@ def teardown(self): # type: () -> None pass - @abstractmethod def ensure_running(self): + """ + 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. + """ # type: () -> None - pass + return None def start_profiling(self, profile): # type: (Profile) -> None From 1f3438dea19e857db4fd7ce818c1d2508ed27304 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 26 Feb 2024 12:56:33 +0100 Subject: [PATCH 12/12] Fix mypy --- sentry_sdk/profiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py index 74362bfe33..dda64d7c28 100644 --- a/sentry_sdk/profiler.py +++ b/sentry_sdk/profiler.py @@ -789,12 +789,12 @@ def teardown(self): pass def ensure_running(self): + # type: () -> None """ 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. """ - # type: () -> None return None def start_profiling(self, profile):