From b3678cb439e6e969d41d43cbf782d5442cd4c2c9 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Fri, 20 Sep 2024 11:26:12 +0200 Subject: [PATCH] ref(client): Improve `get_integration` typing Improve `get_integration` typing to make it clear that we return an `Optional[Integration]`. Further, add overloads to specify that when called with some integration type `I` (i.e. `I` is a subclass of `Integration`), then `get_integration` guarantees a return value of `Optional[I]`. These changes should enhance type safety by explicitly guaranteeing the existing behavior of `get_integration`. --- sentry_sdk/client.py | 34 +++++++++++++++++++--- sentry_sdk/integrations/aiohttp.py | 4 +++ sentry_sdk/integrations/anthropic.py | 8 ++--- sentry_sdk/integrations/atexit.py | 5 +++- sentry_sdk/integrations/aws_lambda.py | 12 +++++--- sentry_sdk/integrations/bottle.py | 6 +++- sentry_sdk/integrations/celery/__init__.py | 6 ++-- sentry_sdk/integrations/cohere.py | 24 +++++++-------- sentry_sdk/integrations/django/__init__.py | 9 +++--- sentry_sdk/integrations/fastapi.py | 4 +-- sentry_sdk/integrations/flask.py | 4 ++- sentry_sdk/integrations/gcp.py | 6 ++-- sentry_sdk/integrations/huggingface_hub.py | 8 ++--- sentry_sdk/integrations/langchain.py | 2 ++ sentry_sdk/integrations/openai.py | 16 +++++----- sentry_sdk/integrations/pyramid.py | 5 +++- sentry_sdk/integrations/sanic.py | 4 +-- sentry_sdk/integrations/starlette.py | 22 ++++++++------ sentry_sdk/integrations/strawberry.py | 6 +++- sentry_sdk/integrations/sys_exit.py | 17 +++++------ sentry_sdk/integrations/threading.py | 5 ++-- 21 files changed, 130 insertions(+), 77 deletions(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index f8bc76771b..0dd216ab21 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -5,7 +5,7 @@ from collections.abc import Mapping from datetime import datetime, timezone from importlib import import_module -from typing import cast +from typing import cast, overload from sentry_sdk._compat import PY37, check_uwsgi_thread_support from sentry_sdk.utils import ( @@ -54,6 +54,7 @@ from typing import Sequence from typing import Type from typing import Union + from typing import TypeVar from sentry_sdk._types import Event, Hint, SDKInfo from sentry_sdk.integrations import Integration @@ -62,6 +63,7 @@ from sentry_sdk.session import Session from sentry_sdk.transport import Transport + I = TypeVar("I", bound=Integration) # noqa: E741 _client_init_debug = ContextVar("client_init_debug") @@ -195,8 +197,20 @@ def capture_session(self, *args, **kwargs): # type: (*Any, **Any) -> None return None - def get_integration(self, *args, **kwargs): - # type: (*Any, **Any) -> Any + if TYPE_CHECKING: + + @overload + def get_integration(self, name_or_class): + # type: (str) -> Optional[Integration] + ... + + @overload + def get_integration(self, name_or_class): + # type: (type[I]) -> Optional[I] + ... + + def get_integration(self, name_or_class): + # type: (Union[str, type[Integration]]) -> Optional[Integration] return None def close(self, *args, **kwargs): @@ -815,10 +829,22 @@ def capture_session( else: self.session_flusher.add_session(session) + if TYPE_CHECKING: + + @overload + def get_integration(self, name_or_class): + # type: (str) -> Optional[Integration] + ... + + @overload + def get_integration(self, name_or_class): + # type: (type[I]) -> Optional[I] + ... + def get_integration( self, name_or_class # type: Union[str, Type[Integration]] ): - # type: (...) -> Any + # type: (...) -> Optional[Integration] """Returns the integration for this client by name or class. If the client does not have that integration then `None` is returned. """ diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py index a447b67f38..5f38b6855c 100644 --- a/sentry_sdk/integrations/aiohttp.py +++ b/sentry_sdk/integrations/aiohttp.py @@ -1,5 +1,6 @@ import sys import weakref +from functools import wraps import sentry_sdk from sentry_sdk.api import continue_trace @@ -146,11 +147,14 @@ async def sentry_app_handle(self, request, *args, **kwargs): old_urldispatcher_resolve = UrlDispatcher.resolve + @wraps(old_urldispatcher_resolve) async def sentry_urldispatcher_resolve(self, request): # type: (UrlDispatcher, Request) -> UrlMappingMatchInfo rv = await old_urldispatcher_resolve(self, request) integration = sentry_sdk.get_client().get_integration(AioHttpIntegration) + if integration is None: + return rv name = None diff --git a/sentry_sdk/integrations/anthropic.py b/sentry_sdk/integrations/anthropic.py index f54708eba5..f3fd8d2d92 100644 --- a/sentry_sdk/integrations/anthropic.py +++ b/sentry_sdk/integrations/anthropic.py @@ -7,7 +7,6 @@ from sentry_sdk.scope import should_send_default_pii from sentry_sdk.utils import ( capture_internal_exceptions, - ensure_integration_enabled, event_from_exception, package_version, ) @@ -78,10 +77,11 @@ def _calculate_token_usage(result, span): def _wrap_message_create(f): # type: (Any) -> Any @wraps(f) - @ensure_integration_enabled(AnthropicIntegration, f) def _sentry_patched_create(*args, **kwargs): # type: (*Any, **Any) -> Any - if "messages" not in kwargs: + integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) + + if integration is None or "messages" not in kwargs: return f(*args, **kwargs) try: @@ -106,8 +106,6 @@ def _sentry_patched_create(*args, **kwargs): span.__exit__(None, None, None) raise exc from None - integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) - with capture_internal_exceptions(): span.set_data(SPANDATA.AI_MODEL_ID, model) span.set_data(SPANDATA.AI_STREAMING, False) diff --git a/sentry_sdk/integrations/atexit.py b/sentry_sdk/integrations/atexit.py index 43e25c1848..ac71270727 100644 --- a/sentry_sdk/integrations/atexit.py +++ b/sentry_sdk/integrations/atexit.py @@ -53,4 +53,7 @@ def _shutdown(): logger.debug("atexit: shutting down client") sentry_sdk.get_isolation_scope().end_session() - client.close(callback=integration.callback) + + if integration is not None: + # Should not be None, but mypy doesn't know that + client.close(callback=integration.callback) diff --git a/sentry_sdk/integrations/aws_lambda.py b/sentry_sdk/integrations/aws_lambda.py index f0cdf31f8c..831cde8999 100644 --- a/sentry_sdk/integrations/aws_lambda.py +++ b/sentry_sdk/integrations/aws_lambda.py @@ -1,3 +1,4 @@ +import functools import json import re import sys @@ -70,7 +71,7 @@ def sentry_init_error(*args, **kwargs): def _wrap_handler(handler): # type: (F) -> F - @ensure_integration_enabled(AwsLambdaIntegration, handler) + @functools.wraps(handler) def sentry_handler(aws_event, aws_context, *args, **kwargs): # type: (Any, Any, *Any, **Any) -> Any @@ -84,6 +85,12 @@ def sentry_handler(aws_event, aws_context, *args, **kwargs): # will be the same for all events in the list, since they're all hitting # the lambda in the same request.) + client = sentry_sdk.get_client() + integration = client.get_integration(AwsLambdaIntegration) + + if integration is None: + return handler(aws_event, aws_context, *args, **kwargs) + if isinstance(aws_event, list) and len(aws_event) >= 1: request_data = aws_event[0] batch_size = len(aws_event) @@ -97,9 +104,6 @@ def sentry_handler(aws_event, aws_context, *args, **kwargs): # this is empty request_data = {} - client = sentry_sdk.get_client() - integration = client.get_integration(AwsLambdaIntegration) - configured_time = aws_context.get_remaining_time_in_millis() with sentry_sdk.isolation_scope() as scope: diff --git a/sentry_sdk/integrations/bottle.py b/sentry_sdk/integrations/bottle.py index b1800bd191..dc573eb958 100644 --- a/sentry_sdk/integrations/bottle.py +++ b/sentry_sdk/integrations/bottle.py @@ -1,3 +1,5 @@ +import functools + import sentry_sdk from sentry_sdk.tracing import SOURCE_FOR_STYLE from sentry_sdk.utils import ( @@ -81,10 +83,12 @@ def sentry_patched_wsgi_app(self, environ, start_response): old_handle = Bottle._handle - @ensure_integration_enabled(BottleIntegration, old_handle) + @functools.wraps(old_handle) def _patched_handle(self, environ): # type: (Bottle, Dict[str, Any]) -> Any integration = sentry_sdk.get_client().get_integration(BottleIntegration) + if integration is None: + return old_handle(self, environ) scope = sentry_sdk.get_isolation_scope() scope._name = "bottle" diff --git a/sentry_sdk/integrations/celery/__init__.py b/sentry_sdk/integrations/celery/__init__.py index 28a44015aa..9a984de8c3 100644 --- a/sentry_sdk/integrations/celery/__init__.py +++ b/sentry_sdk/integrations/celery/__init__.py @@ -248,13 +248,15 @@ def __exit__(self, exc_type, exc_value, traceback): def _wrap_task_run(f): # type: (F) -> F @wraps(f) - @ensure_integration_enabled(CeleryIntegration, f) def apply_async(*args, **kwargs): # type: (*Any, **Any) -> Any # Note: kwargs can contain headers=None, so no setdefault! # Unsure which backend though. - kwarg_headers = kwargs.get("headers") or {} integration = sentry_sdk.get_client().get_integration(CeleryIntegration) + if integration is None: + return f(*args, **kwargs) + + kwarg_headers = kwargs.get("headers") or {} propagate_traces = kwarg_headers.pop( "sentry-propagate-traces", integration.propagate_traces ) diff --git a/sentry_sdk/integrations/cohere.py b/sentry_sdk/integrations/cohere.py index 4d6a4a244c..b4c2af91da 100644 --- a/sentry_sdk/integrations/cohere.py +++ b/sentry_sdk/integrations/cohere.py @@ -14,11 +14,7 @@ import sentry_sdk from sentry_sdk.scope import should_send_default_pii from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.utils import ( - capture_internal_exceptions, - event_from_exception, - ensure_integration_enabled, -) +from sentry_sdk.utils import capture_internal_exceptions, event_from_exception try: from cohere.client import Client @@ -134,13 +130,15 @@ def collect_chat_response_fields(span, res, include_pii): set_data_normalized(span, "ai.warnings", res.meta.warnings) @wraps(f) - @ensure_integration_enabled(CohereIntegration, f) def new_chat(*args, **kwargs): # type: (*Any, **Any) -> Any - if "message" not in kwargs: - return f(*args, **kwargs) + integration = sentry_sdk.get_client().get_integration(CohereIntegration) - if not isinstance(kwargs.get("message"), str): + if ( + integration is None + or "message" not in kwargs + or not isinstance(kwargs.get("message"), str) + ): return f(*args, **kwargs) message = kwargs.get("message") @@ -158,8 +156,6 @@ def new_chat(*args, **kwargs): span.__exit__(None, None, None) raise e from None - integration = sentry_sdk.get_client().get_integration(CohereIntegration) - with capture_internal_exceptions(): if should_send_default_pii() and integration.include_prompts: set_data_normalized( @@ -227,15 +223,17 @@ def _wrap_embed(f): # type: (Callable[..., Any]) -> Callable[..., Any] @wraps(f) - @ensure_integration_enabled(CohereIntegration, f) def new_embed(*args, **kwargs): # type: (*Any, **Any) -> Any + integration = sentry_sdk.get_client().get_integration(CohereIntegration) + if integration is None: + return f(*args, **kwargs) + with sentry_sdk.start_span( op=consts.OP.COHERE_EMBEDDINGS_CREATE, name="Cohere Embedding Creation", origin=CohereIntegration.origin, ) as span: - integration = sentry_sdk.get_client().get_integration(CohereIntegration) if "texts" in kwargs and ( should_send_default_pii() and integration.include_prompts ): diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index fce93503e9..40d17b0507 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -411,10 +411,11 @@ def _set_transaction_name_and_source(scope, transaction_style, request): pass -@ensure_integration_enabled(DjangoIntegration) def _before_get_response(request): # type: (WSGIRequest) -> None integration = sentry_sdk.get_client().get_integration(DjangoIntegration) + if integration is None: + return _patch_drf() @@ -440,11 +441,10 @@ def _attempt_resolve_again(request, scope, transaction_style): _set_transaction_name_and_source(scope, transaction_style, request) -@ensure_integration_enabled(DjangoIntegration) def _after_get_response(request): # type: (WSGIRequest) -> None integration = sentry_sdk.get_client().get_integration(DjangoIntegration) - if integration.transaction_style != "url": + if integration is None or integration.transaction_style != "url": return scope = sentry_sdk.get_current_scope() @@ -510,11 +510,12 @@ def wsgi_request_event_processor(event, hint): return wsgi_request_event_processor -@ensure_integration_enabled(DjangoIntegration) def _got_request_exception(request=None, **kwargs): # type: (WSGIRequest, **Any) -> None client = sentry_sdk.get_client() integration = client.get_integration(DjangoIntegration) + if integration is None: + return if request is not None and integration.transaction_style == "url": scope = sentry_sdk.get_current_scope() diff --git a/sentry_sdk/integrations/fastapi.py b/sentry_sdk/integrations/fastapi.py index 6233a746cc..c3816b6565 100644 --- a/sentry_sdk/integrations/fastapi.py +++ b/sentry_sdk/integrations/fastapi.py @@ -99,10 +99,10 @@ def _sentry_call(*args, **kwargs): async def _sentry_app(*args, **kwargs): # type: (*Any, **Any) -> Any - if sentry_sdk.get_client().get_integration(FastApiIntegration) is None: + integration = sentry_sdk.get_client().get_integration(FastApiIntegration) + if integration is None: return await old_app(*args, **kwargs) - integration = sentry_sdk.get_client().get_integration(FastApiIntegration) request = args[0] _set_transaction_name_and_source( diff --git a/sentry_sdk/integrations/flask.py b/sentry_sdk/integrations/flask.py index 7b0fcf3187..b504376264 100644 --- a/sentry_sdk/integrations/flask.py +++ b/sentry_sdk/integrations/flask.py @@ -118,10 +118,12 @@ def _set_transaction_name_and_source(scope, transaction_style, request): pass -@ensure_integration_enabled(FlaskIntegration) def _request_started(app, **kwargs): # type: (Flask, **Any) -> None integration = sentry_sdk.get_client().get_integration(FlaskIntegration) + if integration is None: + return + request = flask_request._get_current_object() # Set the transaction name and source here, diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index 688d0de4d4..3983f550d3 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -1,3 +1,4 @@ +import functools import sys from copy import deepcopy from datetime import datetime, timedelta, timezone @@ -13,7 +14,6 @@ from sentry_sdk.utils import ( AnnotatedValue, capture_internal_exceptions, - ensure_integration_enabled, event_from_exception, logger, TimeoutThread, @@ -39,12 +39,14 @@ def _wrap_func(func): # type: (F) -> F - @ensure_integration_enabled(GcpIntegration, func) + @functools.wraps(func) def sentry_func(functionhandler, gcp_event, *args, **kwargs): # type: (Any, Any, *Any, **Any) -> Any client = sentry_sdk.get_client() integration = client.get_integration(GcpIntegration) + if integration is None: + return func(functionhandler, gcp_event, *args, **kwargs) configured_time = environ.get("FUNCTION_TIMEOUT_SEC") if not configured_time: diff --git a/sentry_sdk/integrations/huggingface_hub.py b/sentry_sdk/integrations/huggingface_hub.py index 857138ca1d..d09f6e2163 100644 --- a/sentry_sdk/integrations/huggingface_hub.py +++ b/sentry_sdk/integrations/huggingface_hub.py @@ -13,7 +13,6 @@ from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, - ensure_integration_enabled, ) try: @@ -55,9 +54,12 @@ def _capture_exception(exc): def _wrap_text_generation(f): # type: (Callable[..., Any]) -> Callable[..., Any] @wraps(f) - @ensure_integration_enabled(HuggingfaceHubIntegration, f) def new_text_generation(*args, **kwargs): # type: (*Any, **Any) -> Any + integration = sentry_sdk.get_client().get_integration(HuggingfaceHubIntegration) + if integration is None: + return f(*args, **kwargs) + if "prompt" in kwargs: prompt = kwargs["prompt"] elif len(args) >= 2: @@ -84,8 +86,6 @@ def new_text_generation(*args, **kwargs): span.__exit__(None, None, None) raise e from None - integration = sentry_sdk.get_client().get_integration(HuggingfaceHubIntegration) - with capture_internal_exceptions(): if should_send_default_pii() and integration.include_prompts: set_data_normalized(span, SPANDATA.AI_INPUT_MESSAGES, prompt) diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index fefc4619db..10757fbc92 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -420,6 +420,8 @@ def new_configure(*args, **kwargs): # type: (Any, Any) -> Any integration = sentry_sdk.get_client().get_integration(LangchainIntegration) + if integration is None: + return f(*args, **kwargs) with capture_internal_exceptions(): new_callbacks = [] # type: List[BaseCallbackHandler] diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index b8c758f75f..272f142b05 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -10,7 +10,6 @@ from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, - ensure_integration_enabled, ) from typing import TYPE_CHECKING @@ -113,11 +112,12 @@ def _calculate_chat_completion_usage( def _wrap_chat_completion_create(f): # type: (Callable[..., Any]) -> Callable[..., Any] - @ensure_integration_enabled(OpenAIIntegration, f) + @wraps(f) def new_chat_completion(*args, **kwargs): # type: (*Any, **Any) -> Any - if "messages" not in kwargs: - # invalid call (in all versions of openai), let it return error + integration = sentry_sdk.get_client().get_integration(OpenAIIntegration) + if integration is None or "messages" not in kwargs: + # no "messages" means invalid call (in all versions of openai), let it return error return f(*args, **kwargs) try: @@ -144,8 +144,6 @@ def new_chat_completion(*args, **kwargs): span.__exit__(None, None, None) raise e from None - integration = sentry_sdk.get_client().get_integration(OpenAIIntegration) - with capture_internal_exceptions(): if should_send_default_pii() and integration.include_prompts: set_data_normalized(span, SPANDATA.AI_INPUT_MESSAGES, messages) @@ -218,15 +216,17 @@ def _wrap_embeddings_create(f): # type: (Callable[..., Any]) -> Callable[..., Any] @wraps(f) - @ensure_integration_enabled(OpenAIIntegration, f) def new_embeddings_create(*args, **kwargs): # type: (*Any, **Any) -> Any + integration = sentry_sdk.get_client().get_integration(OpenAIIntegration) + if integration is None: + return f(*args, **kwargs) + with sentry_sdk.start_span( op=consts.OP.OPENAI_EMBEDDINGS_CREATE, name="OpenAI Embedding Creation", origin=OpenAIIntegration.origin, ) as span: - integration = sentry_sdk.get_client().get_integration(OpenAIIntegration) if "input" in kwargs and ( should_send_default_pii() and integration.include_prompts ): diff --git a/sentry_sdk/integrations/pyramid.py b/sentry_sdk/integrations/pyramid.py index 3ef7000343..d1475ada65 100644 --- a/sentry_sdk/integrations/pyramid.py +++ b/sentry_sdk/integrations/pyramid.py @@ -1,3 +1,4 @@ +import functools import os import sys import weakref @@ -73,10 +74,12 @@ def setup_once(): old_call_view = router._call_view - @ensure_integration_enabled(PyramidIntegration, old_call_view) + @functools.wraps(old_call_view) def sentry_patched_call_view(registry, request, *args, **kwargs): # type: (Any, Request, *Any, **Any) -> Response integration = sentry_sdk.get_client().get_integration(PyramidIntegration) + if integration is None: + return old_call_view(registry, request, *args, **kwargs) _set_transaction_name_and_source( sentry_sdk.get_current_scope(), integration.transaction_style, request diff --git a/sentry_sdk/integrations/sanic.py b/sentry_sdk/integrations/sanic.py index e2f24e5b6b..26e29cb78c 100644 --- a/sentry_sdk/integrations/sanic.py +++ b/sentry_sdk/integrations/sanic.py @@ -212,9 +212,7 @@ async def _context_exit(request, response=None): if not request.ctx._sentry_do_integration: return - integration = sentry_sdk.get_client().get_integration( - SanicIntegration - ) # type: Integration + integration = sentry_sdk.get_client().get_integration(SanicIntegration) response_status = None if response is None else response.status diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index 1179003561..fb18bc52e9 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -220,15 +220,16 @@ async def _sentry_patched_exception_handler(self, *args, **kwargs): exp = args[0] - is_http_server_error = ( - hasattr(exp, "status_code") - and isinstance(exp.status_code, int) - and _in_http_status_code_range( - exp.status_code, integration.failed_request_status_codes + if integration is not None: + is_http_server_error = ( + hasattr(exp, "status_code") + and isinstance(exp.status_code, int) + and _in_http_status_code_range( + exp.status_code, integration.failed_request_status_codes + ) ) - ) - if is_http_server_error: - _capture_exception(exp, handled=True) + if is_http_server_error: + _capture_exception(exp, handled=True) # Find a matching handler old_handler = None @@ -449,12 +450,15 @@ def event_processor(event, hint): else: - @ensure_integration_enabled(StarletteIntegration, old_func) + @functools.wraps(old_func) def _sentry_sync_func(*args, **kwargs): # type: (*Any, **Any) -> Any integration = sentry_sdk.get_client().get_integration( StarletteIntegration ) + if integration is None: + return old_func(*args, **kwargs) + sentry_scope = sentry_sdk.get_isolation_scope() if sentry_scope.profile is not None: diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index 521609d379..570d10ed07 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -1,3 +1,4 @@ +import functools import hashlib from inspect import isawaitable @@ -87,10 +88,13 @@ def _patch_schema_init(): # type: () -> None old_schema_init = Schema.__init__ - @ensure_integration_enabled(StrawberryIntegration, old_schema_init) + @functools.wraps(old_schema_init) def _sentry_patched_schema_init(self, *args, **kwargs): # type: (Schema, Any, Any) -> None integration = sentry_sdk.get_client().get_integration(StrawberryIntegration) + if integration is None: + return old_schema_init(self, *args, **kwargs) + extensions = kwargs.get("extensions") or [] if integration.async_execution is not None: diff --git a/sentry_sdk/integrations/sys_exit.py b/sentry_sdk/integrations/sys_exit.py index 39539b4c15..2341e11359 100644 --- a/sentry_sdk/integrations/sys_exit.py +++ b/sentry_sdk/integrations/sys_exit.py @@ -1,11 +1,8 @@ +import functools import sys import sentry_sdk -from sentry_sdk.utils import ( - ensure_integration_enabled, - capture_internal_exceptions, - event_from_exception, -) +from sentry_sdk.utils import capture_internal_exceptions, event_from_exception from sentry_sdk.integrations import Integration from sentry_sdk._types import TYPE_CHECKING @@ -41,13 +38,13 @@ def _patch_sys_exit(): # type: () -> None old_exit = sys.exit # type: Callable[[Union[str, int, None]], NoReturn] - @ensure_integration_enabled(SysExitIntegration, old_exit) + @functools.wraps(old_exit) def sentry_patched_exit(__status=0): # type: (Union[str, int, None]) -> NoReturn # @ensure_integration_enabled ensures that this is non-None - integration = sentry_sdk.get_client().get_integration( - SysExitIntegration - ) # type: SysExitIntegration + integration = sentry_sdk.get_client().get_integration(SysExitIntegration) + if integration is None: + old_exit(__status) try: old_exit(__status) @@ -60,7 +57,7 @@ def sentry_patched_exit(__status=0): _capture_exception(e) raise e - sys.exit = sentry_patched_exit # type: ignore + sys.exit = sentry_patched_exit def _capture_exception(exc): diff --git a/sentry_sdk/integrations/threading.py b/sentry_sdk/integrations/threading.py index c729e208a5..5de736e23b 100644 --- a/sentry_sdk/integrations/threading.py +++ b/sentry_sdk/integrations/threading.py @@ -6,7 +6,6 @@ from sentry_sdk.integrations import Integration from sentry_sdk.scope import use_isolation_scope, use_scope from sentry_sdk.utils import ( - ensure_integration_enabled, event_from_exception, capture_internal_exceptions, logger, @@ -51,10 +50,12 @@ def setup_once(): old_start = Thread.start @wraps(old_start) - @ensure_integration_enabled(ThreadingIntegration, old_start) def sentry_start(self, *a, **kw): # type: (Thread, *Any, **Any) -> Any integration = sentry_sdk.get_client().get_integration(ThreadingIntegration) + if integration is None: + return old_start(self, *a, **kw) + if integration.propagate_scope: isolation_scope = sentry_sdk.get_isolation_scope() current_scope = sentry_sdk.get_current_scope()