From 7b8cb2500b3471964d8380486ff80bf21bda8885 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Fri, 27 Jun 2025 16:07:25 +0200 Subject: [PATCH] Migrate typing for integrations - part 5 --- pyproject.toml | 3 + sentry_sdk/integrations/celery/__init__.py | 92 +++++-------- sentry_sdk/integrations/celery/beat.py | 48 +++---- sentry_sdk/integrations/celery/utils.py | 32 ++--- sentry_sdk/integrations/django/__init__.py | 129 ++++++++---------- sentry_sdk/integrations/django/asgi.py | 56 ++++---- sentry_sdk/integrations/django/caching.py | 42 +++--- sentry_sdk/integrations/django/middleware.py | 37 +++-- .../integrations/django/signals_handlers.py | 21 +-- sentry_sdk/integrations/django/templates.py | 35 ++--- .../integrations/django/transactions.py | 27 ++-- sentry_sdk/integrations/django/views.py | 16 +-- sentry_sdk/integrations/grpc/__init__.py | 5 +- sentry_sdk/integrations/grpc/client.py | 28 ++-- sentry_sdk/integrations/grpc/consts.py | 2 + sentry_sdk/integrations/grpc/server.py | 20 +-- sentry_sdk/integrations/redis/__init__.py | 11 +- .../integrations/redis/_async_common.py | 24 ++-- sentry_sdk/integrations/redis/_sync_common.py | 25 ++-- .../integrations/redis/modules/caches.py | 25 ++-- .../integrations/redis/modules/queries.py | 17 +-- sentry_sdk/integrations/redis/rb.py | 5 +- sentry_sdk/integrations/redis/redis.py | 8 +- .../integrations/redis/redis_cluster.py | 18 +-- .../redis/redis_py_cluster_legacy.py | 5 +- sentry_sdk/integrations/redis/utils.py | 43 +++--- sentry_sdk/integrations/spark/__init__.py | 1 + sentry_sdk/integrations/spark/spark_driver.py | 128 ++++++----------- sentry_sdk/integrations/spark/spark_worker.py | 18 +-- 29 files changed, 440 insertions(+), 481 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e5eae2c21f..d9993a099a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -214,3 +214,6 @@ exclude = [ "grpc_test_service_pb2.py", "grpc_test_service_pb2_grpc.py", ] +per-file-ignores = [ + "sentry_sdk/integrations/spark/*:N802,N803", +] diff --git a/sentry_sdk/integrations/celery/__init__.py b/sentry_sdk/integrations/celery/__init__.py index f078f629da..de9bb45422 100644 --- a/sentry_sdk/integrations/celery/__init__.py +++ b/sentry_sdk/integrations/celery/__init__.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sys from collections.abc import Mapping from functools import wraps @@ -62,11 +63,10 @@ class CeleryIntegration(Integration): def __init__( self, - propagate_traces=True, - monitor_beat_tasks=False, - exclude_beat_tasks=None, - ): - # type: (bool, bool, Optional[List[str]]) -> None + propagate_traces: bool = True, + monitor_beat_tasks: bool = False, + exclude_beat_tasks: Optional[List[str]] = None, + ) -> None: self.propagate_traces = propagate_traces self.monitor_beat_tasks = monitor_beat_tasks self.exclude_beat_tasks = exclude_beat_tasks @@ -76,8 +76,7 @@ def __init__( _setup_celery_beat_signals(monitor_beat_tasks) @staticmethod - def setup_once(): - # type: () -> None + def setup_once() -> None: _check_minimum_version(CeleryIntegration, CELERY_VERSION) _patch_build_tracer() @@ -97,16 +96,14 @@ def setup_once(): ignore_logger("celery.redirected") -def _set_status(status): - # type: (str) -> None +def _set_status(status: str) -> None: with capture_internal_exceptions(): span = sentry_sdk.get_current_span() if span is not None: span.set_status(status) -def _capture_exception(task, exc_info): - # type: (Any, ExcInfo) -> None +def _capture_exception(task: Any, exc_info: ExcInfo) -> None: client = sentry_sdk.get_client() if client.get_integration(CeleryIntegration) is None: return @@ -129,10 +126,10 @@ def _capture_exception(task, exc_info): sentry_sdk.capture_event(event, hint=hint) -def _make_event_processor(task, uuid, args, kwargs, request=None): - # type: (Any, Any, Any, Any, Optional[Any]) -> EventProcessor - def event_processor(event, hint): - # type: (Event, Hint) -> Optional[Event] +def _make_event_processor( + task: Any, uuid: Any, args: Any, kwargs: Any, request: Optional[Any] = None +) -> EventProcessor: + def event_processor(event: Event, hint: Hint) -> Optional[Event]: with capture_internal_exceptions(): tags = event.setdefault("tags", {}) @@ -158,8 +155,9 @@ def event_processor(event, hint): return event_processor -def _update_celery_task_headers(original_headers, span, monitor_beat_tasks): - # type: (dict[str, Any], Optional[Span], bool) -> dict[str, Any] +def _update_celery_task_headers( + original_headers: dict[str, Any], span: Optional[Span], monitor_beat_tasks: bool +) -> dict[str, Any]: """ Updates the headers of the Celery task with the tracing information and eventually Sentry Crons monitoring information for beat tasks. @@ -233,20 +231,16 @@ def _update_celery_task_headers(original_headers, span, monitor_beat_tasks): class NoOpMgr: - def __enter__(self): - # type: () -> None + def __enter__(self) -> None: return None - def __exit__(self, exc_type, exc_value, traceback): - # type: (Any, Any, Any) -> None + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: return None -def _wrap_task_run(f): - # type: (F) -> F +def _wrap_task_run(f: F) -> F: @wraps(f) - def apply_async(*args, **kwargs): - # type: (*Any, **Any) -> Any + def apply_async(*args: Any, **kwargs: Any) -> Any: # Note: kwargs can contain headers=None, so no setdefault! # Unsure which backend though. integration = sentry_sdk.get_client().get_integration(CeleryIntegration) @@ -262,7 +256,7 @@ def apply_async(*args, **kwargs): return f(*args, **kwargs) if isinstance(args[0], Task): - task_name = args[0].name # type: str + task_name: str = args[0].name elif len(args) > 1 and isinstance(args[1], str): task_name = args[1] else: @@ -270,7 +264,7 @@ def apply_async(*args, **kwargs): task_started_from_beat = sentry_sdk.get_isolation_scope()._name == "celery-beat" - span_mgr = ( + span_mgr: Union[Span, NoOpMgr] = ( sentry_sdk.start_span( op=OP.QUEUE_SUBMIT_CELERY, name=task_name, @@ -279,7 +273,7 @@ def apply_async(*args, **kwargs): ) if not task_started_from_beat else NoOpMgr() - ) # type: Union[Span, NoOpMgr] + ) with span_mgr as span: kwargs["headers"] = _update_celery_task_headers( @@ -290,8 +284,7 @@ def apply_async(*args, **kwargs): return apply_async # type: ignore -def _wrap_tracer(task, f): - # type: (Any, F) -> F +def _wrap_tracer(task: Any, f: F) -> F: # Need to wrap tracer for pushing the scope before prerun is sent, and # popping it after postrun is sent. @@ -301,8 +294,7 @@ def _wrap_tracer(task, f): # crashes. @wraps(f) @ensure_integration_enabled(CeleryIntegration, f) - def _inner(*args, **kwargs): - # type: (*Any, **Any) -> Any + def _inner(*args: Any, **kwargs: Any) -> Any: with isolation_scope() as scope: scope._name = "celery" scope.clear_breadcrumbs() @@ -333,8 +325,7 @@ def _inner(*args, **kwargs): return _inner # type: ignore -def _set_messaging_destination_name(task, span): - # type: (Any, Span) -> None +def _set_messaging_destination_name(task: Any, span: Span) -> None: """Set "messaging.destination.name" tag for span""" with capture_internal_exceptions(): delivery_info = task.request.delivery_info @@ -346,8 +337,7 @@ def _set_messaging_destination_name(task, span): span.set_attribute(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) -def _wrap_task_call(task, f): - # type: (Any, F) -> F +def _wrap_task_call(task: Any, f: F) -> F: # Need to wrap task call because the exception is caught before we get to # see it. Also celery's reported stacktrace is untrustworthy. @@ -358,8 +348,7 @@ def _wrap_task_call(task, f): # to add @functools.wraps(f) here. # https://github.com/getsentry/sentry-python/issues/421 @ensure_integration_enabled(CeleryIntegration, f) - def _inner(*args, **kwargs): - # type: (*Any, **Any) -> Any + def _inner(*args: Any, **kwargs: Any) -> Any: try: with sentry_sdk.start_span( op=OP.QUEUE_PROCESS, @@ -409,14 +398,12 @@ def _inner(*args, **kwargs): return _inner # type: ignore -def _patch_build_tracer(): - # type: () -> None +def _patch_build_tracer() -> None: import celery.app.trace as trace # type: ignore original_build_tracer = trace.build_tracer - def sentry_build_tracer(name, task, *args, **kwargs): - # type: (Any, Any, *Any, **Any) -> Any + def sentry_build_tracer(name: Any, task: Any, *args: Any, **kwargs: Any) -> Any: if not getattr(task, "_sentry_is_patched", False): # determine whether Celery will use __call__ or run and patch # accordingly @@ -435,20 +422,17 @@ def sentry_build_tracer(name, task, *args, **kwargs): trace.build_tracer = sentry_build_tracer -def _patch_task_apply_async(): - # type: () -> None +def _patch_task_apply_async() -> None: Task.apply_async = _wrap_task_run(Task.apply_async) -def _patch_celery_send_task(): - # type: () -> None +def _patch_celery_send_task() -> None: from celery import Celery Celery.send_task = _wrap_task_run(Celery.send_task) -def _patch_worker_exit(): - # type: () -> None +def _patch_worker_exit() -> None: # Need to flush queue before worker shutdown because a crashing worker will # call os._exit @@ -456,8 +440,7 @@ def _patch_worker_exit(): original_workloop = Worker.workloop - def sentry_workloop(*args, **kwargs): - # type: (*Any, **Any) -> Any + def sentry_workloop(*args: Any, **kwargs: Any) -> Any: try: return original_workloop(*args, **kwargs) finally: @@ -471,13 +454,11 @@ def sentry_workloop(*args, **kwargs): Worker.workloop = sentry_workloop -def _patch_producer_publish(): - # type: () -> None +def _patch_producer_publish() -> None: original_publish = Producer.publish @ensure_integration_enabled(CeleryIntegration, original_publish) - def sentry_publish(self, *args, **kwargs): - # type: (Producer, *Any, **Any) -> Any + def sentry_publish(self: Producer, *args: Any, **kwargs: Any) -> Any: kwargs_headers = kwargs.get("headers", {}) if not isinstance(kwargs_headers, Mapping): # Ensure kwargs_headers is a Mapping, so we can safely call get(). @@ -521,8 +502,7 @@ def sentry_publish(self, *args, **kwargs): Producer.publish = sentry_publish -def _prepopulate_attributes(task, args, kwargs): - # type: (Any, *Any, **Any) -> dict[str, str] +def _prepopulate_attributes(task: Any, args: Any, kwargs: Any) -> dict[str, str]: attributes = { "celery.job.task": task.name, } diff --git a/sentry_sdk/integrations/celery/beat.py b/sentry_sdk/integrations/celery/beat.py index 4b7e45e6f0..b0c28f7bc8 100644 --- a/sentry_sdk/integrations/celery/beat.py +++ b/sentry_sdk/integrations/celery/beat.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.crons import capture_checkin, MonitorStatus from sentry_sdk.integrations import DidNotEnable @@ -42,8 +43,7 @@ RedBeatScheduler = None -def _get_headers(task): - # type: (Task) -> dict[str, Any] +def _get_headers(task: Task) -> dict[str, Any]: headers = task.request.get("headers") or {} # flatten nested headers @@ -56,12 +56,13 @@ def _get_headers(task): return headers -def _get_monitor_config(celery_schedule, app, monitor_name): - # type: (Any, Celery, str) -> MonitorConfig - monitor_config = {} # type: MonitorConfig - schedule_type = None # type: Optional[MonitorConfigScheduleType] - schedule_value = None # type: Optional[Union[str, int]] - schedule_unit = None # type: Optional[MonitorConfigScheduleUnit] +def _get_monitor_config( + celery_schedule: Any, app: Celery, monitor_name: str +) -> MonitorConfig: + monitor_config: MonitorConfig = {} + schedule_type: Optional[MonitorConfigScheduleType] = None + schedule_value: Optional[Union[str, int]] = None + schedule_unit: Optional[MonitorConfigScheduleUnit] = None if isinstance(celery_schedule, crontab): schedule_type = "crontab" @@ -113,8 +114,11 @@ def _get_monitor_config(celery_schedule, app, monitor_name): return monitor_config -def _apply_crons_data_to_schedule_entry(scheduler, schedule_entry, integration): - # type: (Any, Any, sentry_sdk.integrations.celery.CeleryIntegration) -> None +def _apply_crons_data_to_schedule_entry( + scheduler: Any, + schedule_entry: Any, + integration: sentry_sdk.integrations.celery.CeleryIntegration, +) -> None: """ Add Sentry Crons information to the schedule_entry headers. """ @@ -158,8 +162,7 @@ def _apply_crons_data_to_schedule_entry(scheduler, schedule_entry, integration): schedule_entry.options["headers"] = headers -def _wrap_beat_scheduler(original_function): - # type: (Callable[..., Any]) -> Callable[..., Any] +def _wrap_beat_scheduler(original_function: Callable[..., Any]) -> Callable[..., Any]: """ Makes sure that: - a new Sentry trace is started for each task started by Celery Beat and @@ -178,8 +181,7 @@ def _wrap_beat_scheduler(original_function): from sentry_sdk.integrations.celery import CeleryIntegration - def sentry_patched_scheduler(*args, **kwargs): - # type: (*Any, **Any) -> None + def sentry_patched_scheduler(*args: Any, **kwargs: Any) -> None: integration = sentry_sdk.get_client().get_integration(CeleryIntegration) if integration is None: return original_function(*args, **kwargs) @@ -197,29 +199,25 @@ def sentry_patched_scheduler(*args, **kwargs): return sentry_patched_scheduler -def _patch_beat_apply_entry(): - # type: () -> None +def _patch_beat_apply_entry() -> None: Scheduler.apply_entry = _wrap_beat_scheduler(Scheduler.apply_entry) -def _patch_redbeat_apply_async(): - # type: () -> None +def _patch_redbeat_apply_async() -> None: if RedBeatScheduler is None: return RedBeatScheduler.apply_async = _wrap_beat_scheduler(RedBeatScheduler.apply_async) -def _setup_celery_beat_signals(monitor_beat_tasks): - # type: (bool) -> None +def _setup_celery_beat_signals(monitor_beat_tasks: bool) -> None: if monitor_beat_tasks: task_success.connect(crons_task_success) task_failure.connect(crons_task_failure) task_retry.connect(crons_task_retry) -def crons_task_success(sender, **kwargs): - # type: (Task, dict[Any, Any]) -> None +def crons_task_success(sender: Task, **kwargs: dict[Any, Any]) -> None: logger.debug("celery_task_success %s", sender) headers = _get_headers(sender) @@ -243,8 +241,7 @@ def crons_task_success(sender, **kwargs): ) -def crons_task_failure(sender, **kwargs): - # type: (Task, dict[Any, Any]) -> None +def crons_task_failure(sender: Task, **kwargs: dict[Any, Any]) -> None: logger.debug("celery_task_failure %s", sender) headers = _get_headers(sender) @@ -268,8 +265,7 @@ def crons_task_failure(sender, **kwargs): ) -def crons_task_retry(sender, **kwargs): - # type: (Task, dict[Any, Any]) -> None +def crons_task_retry(sender: Task, **kwargs: dict[Any, Any]) -> None: logger.debug("celery_task_retry %s", sender) headers = _get_headers(sender) diff --git a/sentry_sdk/integrations/celery/utils.py b/sentry_sdk/integrations/celery/utils.py index a1961b15bc..eb96cb9016 100644 --- a/sentry_sdk/integrations/celery/utils.py +++ b/sentry_sdk/integrations/celery/utils.py @@ -1,13 +1,20 @@ +from __future__ import annotations import time -from typing import TYPE_CHECKING, cast +from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Tuple + from typing import Any, Tuple, List from sentry_sdk._types import MonitorConfigScheduleUnit -def _now_seconds_since_epoch(): - # type: () -> float +TIME_UNITS: List[Tuple[MonitorConfigScheduleUnit, float]] = [ + ("day", 60 * 60 * 24.0), + ("hour", 60 * 60.0), + ("minute", 60.0), +] + + +def _now_seconds_since_epoch() -> float: # We cannot use `time.perf_counter()` when dealing with the duration # of a Celery task, because the start of a Celery task and # the end are recorded in different processes. @@ -16,28 +23,19 @@ def _now_seconds_since_epoch(): return time.time() -def _get_humanized_interval(seconds): - # type: (float) -> Tuple[int, MonitorConfigScheduleUnit] - TIME_UNITS = ( # noqa: N806 - ("day", 60 * 60 * 24.0), - ("hour", 60 * 60.0), - ("minute", 60.0), - ) - +def _get_humanized_interval(seconds: float) -> Tuple[int, MonitorConfigScheduleUnit]: seconds = float(seconds) for unit, divider in TIME_UNITS: if seconds >= divider: interval = int(seconds / divider) - return (interval, cast("MonitorConfigScheduleUnit", unit)) + return (interval, unit) return (int(seconds), "second") class NoOpMgr: - def __enter__(self): - # type: () -> None + def __enter__(self) -> None: return None - def __exit__(self, exc_type, exc_value, traceback): - # type: (Any, Any, Any) -> None + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: return None diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index e62ba63f70..14b42001c9 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -1,3 +1,4 @@ +from __future__ import annotations import functools import inspect import sys @@ -107,18 +108,17 @@ class DjangoIntegration(Integration): middleware_spans = None signals_spans = None cache_spans = None - signals_denylist = [] # type: list[signals.Signal] + signals_denylist: list[signals.Signal] = [] def __init__( self, - transaction_style="url", # type: str - middleware_spans=True, # type: bool - signals_spans=True, # type: bool - cache_spans=True, # type: bool - signals_denylist=None, # type: Optional[list[signals.Signal]] - http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: tuple[str, ...] - ): - # type: (...) -> None + transaction_style: str = "url", + middleware_spans: bool = True, + signals_spans: bool = True, + cache_spans: bool = True, + signals_denylist: Optional[list[signals.Signal]] = None, + http_methods_to_capture: tuple[str, ...] = DEFAULT_HTTP_METHODS_TO_CAPTURE, + ) -> None: if transaction_style not in TRANSACTION_STYLE_VALUES: raise ValueError( "Invalid value for transaction_style: %s (must be in %s)" @@ -135,8 +135,7 @@ def __init__( self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture)) @staticmethod - def setup_once(): - # type: () -> None + def setup_once() -> None: _check_minimum_version(DjangoIntegration, DJANGO_VERSION) install_sql_hook() @@ -151,8 +150,9 @@ def setup_once(): old_app = WSGIHandler.__call__ @ensure_integration_enabled(DjangoIntegration, old_app) - def sentry_patched_wsgi_handler(self, environ, start_response): - # type: (Any, Dict[str, str], Callable[..., Any]) -> _ScopedResponse + def sentry_patched_wsgi_handler( + self: Any, environ: Dict[str, str], start_response: Callable[..., Any] + ) -> _ScopedResponse: bound_old_app = old_app.__get__(self, WSGIHandler) from django.conf import settings @@ -182,8 +182,9 @@ def sentry_patched_wsgi_handler(self, environ, start_response): signals.got_request_exception.connect(_got_request_exception) @add_global_event_processor - def process_django_templates(event, hint): - # type: (Event, Optional[Hint]) -> Optional[Event] + def process_django_templates( + event: Event, hint: Optional[Hint] + ) -> Optional[Event]: if hint is None: return event @@ -225,8 +226,9 @@ def process_django_templates(event, hint): return event @add_global_repr_processor - def _django_queryset_repr(value, hint): - # type: (Any, Dict[str, Any]) -> Union[NotImplementedType, str] + def _django_queryset_repr( + value: Any, hint: Dict[str, Any] + ) -> Union[NotImplementedType, str]: try: # Django 1.6 can fail to import `QuerySet` when Django settings # have not yet been initialized. @@ -261,8 +263,7 @@ def _django_queryset_repr(value, hint): _DRF_PATCH_LOCK = threading.Lock() -def _patch_drf(): - # type: () -> None +def _patch_drf() -> None: """ Patch Django Rest Framework for more/better request data. DRF's request type is a wrapper around Django's request type. The attribute we're @@ -305,8 +306,9 @@ def _patch_drf(): old_drf_initial = APIView.initial @functools.wraps(old_drf_initial) - def sentry_patched_drf_initial(self, request, *args, **kwargs): - # type: (APIView, Any, *Any, **Any) -> Any + def sentry_patched_drf_initial( + self: APIView, request: Any, *args: Any, **kwargs: Any + ) -> Any: with capture_internal_exceptions(): request._request._sentry_drf_request_backref = weakref.ref( request @@ -317,8 +319,7 @@ def sentry_patched_drf_initial(self, request, *args, **kwargs): APIView.initial = sentry_patched_drf_initial -def _patch_channels(): - # type: () -> None +def _patch_channels() -> None: try: from channels.http import AsgiHandler # type: ignore except ImportError: @@ -342,8 +343,7 @@ def _patch_channels(): patch_channels_asgi_handler_impl(AsgiHandler) -def _patch_django_asgi_handler(): - # type: () -> None +def _patch_django_asgi_handler() -> None: try: from django.core.handlers.asgi import ASGIHandler except ImportError: @@ -364,8 +364,9 @@ def _patch_django_asgi_handler(): patch_django_asgi_handler_impl(ASGIHandler) -def _set_transaction_name_and_source(scope, transaction_style, request): - # type: (sentry_sdk.Scope, str, WSGIRequest) -> None +def _set_transaction_name_and_source( + scope: sentry_sdk.Scope, transaction_style: str, request: WSGIRequest +) -> None: try: transaction_name = None if transaction_style == "function_name": @@ -408,8 +409,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request): pass -def _before_get_response(request): - # type: (WSGIRequest) -> None +def _before_get_response(request: WSGIRequest) -> None: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None: return @@ -425,8 +425,9 @@ def _before_get_response(request): ) -def _attempt_resolve_again(request, scope, transaction_style): - # type: (WSGIRequest, sentry_sdk.Scope, str) -> None +def _attempt_resolve_again( + request: WSGIRequest, scope: sentry_sdk.Scope, transaction_style: str +) -> None: """ Some django middlewares overwrite request.urlconf so we need to respect that contract, @@ -438,8 +439,7 @@ def _attempt_resolve_again(request, scope, transaction_style): _set_transaction_name_and_source(scope, transaction_style, request) -def _after_get_response(request): - # type: (WSGIRequest) -> None +def _after_get_response(request: WSGIRequest) -> None: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None or integration.transaction_style != "url": return @@ -448,8 +448,7 @@ def _after_get_response(request): _attempt_resolve_again(request, scope, integration.transaction_style) -def _patch_get_response(): - # type: () -> None +def _patch_get_response() -> None: """ patch get_response, because at that point we have the Django request object """ @@ -458,8 +457,9 @@ def _patch_get_response(): old_get_response = BaseHandler.get_response @functools.wraps(old_get_response) - def sentry_patched_get_response(self, request): - # type: (Any, WSGIRequest) -> Union[HttpResponse, BaseException] + def sentry_patched_get_response( + self: Any, request: WSGIRequest + ) -> Union[HttpResponse, BaseException]: _before_get_response(request) rv = old_get_response(self, request) _after_get_response(request) @@ -473,10 +473,10 @@ def sentry_patched_get_response(self, request): patch_get_response_async(BaseHandler, _before_get_response) -def _make_wsgi_request_event_processor(weak_request, integration): - # type: (Callable[[], WSGIRequest], DjangoIntegration) -> EventProcessor - def wsgi_request_event_processor(event, hint): - # type: (Event, dict[str, Any]) -> Event +def _make_wsgi_request_event_processor( + weak_request: Callable[[], WSGIRequest], integration: DjangoIntegration +) -> EventProcessor: + def wsgi_request_event_processor(event: Event, hint: dict[str, Any]) -> Event: # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. @@ -501,8 +501,7 @@ def wsgi_request_event_processor(event, hint): return wsgi_request_event_processor -def _got_request_exception(request=None, **kwargs): - # type: (WSGIRequest, **Any) -> None +def _got_request_exception(request: WSGIRequest = None, **kwargs: Any) -> None: client = sentry_sdk.get_client() integration = client.get_integration(DjangoIntegration) if integration is None: @@ -521,8 +520,7 @@ def _got_request_exception(request=None, **kwargs): class DjangoRequestExtractor(RequestExtractor): - def __init__(self, request): - # type: (Union[WSGIRequest, ASGIRequest]) -> None + def __init__(self, request: Union[WSGIRequest, ASGIRequest]) -> None: try: drf_request = request._sentry_drf_request_backref() if drf_request is not None: @@ -531,18 +529,16 @@ def __init__(self, request): pass self.request = request - def env(self): - # type: () -> Dict[str, str] + def env(self) -> Dict[str, str]: return self.request.META - def cookies(self): - # type: () -> Dict[str, Union[str, AnnotatedValue]] + def cookies(self) -> Dict[str, Union[str, AnnotatedValue]]: privacy_cookies = [ django_settings.CSRF_COOKIE_NAME, django_settings.SESSION_COOKIE_NAME, ] - clean_cookies = {} # type: Dict[str, Union[str, AnnotatedValue]] + clean_cookies: Dict[str, Union[str, AnnotatedValue]] = {} for key, val in self.request.COOKIES.items(): if key in privacy_cookies: clean_cookies[key] = SENSITIVE_DATA_SUBSTITUTE @@ -551,32 +547,26 @@ def cookies(self): return clean_cookies - def raw_data(self): - # type: () -> bytes + def raw_data(self) -> bytes: return self.request.body - def form(self): - # type: () -> QueryDict + def form(self) -> QueryDict: return self.request.POST - def files(self): - # type: () -> MultiValueDict + def files(self) -> MultiValueDict: return self.request.FILES - def size_of_file(self, file): - # type: (Any) -> int + def size_of_file(self, file: Any) -> int: return file.size - def parsed_body(self): - # type: () -> Optional[Dict[str, Any]] + def parsed_body(self) -> Optional[Dict[str, Any]]: try: return self.request.data except Exception: return RequestExtractor.parsed_body(self) -def _set_user_info(request, event): - # type: (WSGIRequest, Event) -> None +def _set_user_info(request: WSGIRequest, event: Event) -> None: user_info = event.setdefault("user", {}) user = getattr(request, "user", None) @@ -600,8 +590,7 @@ def _set_user_info(request, event): pass -def install_sql_hook(): - # type: () -> None +def install_sql_hook() -> None: """If installed this causes Django's queries to be captured.""" try: from django.db.backends.utils import CursorWrapper @@ -615,8 +604,7 @@ def install_sql_hook(): real_connect = BaseDatabaseWrapper.connect @ensure_integration_enabled(DjangoIntegration, real_execute) - def execute(self, sql, params=None): - # type: (CursorWrapper, Any, Optional[Any]) -> Any + def execute(self: CursorWrapper, sql: Any, params: Optional[Any] = None) -> Any: with record_sql_queries( cursor=self.cursor, query=sql, @@ -634,8 +622,7 @@ def execute(self, sql, params=None): return result @ensure_integration_enabled(DjangoIntegration, real_executemany) - def executemany(self, sql, param_list): - # type: (CursorWrapper, Any, List[Any]) -> Any + def executemany(self: CursorWrapper, sql: Any, param_list: List[Any]) -> Any: with record_sql_queries( cursor=self.cursor, query=sql, @@ -654,8 +641,7 @@ def executemany(self, sql, param_list): return result @ensure_integration_enabled(DjangoIntegration, real_connect) - def connect(self): - # type: (BaseDatabaseWrapper) -> None + def connect(self: BaseDatabaseWrapper) -> None: with capture_internal_exceptions(): sentry_sdk.add_breadcrumb(message="connect", category="query") @@ -674,8 +660,7 @@ def connect(self): ignore_logger("django.db.backends") -def _set_db_data(span, cursor_or_db): - # type: (Span, Any) -> None +def _set_db_data(span: Span, cursor_or_db: Any) -> None: db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db vendor = db.vendor span.set_attribute(SPANDATA.DB_SYSTEM, vendor) diff --git a/sentry_sdk/integrations/django/asgi.py b/sentry_sdk/integrations/django/asgi.py index d37503d16d..1435fefa04 100644 --- a/sentry_sdk/integrations/django/asgi.py +++ b/sentry_sdk/integrations/django/asgi.py @@ -1,3 +1,5 @@ +from __future__ import annotations + """ Instrumentation for Django 3.0 @@ -51,10 +53,8 @@ def markcoroutinefunction(func: "_F") -> "_F": return func -def _make_asgi_request_event_processor(request): - # type: (ASGIRequest) -> EventProcessor - def asgi_request_event_processor(event, hint): - # type: (Event, dict[str, Any]) -> Event +def _make_asgi_request_event_processor(request: ASGIRequest) -> EventProcessor: + def asgi_request_event_processor(event: Event, hint: dict[str, Any]) -> Event: # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. @@ -81,16 +81,16 @@ def asgi_request_event_processor(event, hint): return asgi_request_event_processor -def patch_django_asgi_handler_impl(cls): - # type: (Any) -> None +def patch_django_asgi_handler_impl(cls: Any) -> None: from sentry_sdk.integrations.django import DjangoIntegration old_app = cls.__call__ @functools.wraps(old_app) - async def sentry_patched_asgi_handler(self, scope, receive, send): - # type: (Any, Any, Any, Any) -> Any + async def sentry_patched_asgi_handler( + self: Any, scope: Any, receive: Any, send: Any + ) -> Any: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None: return await old_app(self, scope, receive, send) @@ -111,8 +111,7 @@ async def sentry_patched_asgi_handler(self, scope, receive, send): old_create_request = cls.create_request @ensure_integration_enabled(DjangoIntegration, old_create_request) - def sentry_patched_create_request(self, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + def sentry_patched_create_request(self: Any, *args: Any, **kwargs: Any) -> Any: request, error_response = old_create_request(self, *args, **kwargs) scope = sentry_sdk.get_isolation_scope() scope.add_event_processor(_make_asgi_request_event_processor(request)) @@ -122,21 +121,20 @@ def sentry_patched_create_request(self, *args, **kwargs): cls.create_request = sentry_patched_create_request -def patch_get_response_async(cls, _before_get_response): - # type: (Any, Any) -> None +def patch_get_response_async(cls: Any, _before_get_response: Any) -> None: old_get_response_async = cls.get_response_async @functools.wraps(old_get_response_async) - async def sentry_patched_get_response_async(self, request): - # type: (Any, Any) -> Union[HttpResponse, BaseException] + async def sentry_patched_get_response_async( + self: Any, request: Any + ) -> Union[HttpResponse, BaseException]: _before_get_response(request) return await old_get_response_async(self, request) cls.get_response_async = sentry_patched_get_response_async -def patch_channels_asgi_handler_impl(cls): - # type: (Any) -> None +def patch_channels_asgi_handler_impl(cls: Any) -> None: import channels # type: ignore from sentry_sdk.integrations.django import DjangoIntegration @@ -145,8 +143,9 @@ def patch_channels_asgi_handler_impl(cls): old_app = cls.__call__ @functools.wraps(old_app) - async def sentry_patched_asgi_handler(self, receive, send): - # type: (Any, Any, Any) -> Any + async def sentry_patched_asgi_handler( + self: Any, receive: Any, send: Any + ) -> Any: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None: return await old_app(self, receive, send) @@ -168,13 +167,11 @@ async def sentry_patched_asgi_handler(self, receive, send): patch_django_asgi_handler_impl(cls) -def wrap_async_view(callback): - # type: (Any) -> Any +def wrap_async_view(callback: Any) -> Any: from sentry_sdk.integrations.django import DjangoIntegration @functools.wraps(callback) - async def sentry_wrapped_callback(request, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + async def sentry_wrapped_callback(request: Any, *args: Any, **kwargs: Any) -> Any: current_scope = sentry_sdk.get_current_scope() if current_scope.root_span is not None: current_scope.root_span.update_active_thread() @@ -194,8 +191,7 @@ async def sentry_wrapped_callback(request, *args, **kwargs): return sentry_wrapped_callback -def _asgi_middleware_mixin_factory(_check_middleware_span): - # type: (Callable[..., Any]) -> Any +def _asgi_middleware_mixin_factory(_check_middleware_span: Callable[..., Any]) -> Any: """ Mixin class factory that generates a middleware mixin for handling requests in async mode. @@ -205,14 +201,12 @@ class SentryASGIMixin: if TYPE_CHECKING: _inner = None - def __init__(self, get_response): - # type: (Callable[..., Any]) -> None + def __init__(self, get_response: Callable[..., Any]) -> None: self.get_response = get_response self._acall_method = None self._async_check() - def _async_check(self): - # type: () -> None + def _async_check(self) -> None: """ If get_response is a coroutine function, turns us into async mode so a thread is not consumed during a whole request. @@ -221,16 +215,14 @@ def _async_check(self): if iscoroutinefunction(self.get_response): markcoroutinefunction(self) - def async_route_check(self): - # type: () -> bool + def async_route_check(self) -> bool: """ Function that checks if we are in async mode, and if we are forwards the handling of requests to __acall__ """ return iscoroutinefunction(self.get_response) - async def __acall__(self, *args, **kwargs): - # type: (*Any, **Any) -> Any + async def __acall__(self, *args: Any, **kwargs: Any) -> Any: f = self._acall_method if f is None: if hasattr(self._inner, "__acall__"): diff --git a/sentry_sdk/integrations/django/caching.py b/sentry_sdk/integrations/django/caching.py index 65bf2674e1..021ed398f7 100644 --- a/sentry_sdk/integrations/django/caching.py +++ b/sentry_sdk/integrations/django/caching.py @@ -1,3 +1,4 @@ +from __future__ import annotations import functools from typing import TYPE_CHECKING from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string @@ -28,22 +29,29 @@ ] -def _get_span_description(method_name, args, kwargs): - # type: (str, tuple[Any], dict[str, Any]) -> str +def _get_span_description( + method_name: str, args: tuple[Any], kwargs: dict[str, Any] +) -> str: return _key_as_string(_get_safe_key(method_name, args, kwargs)) -def _patch_cache_method(cache, method_name, address, port): - # type: (CacheHandler, str, Optional[str], Optional[int]) -> None +def _patch_cache_method( + cache: CacheHandler, method_name: str, address: Optional[str], port: Optional[int] +) -> None: from sentry_sdk.integrations.django import DjangoIntegration original_method = getattr(cache, method_name) @ensure_integration_enabled(DjangoIntegration, original_method) def _instrument_call( - cache, method_name, original_method, args, kwargs, address, port - ): - # type: (CacheHandler, str, Callable[..., Any], tuple[Any, ...], dict[str, Any], Optional[str], Optional[int]) -> Any + cache: CacheHandler, + method_name: str, + original_method: Callable[..., Any], + args: tuple[Any, ...], + kwargs: dict[str, Any], + address: Optional[str], + port: Optional[int], + ) -> Any: is_set_operation = method_name.startswith("set") is_get_operation = not is_set_operation @@ -91,8 +99,7 @@ def _instrument_call( return value @functools.wraps(original_method) - def sentry_method(*args, **kwargs): - # type: (*Any, **Any) -> Any + def sentry_method(*args: Any, **kwargs: Any) -> Any: return _instrument_call( cache, method_name, original_method, args, kwargs, address, port ) @@ -100,16 +107,16 @@ def sentry_method(*args, **kwargs): setattr(cache, method_name, sentry_method) -def _patch_cache(cache, address=None, port=None): - # type: (CacheHandler, Optional[str], Optional[int]) -> None +def _patch_cache( + cache: CacheHandler, address: Optional[str] = None, port: Optional[int] = None +) -> None: if not hasattr(cache, "_sentry_patched"): for method_name in METHODS_TO_INSTRUMENT: _patch_cache_method(cache, method_name, address, port) cache._sentry_patched = True -def _get_address_port(settings): - # type: (dict[str, Any]) -> tuple[Optional[str], Optional[int]] +def _get_address_port(settings: dict[str, Any]) -> tuple[Optional[str], Optional[int]]: location = settings.get("LOCATION") # TODO: location can also be an array of locations @@ -134,8 +141,7 @@ def _get_address_port(settings): return address, int(port) if port is not None else None -def patch_caching(): - # type: () -> None +def patch_caching() -> None: from sentry_sdk.integrations.django import DjangoIntegration if not hasattr(CacheHandler, "_sentry_patched"): @@ -143,8 +149,7 @@ def patch_caching(): original_get_item = CacheHandler.__getitem__ @functools.wraps(original_get_item) - def sentry_get_item(self, alias): - # type: (CacheHandler, str) -> Any + def sentry_get_item(self: CacheHandler, alias: str) -> Any: cache = original_get_item(self, alias) integration = sentry_sdk.get_client().get_integration(DjangoIntegration) @@ -166,8 +171,7 @@ def sentry_get_item(self, alias): original_create_connection = CacheHandler.create_connection @functools.wraps(original_create_connection) - def sentry_create_connection(self, alias): - # type: (CacheHandler, str) -> Any + def sentry_create_connection(self: CacheHandler, alias: str) -> Any: cache = original_create_connection(self, alias) integration = sentry_sdk.get_client().get_integration(DjangoIntegration) diff --git a/sentry_sdk/integrations/django/middleware.py b/sentry_sdk/integrations/django/middleware.py index 6640ac2919..bb16cc890a 100644 --- a/sentry_sdk/integrations/django/middleware.py +++ b/sentry_sdk/integrations/django/middleware.py @@ -1,3 +1,5 @@ +from __future__ import annotations + """ Create spans from Django middleware invocations """ @@ -38,14 +40,12 @@ from .asgi import _asgi_middleware_mixin_factory -def patch_django_middlewares(): - # type: () -> None +def patch_django_middlewares() -> None: from django.core.handlers import base old_import_string = base.import_string - def sentry_patched_import_string(dotted_path): - # type: (str) -> Any + def sentry_patched_import_string(dotted_path: str) -> Any: rv = old_import_string(dotted_path) if _import_string_should_wrap_middleware.get(None): @@ -57,8 +57,7 @@ def sentry_patched_import_string(dotted_path): old_load_middleware = base.BaseHandler.load_middleware - def sentry_patched_load_middleware(*args, **kwargs): - # type: (Any, Any) -> Any + def sentry_patched_load_middleware(*args: Any, **kwargs: Any) -> Any: _import_string_should_wrap_middleware.set(True) try: return old_load_middleware(*args, **kwargs) @@ -68,12 +67,10 @@ def sentry_patched_load_middleware(*args, **kwargs): base.BaseHandler.load_middleware = sentry_patched_load_middleware -def _wrap_middleware(middleware, middleware_name): - # type: (Any, str) -> Any +def _wrap_middleware(middleware: Any, middleware_name: str) -> Any: from sentry_sdk.integrations.django import DjangoIntegration - def _check_middleware_span(old_method): - # type: (Callable[..., Any]) -> Optional[Span] + def _check_middleware_span(old_method: Callable[..., Any]) -> Optional[Span]: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None or not integration.middleware_spans: return None @@ -96,12 +93,10 @@ def _check_middleware_span(old_method): return middleware_span - def _get_wrapped_method(old_method): - # type: (F) -> F + def _get_wrapped_method(old_method: F) -> F: with capture_internal_exceptions(): - def sentry_wrapped_method(*args, **kwargs): - # type: (*Any, **Any) -> Any + def sentry_wrapped_method(*args: Any, **kwargs: Any) -> Any: middleware_span = _check_middleware_span(old_method) if middleware_span is None: @@ -131,8 +126,12 @@ class SentryWrappingMiddleware( middleware, "async_capable", False ) - def __init__(self, get_response=None, *args, **kwargs): - # type: (Optional[Callable[..., Any]], *Any, **Any) -> None + def __init__( + self, + get_response: Optional[Callable[..., Any]] = None, + *args: Any, + **kwargs: Any, + ) -> None: if get_response: self._inner = middleware(get_response, *args, **kwargs) else: @@ -144,8 +143,7 @@ def __init__(self, get_response=None, *args, **kwargs): # We need correct behavior for `hasattr()`, which we can only determine # when we have an instance of the middleware we're wrapping. - def __getattr__(self, method_name): - # type: (str) -> Any + def __getattr__(self, method_name: str) -> Any: if method_name not in ( "process_request", "process_view", @@ -160,8 +158,7 @@ def __getattr__(self, method_name): self.__dict__[method_name] = rv return rv - def __call__(self, *args, **kwargs): - # type: (*Any, **Any) -> Any + def __call__(self, *args: Any, **kwargs: Any) -> Any: if hasattr(self, "async_route_check") and self.async_route_check(): return self.__acall__(*args, **kwargs) diff --git a/sentry_sdk/integrations/django/signals_handlers.py b/sentry_sdk/integrations/django/signals_handlers.py index 6e398ddfc3..23c821c65b 100644 --- a/sentry_sdk/integrations/django/signals_handlers.py +++ b/sentry_sdk/integrations/django/signals_handlers.py @@ -1,3 +1,4 @@ +from __future__ import annotations from functools import wraps from django.dispatch import Signal @@ -13,8 +14,7 @@ from typing import Any, Union -def _get_receiver_name(receiver): - # type: (Callable[..., Any]) -> str +def _get_receiver_name(receiver: Callable[..., Any]) -> str: name = "" if hasattr(receiver, "__qualname__"): @@ -38,8 +38,7 @@ def _get_receiver_name(receiver): return name -def patch_signals(): - # type: () -> None +def patch_signals() -> None: """ Patch django signal receivers to create a span. @@ -51,19 +50,21 @@ def patch_signals(): old_live_receivers = Signal._live_receivers @wraps(old_live_receivers) - def _sentry_live_receivers(self, sender): - # type: (Signal, Any) -> Union[tuple[list[Callable[..., Any]], list[Callable[..., Any]]], list[Callable[..., Any]]] + def _sentry_live_receivers(self: Signal, sender: Any) -> Union[ + tuple[list[Callable[..., Any]], list[Callable[..., Any]]], + list[Callable[..., Any]], + ]: if DJANGO_VERSION >= (5, 0): sync_receivers, async_receivers = old_live_receivers(self, sender) else: sync_receivers = old_live_receivers(self, sender) async_receivers = [] - def sentry_sync_receiver_wrapper(receiver): - # type: (Callable[..., Any]) -> Callable[..., Any] + def sentry_sync_receiver_wrapper( + receiver: Callable[..., Any], + ) -> Callable[..., Any]: @wraps(receiver) - def wrapper(*args, **kwargs): - # type: (Any, Any) -> Any + def wrapper(*args: Any, **kwargs: Any) -> Any: signal_name = _get_receiver_name(receiver) with sentry_sdk.start_span( op=OP.EVENT_DJANGO, diff --git a/sentry_sdk/integrations/django/templates.py b/sentry_sdk/integrations/django/templates.py index fd6e56b515..8299afa92f 100644 --- a/sentry_sdk/integrations/django/templates.py +++ b/sentry_sdk/integrations/django/templates.py @@ -1,3 +1,4 @@ +from __future__ import annotations import functools from django.template import TemplateSyntaxError @@ -18,8 +19,9 @@ from typing import Tuple -def get_template_frame_from_exception(exc_value): - # type: (Optional[BaseException]) -> Optional[Dict[str, Any]] +def get_template_frame_from_exception( + exc_value: Optional[BaseException], +) -> Optional[Dict[str, Any]]: # As of Django 1.9 or so the new template debug thing showed up. if hasattr(exc_value, "template_debug"): @@ -41,8 +43,7 @@ def get_template_frame_from_exception(exc_value): return None -def _get_template_name_description(template_name): - # type: (str) -> str +def _get_template_name_description(template_name: str) -> str: if isinstance(template_name, (list, tuple)): if template_name: return "[{}, ...]".format(template_name[0]) @@ -50,8 +51,7 @@ def _get_template_name_description(template_name): return template_name -def patch_templates(): - # type: () -> None +def patch_templates() -> None: from django.template.response import SimpleTemplateResponse from sentry_sdk.integrations.django import DjangoIntegration @@ -59,8 +59,7 @@ def patch_templates(): @property # type: ignore @ensure_integration_enabled(DjangoIntegration, real_rendered_content.fget) - def rendered_content(self): - # type: (SimpleTemplateResponse) -> str + def rendered_content(self: SimpleTemplateResponse) -> str: with sentry_sdk.start_span( op=OP.TEMPLATE_RENDER, name=_get_template_name_description(self.template_name), @@ -80,8 +79,13 @@ def rendered_content(self): @functools.wraps(real_render) @ensure_integration_enabled(DjangoIntegration, real_render) - def render(request, template_name, context=None, *args, **kwargs): - # type: (django.http.HttpRequest, str, Optional[Dict[str, Any]], *Any, **Any) -> django.http.HttpResponse + def render( + request: django.http.HttpRequest, + template_name: str, + context: Optional[Dict[str, Any]] = None, + *args: Any, + **kwargs: Any, + ) -> django.http.HttpResponse: # Inject trace meta tags into template context context = context or {} @@ -103,8 +107,7 @@ def render(request, template_name, context=None, *args, **kwargs): django.shortcuts.render = render -def _get_template_frame_from_debug(debug): - # type: (Dict[str, Any]) -> Dict[str, Any] +def _get_template_frame_from_debug(debug: Dict[str, Any]) -> Dict[str, Any]: if debug is None: return None @@ -135,8 +138,7 @@ def _get_template_frame_from_debug(debug): } -def _linebreak_iter(template_source): - # type: (str) -> Iterator[int] +def _linebreak_iter(template_source: str) -> Iterator[int]: yield 0 p = template_source.find("\n") while p >= 0: @@ -144,8 +146,9 @@ def _linebreak_iter(template_source): p = template_source.find("\n", p + 1) -def _get_template_frame_from_source(source): - # type: (Tuple[Origin, Tuple[int, int]]) -> Optional[Dict[str, Any]] +def _get_template_frame_from_source( + source: Tuple[Origin, Tuple[int, int]], +) -> Optional[Dict[str, Any]]: if not source: return None diff --git a/sentry_sdk/integrations/django/transactions.py b/sentry_sdk/integrations/django/transactions.py index 78b972bc37..3fe81f2029 100644 --- a/sentry_sdk/integrations/django/transactions.py +++ b/sentry_sdk/integrations/django/transactions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + """ Copied from raven-python. @@ -27,8 +29,7 @@ from django.core.urlresolvers import get_resolver -def get_regex(resolver_or_pattern): - # type: (Union[URLPattern, URLResolver]) -> Pattern[str] +def get_regex(resolver_or_pattern: Union[URLPattern, URLResolver]) -> Pattern[str]: """Utility method for django's deprecated resolver.regex""" try: regex = resolver_or_pattern.regex @@ -48,10 +49,9 @@ class RavenResolver: _either_option_matcher = re.compile(r"\[([^\]]+)\|([^\]]+)\]") _camel_re = re.compile(r"([A-Z]+)([a-z])") - _cache = {} # type: Dict[URLPattern, str] + _cache: Dict[URLPattern, str] = {} - def _simplify(self, pattern): - # type: (Union[URLPattern, URLResolver]) -> str + def _simplify(self, pattern: Union[URLPattern, URLResolver]) -> str: r""" Clean up urlpattern regexes into something readable by humans: @@ -102,8 +102,12 @@ def _simplify(self, pattern): return result - def _resolve(self, resolver, path, parents=None): - # type: (URLResolver, str, Optional[List[URLResolver]]) -> Optional[str] + def _resolve( + self, + resolver: URLResolver, + path: str, + parents: Optional[List[URLResolver]] = None, + ) -> Optional[str]: match = get_regex(resolver).search(path) # Django < 2.0 @@ -142,10 +146,11 @@ def _resolve(self, resolver, path, parents=None): def resolve( self, - path, # type: str - urlconf=None, # type: Union[None, Tuple[URLPattern, URLPattern, URLResolver], Tuple[URLPattern]] - ): - # type: (...) -> Optional[str] + path: str, + urlconf: Union[ + None, Tuple[URLPattern, URLPattern, URLResolver], Tuple[URLPattern] + ] = None, + ) -> Optional[str]: resolver = get_resolver(urlconf) match = self._resolve(resolver, path) return match diff --git a/sentry_sdk/integrations/django/views.py b/sentry_sdk/integrations/django/views.py index 6240ac6bbb..4cc5a90cfc 100644 --- a/sentry_sdk/integrations/django/views.py +++ b/sentry_sdk/integrations/django/views.py @@ -1,3 +1,4 @@ +from __future__ import annotations import functools import sentry_sdk @@ -21,8 +22,7 @@ wrap_async_view = None # type: ignore -def patch_views(): - # type: () -> None +def patch_views() -> None: from django.core.handlers.base import BaseHandler from django.template.response import SimpleTemplateResponse @@ -32,8 +32,7 @@ def patch_views(): old_render = SimpleTemplateResponse.render @functools.wraps(old_render) - def sentry_patched_render(self): - # type: (SimpleTemplateResponse) -> Any + def sentry_patched_render(self: SimpleTemplateResponse) -> Any: with sentry_sdk.start_span( op=OP.VIEW_RESPONSE_RENDER, name="serialize response", @@ -43,8 +42,7 @@ def sentry_patched_render(self): return old_render(self) @functools.wraps(old_make_view_atomic) - def sentry_patched_make_view_atomic(self, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + def sentry_patched_make_view_atomic(self: Any, *args: Any, **kwargs: Any) -> Any: callback = old_make_view_atomic(self, *args, **kwargs) # XXX: The wrapper function is created for every request. Find more @@ -71,13 +69,11 @@ def sentry_patched_make_view_atomic(self, *args, **kwargs): BaseHandler.make_view_atomic = sentry_patched_make_view_atomic -def _wrap_sync_view(callback): - # type: (Any) -> Any +def _wrap_sync_view(callback: Any) -> Any: from sentry_sdk.integrations.django import DjangoIntegration @functools.wraps(callback) - def sentry_wrapped_callback(request, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + def sentry_wrapped_callback(request: Any, *args: Any, **kwargs: Any) -> Any: current_scope = sentry_sdk.get_current_scope() if current_scope.root_span is not None: current_scope.root_span.update_active_thread() diff --git a/sentry_sdk/integrations/grpc/__init__.py b/sentry_sdk/integrations/grpc/__init__.py index 4e15f95ae5..29f6100a50 100644 --- a/sentry_sdk/integrations/grpc/__init__.py +++ b/sentry_sdk/integrations/grpc/__init__.py @@ -1,3 +1,4 @@ +from __future__ import annotations from functools import wraps import grpc @@ -130,10 +131,10 @@ def patched_aio_server( # type: ignore **kwargs: P.kwargs, ) -> Server: server_interceptor = AsyncServerInterceptor() - interceptors = [ + interceptors: Sequence[grpc.ServerInterceptor] = [ server_interceptor, *(interceptors or []), - ] # type: Sequence[grpc.ServerInterceptor] + ] try: # We prefer interceptors as a list because of compatibility with diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index b7a1ddd85e..a3c434bd56 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable @@ -23,8 +24,12 @@ class ClientInterceptor( ): _is_intercepted = False - def intercept_unary_unary(self, continuation, client_call_details, request): - # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], _UnaryOutcome], ClientCallDetails, Message) -> _UnaryOutcome + def intercept_unary_unary( + self: ClientInterceptor, + continuation: Callable[[ClientCallDetails, Message], _UnaryOutcome], + client_call_details: ClientCallDetails, + request: Message, + ) -> _UnaryOutcome: method = client_call_details.method with sentry_sdk.start_span( @@ -45,8 +50,14 @@ def intercept_unary_unary(self, continuation, client_call_details, request): return response - def intercept_unary_stream(self, continuation, client_call_details, request): - # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], Union[Iterable[Any], UnaryStreamCall]], ClientCallDetails, Message) -> Union[Iterator[Message], Call] + def intercept_unary_stream( + self: ClientInterceptor, + continuation: Callable[ + [ClientCallDetails, Message], Union[Iterable[Any], UnaryStreamCall] + ], + client_call_details: ClientCallDetails, + request: Message, + ) -> Union[Iterator[Message], Call]: method = client_call_details.method with sentry_sdk.start_span( @@ -62,17 +73,16 @@ def intercept_unary_stream(self, continuation, client_call_details, request): client_call_details ) - response = continuation( - client_call_details, request - ) # type: UnaryStreamCall + response: UnaryStreamCall = continuation(client_call_details, request) # Setting code on unary-stream leads to execution getting stuck # span.set_attribute("code", response.code().name) return response @staticmethod - def _update_client_call_details_metadata_from_scope(client_call_details): - # type: (ClientCallDetails) -> ClientCallDetails + def _update_client_call_details_metadata_from_scope( + client_call_details: ClientCallDetails, + ) -> ClientCallDetails: metadata = ( list(client_call_details.metadata) if client_call_details.metadata else [] ) diff --git a/sentry_sdk/integrations/grpc/consts.py b/sentry_sdk/integrations/grpc/consts.py index 9fdb975caf..6ee9ed49ca 100644 --- a/sentry_sdk/integrations/grpc/consts.py +++ b/sentry_sdk/integrations/grpc/consts.py @@ -1 +1,3 @@ +from __future__ import annotations + SPAN_ORIGIN = "auto.grpc.grpc" diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index 582ef6e24a..2407bfecbe 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable @@ -18,20 +19,24 @@ class ServerInterceptor(grpc.ServerInterceptor): # type: ignore - def __init__(self, find_name=None): - # type: (ServerInterceptor, Optional[Callable[[ServicerContext], str]]) -> None + def __init__( + self: ServerInterceptor, + find_name: Optional[Callable[[ServicerContext], str]] = None, + ) -> None: self._find_method_name = find_name or ServerInterceptor._find_name super().__init__() - def intercept_service(self, continuation, handler_call_details): - # type: (ServerInterceptor, Callable[[HandlerCallDetails], RpcMethodHandler], HandlerCallDetails) -> RpcMethodHandler + def intercept_service( + self: ServerInterceptor, + continuation: Callable[[HandlerCallDetails], RpcMethodHandler], + handler_call_details: HandlerCallDetails, + ) -> RpcMethodHandler: handler = continuation(handler_call_details) if not handler or not handler.unary_unary: return handler - def behavior(request, context): - # type: (Message, ServicerContext) -> Message + def behavior(request: Message, context: ServicerContext) -> Message: with sentry_sdk.isolation_scope(): name = self._find_method_name(context) @@ -59,6 +64,5 @@ def behavior(request, context): ) @staticmethod - def _find_name(context): - # type: (ServicerContext) -> str + def _find_name(context: ServicerContext) -> str: return context._rpc_event.call_details.method.decode() diff --git a/sentry_sdk/integrations/redis/__init__.py b/sentry_sdk/integrations/redis/__init__.py index f443138295..1d0b39f1cb 100644 --- a/sentry_sdk/integrations/redis/__init__.py +++ b/sentry_sdk/integrations/redis/__init__.py @@ -1,3 +1,4 @@ +from __future__ import annotations from sentry_sdk.integrations import Integration, DidNotEnable from sentry_sdk.integrations.redis.consts import _DEFAULT_MAX_DATA_SIZE from sentry_sdk.integrations.redis.rb import _patch_rb @@ -15,14 +16,16 @@ class RedisIntegration(Integration): identifier = "redis" - def __init__(self, max_data_size=_DEFAULT_MAX_DATA_SIZE, cache_prefixes=None): - # type: (int, Optional[list[str]]) -> None + def __init__( + self, + max_data_size: int = _DEFAULT_MAX_DATA_SIZE, + cache_prefixes: Optional[list[str]] = None, + ) -> None: self.max_data_size = max_data_size self.cache_prefixes = cache_prefixes if cache_prefixes is not None else [] @staticmethod - def setup_once(): - # type: () -> None + def setup_once() -> None: try: from redis import StrictRedis, client except ImportError: diff --git a/sentry_sdk/integrations/redis/_async_common.py b/sentry_sdk/integrations/redis/_async_common.py index c3e23f8a99..ca23db3939 100644 --- a/sentry_sdk/integrations/redis/_async_common.py +++ b/sentry_sdk/integrations/redis/_async_common.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations.redis.consts import SPAN_ORIGIN @@ -24,15 +25,16 @@ def patch_redis_async_pipeline( - pipeline_cls, is_cluster, get_command_args_fn, get_db_data_fn -): - # type: (Union[type[Pipeline[Any]], type[ClusterPipeline[Any]]], bool, Any, Callable[[Any], dict[str, Any]]) -> None + pipeline_cls: Union[type[Pipeline[Any]], type[ClusterPipeline[Any]]], + is_cluster: bool, + get_command_args_fn: Any, + get_db_data_fn: Callable[[Any], dict[str, Any]], +) -> None: old_execute = pipeline_cls.execute from sentry_sdk.integrations.redis import RedisIntegration - async def _sentry_execute(self, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + async def _sentry_execute(self: Any, *args: Any, **kwargs: Any) -> Any: if sentry_sdk.get_client().get_integration(RedisIntegration) is None: return await old_execute(self, *args, **kwargs) @@ -67,14 +69,18 @@ async def _sentry_execute(self, *args, **kwargs): pipeline_cls.execute = _sentry_execute # type: ignore -def patch_redis_async_client(cls, is_cluster, get_db_data_fn): - # type: (Union[type[StrictRedis[Any]], type[RedisCluster[Any]]], bool, Callable[[Any], dict[str, Any]]) -> None +def patch_redis_async_client( + cls: Union[type[StrictRedis[Any]], type[RedisCluster[Any]]], + is_cluster: bool, + get_db_data_fn: Callable[[Any], dict[str, Any]], +) -> None: old_execute_command = cls.execute_command from sentry_sdk.integrations.redis import RedisIntegration - async def _sentry_execute_command(self, name, *args, **kwargs): - # type: (Any, str, *Any, **Any) -> Any + async def _sentry_execute_command( + self: Any, name: str, *args: Any, **kwargs: Any + ) -> Any: integration = sentry_sdk.get_client().get_integration(RedisIntegration) if integration is None: return await old_execute_command(self, name, *args, **kwargs) diff --git a/sentry_sdk/integrations/redis/_sync_common.py b/sentry_sdk/integrations/redis/_sync_common.py index 7efdf764a7..e3d5b77323 100644 --- a/sentry_sdk/integrations/redis/_sync_common.py +++ b/sentry_sdk/integrations/redis/_sync_common.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations.redis.consts import SPAN_ORIGIN @@ -22,18 +23,16 @@ def patch_redis_pipeline( - pipeline_cls, - is_cluster, - get_command_args_fn, - get_db_data_fn, -): - # type: (Any, bool, Any, Callable[[Any], dict[str, Any]]) -> None + pipeline_cls: Any, + is_cluster: bool, + get_command_args_fn: Any, + get_db_data_fn: Callable[[Any], dict[str, Any]], +) -> None: old_execute = pipeline_cls.execute from sentry_sdk.integrations.redis import RedisIntegration - def sentry_patched_execute(self, *args, **kwargs): - # type: (Any, *Any, **Any) -> Any + def sentry_patched_execute(self: Any, *args: Any, **kwargs: Any) -> Any: if sentry_sdk.get_client().get_integration(RedisIntegration) is None: return old_execute(self, *args, **kwargs) @@ -64,8 +63,9 @@ def sentry_patched_execute(self, *args, **kwargs): pipeline_cls.execute = sentry_patched_execute -def patch_redis_client(cls, is_cluster, get_db_data_fn): - # type: (Any, bool, Callable[[Any], dict[str, Any]]) -> None +def patch_redis_client( + cls: Any, is_cluster: bool, get_db_data_fn: Callable[[Any], dict[str, Any]] +) -> None: """ This function can be used to instrument custom redis client classes or subclasses. @@ -74,8 +74,9 @@ def patch_redis_client(cls, is_cluster, get_db_data_fn): from sentry_sdk.integrations.redis import RedisIntegration - def sentry_patched_execute_command(self, name, *args, **kwargs): - # type: (Any, str, *Any, **Any) -> Any + def sentry_patched_execute_command( + self: Any, name: str, *args: Any, **kwargs: Any + ) -> Any: integration = sentry_sdk.get_client().get_integration(RedisIntegration) if integration is None: return old_execute_command(self, name, *args, **kwargs) diff --git a/sentry_sdk/integrations/redis/modules/caches.py b/sentry_sdk/integrations/redis/modules/caches.py index 4ab33d2ea8..574c928f12 100644 --- a/sentry_sdk/integrations/redis/modules/caches.py +++ b/sentry_sdk/integrations/redis/modules/caches.py @@ -2,6 +2,7 @@ Code used for the Caches module in Sentry """ +from __future__ import annotations from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string from sentry_sdk.utils import capture_internal_exceptions @@ -16,8 +17,7 @@ from typing import Any, Optional -def _get_op(name): - # type: (str) -> Optional[str] +def _get_op(name: str) -> Optional[str]: op = None if name.lower() in GET_COMMANDS: op = OP.CACHE_GET @@ -27,8 +27,12 @@ def _get_op(name): return op -def _compile_cache_span_properties(redis_command, args, kwargs, integration): - # type: (str, tuple[Any, ...], dict[str, Any], RedisIntegration) -> dict[str, Any] +def _compile_cache_span_properties( + redis_command: str, + args: tuple[Any, ...], + kwargs: dict[str, Any], + integration: RedisIntegration, +) -> dict[str, Any]: key = _get_safe_key(redis_command, args, kwargs) key_as_string = _key_as_string(key) keys_as_string = key_as_string.split(", ") @@ -61,8 +65,12 @@ def _compile_cache_span_properties(redis_command, args, kwargs, integration): return properties -def _get_cache_span_description(redis_command, args, kwargs, integration): - # type: (str, tuple[Any, ...], dict[str, Any], RedisIntegration) -> str +def _get_cache_span_description( + redis_command: str, + args: tuple[Any, ...], + kwargs: dict[str, Any], + integration: RedisIntegration, +) -> str: description = _key_as_string(_get_safe_key(redis_command, args, kwargs)) data_should_be_truncated = ( @@ -74,8 +82,9 @@ def _get_cache_span_description(redis_command, args, kwargs, integration): return description -def _get_cache_data(redis_client, properties, return_value): - # type: (Any, dict[str, Any], Optional[Any]) -> dict[str, Any] +def _get_cache_data( + redis_client: Any, properties: dict[str, Any], return_value: Optional[Any] +) -> dict[str, Any]: data = {} with capture_internal_exceptions(): diff --git a/sentry_sdk/integrations/redis/modules/queries.py b/sentry_sdk/integrations/redis/modules/queries.py index c070893ac8..312d48e2bd 100644 --- a/sentry_sdk/integrations/redis/modules/queries.py +++ b/sentry_sdk/integrations/redis/modules/queries.py @@ -2,6 +2,7 @@ Code used for the Queries module in Sentry """ +from __future__ import annotations from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.redis.utils import _get_safe_command from sentry_sdk.utils import capture_internal_exceptions @@ -14,8 +15,9 @@ from typing import Any -def _compile_db_span_properties(integration, redis_command, args): - # type: (RedisIntegration, str, tuple[Any, ...]) -> dict[str, Any] +def _compile_db_span_properties( + integration: RedisIntegration, redis_command: str, args: tuple[Any, ...] +) -> dict[str, Any]: description = _get_db_span_description(integration, redis_command, args) properties = { @@ -26,8 +28,9 @@ def _compile_db_span_properties(integration, redis_command, args): return properties -def _get_db_span_description(integration, command_name, args): - # type: (RedisIntegration, str, tuple[Any, ...]) -> str +def _get_db_span_description( + integration: RedisIntegration, command_name: str, args: tuple[Any, ...] +) -> str: description = command_name with capture_internal_exceptions(): @@ -42,8 +45,7 @@ def _get_db_span_description(integration, command_name, args): return description -def _get_connection_data(connection_params): - # type: (dict[str, Any]) -> dict[str, Any] +def _get_connection_data(connection_params: dict[str, Any]) -> dict[str, Any]: data = { SPANDATA.DB_SYSTEM: "redis", } @@ -63,8 +65,7 @@ def _get_connection_data(connection_params): return data -def _get_db_data(redis_instance): - # type: (Redis[Any]) -> dict[str, Any] +def _get_db_data(redis_instance: Redis[Any]) -> dict[str, Any]: try: return _get_connection_data(redis_instance.connection_pool.connection_kwargs) except AttributeError: diff --git a/sentry_sdk/integrations/redis/rb.py b/sentry_sdk/integrations/redis/rb.py index 68d3c3a9d6..b6eab57171 100644 --- a/sentry_sdk/integrations/redis/rb.py +++ b/sentry_sdk/integrations/redis/rb.py @@ -4,12 +4,13 @@ https://github.com/getsentry/rb """ +from __future__ import annotations + from sentry_sdk.integrations.redis._sync_common import patch_redis_client from sentry_sdk.integrations.redis.modules.queries import _get_db_data -def _patch_rb(): - # type: () -> None +def _patch_rb() -> None: try: import rb.clients # type: ignore except ImportError: diff --git a/sentry_sdk/integrations/redis/redis.py b/sentry_sdk/integrations/redis/redis.py index 935a828c3d..f7332c906b 100644 --- a/sentry_sdk/integrations/redis/redis.py +++ b/sentry_sdk/integrations/redis/redis.py @@ -4,6 +4,8 @@ https://github.com/redis/redis-py """ +from __future__ import annotations + from sentry_sdk.integrations.redis._sync_common import ( patch_redis_client, patch_redis_pipeline, @@ -16,13 +18,11 @@ from typing import Any, Sequence -def _get_redis_command_args(command): - # type: (Any) -> Sequence[Any] +def _get_redis_command_args(command: Any) -> Sequence[Any]: return command[0] -def _patch_redis(StrictRedis, client): # noqa: N803 - # type: (Any, Any) -> None +def _patch_redis(StrictRedis: Any, client: Any) -> None: # noqa: N803 patch_redis_client( StrictRedis, is_cluster=False, diff --git a/sentry_sdk/integrations/redis/redis_cluster.py b/sentry_sdk/integrations/redis/redis_cluster.py index 5aab34ad64..3c4dfdea93 100644 --- a/sentry_sdk/integrations/redis/redis_cluster.py +++ b/sentry_sdk/integrations/redis/redis_cluster.py @@ -5,6 +5,8 @@ https://github.com/redis/redis-py/blob/master/redis/cluster.py """ +from __future__ import annotations + from sentry_sdk.integrations.redis._sync_common import ( patch_redis_client, patch_redis_pipeline, @@ -25,8 +27,9 @@ ) -def _get_async_cluster_db_data(async_redis_cluster_instance): - # type: (AsyncRedisCluster[Any]) -> dict[str, Any] +def _get_async_cluster_db_data( + async_redis_cluster_instance: AsyncRedisCluster[Any], +) -> dict[str, Any]: default_node = async_redis_cluster_instance.get_default_node() if default_node is not None and default_node.connection_kwargs is not None: return _get_connection_data(default_node.connection_kwargs) @@ -34,8 +37,9 @@ def _get_async_cluster_db_data(async_redis_cluster_instance): return {} -def _get_async_cluster_pipeline_db_data(async_redis_cluster_pipeline_instance): - # type: (AsyncClusterPipeline[Any]) -> dict[str, Any] +def _get_async_cluster_pipeline_db_data( + async_redis_cluster_pipeline_instance: AsyncClusterPipeline[Any], +) -> dict[str, Any]: with capture_internal_exceptions(): client = getattr(async_redis_cluster_pipeline_instance, "cluster_client", None) if client is None: @@ -50,8 +54,7 @@ def _get_async_cluster_pipeline_db_data(async_redis_cluster_pipeline_instance): return _get_async_cluster_db_data(client) -def _get_cluster_db_data(redis_cluster_instance): - # type: (RedisCluster[Any]) -> dict[str, Any] +def _get_cluster_db_data(redis_cluster_instance: RedisCluster[Any]) -> dict[str, Any]: default_node = redis_cluster_instance.get_default_node() if default_node is not None: @@ -64,8 +67,7 @@ def _get_cluster_db_data(redis_cluster_instance): return {} -def _patch_redis_cluster(): - # type: () -> None +def _patch_redis_cluster() -> None: """Patches the cluster module on redis SDK (as opposed to rediscluster library)""" try: from redis import RedisCluster, cluster diff --git a/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py b/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py index 53b545c21b..e658443e81 100644 --- a/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +++ b/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py @@ -5,6 +5,8 @@ https://github.com/grokzen/redis-py-cluster """ +from __future__ import annotations + from sentry_sdk.integrations.redis._sync_common import ( patch_redis_client, patch_redis_pipeline, @@ -13,8 +15,7 @@ from sentry_sdk.integrations.redis.utils import _parse_rediscluster_command -def _patch_rediscluster(): - # type: () -> None +def _patch_rediscluster() -> None: try: import rediscluster # type: ignore except ImportError: diff --git a/sentry_sdk/integrations/redis/utils.py b/sentry_sdk/integrations/redis/utils.py index 6d9a2d6160..e109d3fe34 100644 --- a/sentry_sdk/integrations/redis/utils.py +++ b/sentry_sdk/integrations/redis/utils.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.redis.consts import ( @@ -26,8 +27,7 @@ ] -def _update_span(span, *data_bags): - # type: (Span, *dict[str, Any]) -> None +def _update_span(span: Span, *data_bags: dict[str, Any]) -> None: """ Set tags and data on the given span to data from the given data bags. """ @@ -39,8 +39,7 @@ def _update_span(span, *data_bags): span.set_attribute(key, value) -def _create_breadcrumb(message, *data_bags): - # type: (str, *dict[str, Any]) -> None +def _create_breadcrumb(message: str, *data_bags: dict[str, Any]) -> None: """ Create a breadcrumb containing the tags data from the given data bags. """ @@ -58,8 +57,7 @@ def _create_breadcrumb(message, *data_bags): ) -def _get_safe_command(name, args): - # type: (str, Sequence[Any]) -> str +def _get_safe_command(name: str, args: Sequence[Any]) -> str: command_parts = [name] for i, arg in enumerate(args): @@ -86,8 +84,7 @@ def _get_safe_command(name, args): return command -def _safe_decode(key): - # type: (Any) -> str +def _safe_decode(key: Any) -> str: if isinstance(key, bytes): try: return key.decode() @@ -97,8 +94,7 @@ def _safe_decode(key): return str(key) -def _key_as_string(key): - # type: (Any) -> str +def _key_as_string(key: Any) -> str: if isinstance(key, (dict, list, tuple)): key = ", ".join(_safe_decode(x) for x in key) elif isinstance(key, bytes): @@ -111,8 +107,9 @@ def _key_as_string(key): return key -def _get_safe_key(method_name, args, kwargs): - # type: (str, Optional[tuple[Any, ...]], Optional[dict[str, Any]]) -> Optional[tuple[str, ...]] +def _get_safe_key( + method_name: str, args: Optional[tuple[Any, ...]], kwargs: Optional[dict[str, Any]] +) -> Optional[tuple[str, ...]]: """ Gets the key (or keys) from the given method_name. The method_name could be a redis command or a django caching command @@ -142,17 +139,20 @@ def _get_safe_key(method_name, args, kwargs): return key -def _parse_rediscluster_command(command): - # type: (Any) -> Sequence[Any] +def _parse_rediscluster_command(command: Any) -> Sequence[Any]: return command.args -def _get_pipeline_data(is_cluster, get_command_args_fn, is_transaction, command_seq): - # type: (bool, Any, bool, Sequence[Any]) -> dict[str, Any] - data = { +def _get_pipeline_data( + is_cluster: bool, + get_command_args_fn: Any, + is_transaction: bool, + command_seq: Sequence[Any], +) -> dict[str, Any]: + data: dict[str, Any] = { "redis.is_cluster": is_cluster, "redis.transaction": is_transaction, - } # type: dict[str, Any] + } commands = [] for i, arg in enumerate(command_seq): @@ -168,11 +168,10 @@ def _get_pipeline_data(is_cluster, get_command_args_fn, is_transaction, command_ return data -def _get_client_data(is_cluster, name, *args): - # type: (bool, str, *Any) -> dict[str, Any] - data = { +def _get_client_data(is_cluster: bool, name: str, *args: Any) -> dict[str, Any]: + data: dict[str, Any] = { "redis.is_cluster": is_cluster, - } # type: dict[str, Any] + } if name: data["redis.command"] = name diff --git a/sentry_sdk/integrations/spark/__init__.py b/sentry_sdk/integrations/spark/__init__.py index 10d94163c5..d9e8e3fa84 100644 --- a/sentry_sdk/integrations/spark/__init__.py +++ b/sentry_sdk/integrations/spark/__init__.py @@ -1,3 +1,4 @@ +from __future__ import annotations from sentry_sdk.integrations.spark.spark_driver import SparkIntegration from sentry_sdk.integrations.spark.spark_worker import SparkWorkerIntegration diff --git a/sentry_sdk/integrations/spark/spark_driver.py b/sentry_sdk/integrations/spark/spark_driver.py index fac985357f..a35883b60f 100644 --- a/sentry_sdk/integrations/spark/spark_driver.py +++ b/sentry_sdk/integrations/spark/spark_driver.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sentry_sdk from sentry_sdk.integrations import Integration from sentry_sdk.utils import capture_internal_exceptions, ensure_integration_enabled @@ -16,13 +17,11 @@ class SparkIntegration(Integration): identifier = "spark" @staticmethod - def setup_once(): - # type: () -> None + def setup_once() -> None: _setup_sentry_tracing() -def _set_app_properties(): - # type: () -> None +def _set_app_properties() -> None: """ Set properties in driver that propagate to worker processes, allowing for workers to have access to those properties. This allows worker integration to have access to app_name and application_id. @@ -41,8 +40,7 @@ def _set_app_properties(): ) -def _start_sentry_listener(sc): - # type: (SparkContext) -> None +def _start_sentry_listener(sc: SparkContext) -> None: """ Start java gateway server to add custom `SparkListener` """ @@ -54,13 +52,11 @@ def _start_sentry_listener(sc): sc._jsc.sc().addSparkListener(listener) -def _add_event_processor(sc): - # type: (SparkContext) -> None +def _add_event_processor(sc: SparkContext) -> None: scope = sentry_sdk.get_isolation_scope() @scope.add_event_processor - def process_event(event, hint): - # type: (Event, Hint) -> Optional[Event] + def process_event(event: Event, hint: Hint) -> Optional[Event]: with capture_internal_exceptions(): if sentry_sdk.get_client().get_integration(SparkIntegration) is None: return event @@ -90,23 +86,22 @@ def process_event(event, hint): return event -def _activate_integration(sc): - # type: (SparkContext) -> None +def _activate_integration(sc: SparkContext) -> None: _start_sentry_listener(sc) _set_app_properties() _add_event_processor(sc) -def _patch_spark_context_init(): - # type: () -> None +def _patch_spark_context_init() -> None: from pyspark import SparkContext spark_context_init = SparkContext._do_init @ensure_integration_enabled(SparkIntegration, spark_context_init) - def _sentry_patched_spark_context_init(self, *args, **kwargs): - # type: (SparkContext, *Any, **Any) -> Optional[Any] + def _sentry_patched_spark_context_init( + self: SparkContext, *args: Any, **kwargs: Any + ) -> Optional[Any]: rv = spark_context_init(self, *args, **kwargs) _activate_integration(self) return rv @@ -114,8 +109,7 @@ def _sentry_patched_spark_context_init(self, *args, **kwargs): SparkContext._do_init = _sentry_patched_spark_context_init -def _setup_sentry_tracing(): - # type: () -> None +def _setup_sentry_tracing() -> None: from pyspark import SparkContext if SparkContext._active_spark_context is not None: @@ -125,102 +119,76 @@ def _setup_sentry_tracing(): class SparkListener: - def onApplicationEnd(self, applicationEnd): # noqa: N802,N803 - # type: (Any) -> None + def onApplicationEnd(self, applicationEnd: Any) -> None: pass - def onApplicationStart(self, applicationStart): # noqa: N802,N803 - # type: (Any) -> None + def onApplicationStart(self, applicationStart: Any) -> None: pass - def onBlockManagerAdded(self, blockManagerAdded): # noqa: N802,N803 - # type: (Any) -> None + def onBlockManagerAdded(self, blockManagerAdded: Any) -> None: pass - def onBlockManagerRemoved(self, blockManagerRemoved): # noqa: N802,N803 - # type: (Any) -> None + def onBlockManagerRemoved(self, blockManagerRemoved: Any) -> None: pass - def onBlockUpdated(self, blockUpdated): # noqa: N802,N803 - # type: (Any) -> None + def onBlockUpdated(self, blockUpdated: Any) -> None: pass - def onEnvironmentUpdate(self, environmentUpdate): # noqa: N802,N803 - # type: (Any) -> None + def onEnvironmentUpdate(self, environmentUpdate: Any) -> None: pass - def onExecutorAdded(self, executorAdded): # noqa: N802,N803 - # type: (Any) -> None + def onExecutorAdded(self, executorAdded: Any) -> None: pass - def onExecutorBlacklisted(self, executorBlacklisted): # noqa: N802,N803 - # type: (Any) -> None + def onExecutorBlacklisted(self, executorBlacklisted: Any) -> None: pass - def onExecutorBlacklistedForStage( # noqa: N802 - self, executorBlacklistedForStage # noqa: N803 - ): - # type: (Any) -> None + def onExecutorBlacklistedForStage(self, executorBlacklistedForStage: Any) -> None: pass - def onExecutorMetricsUpdate(self, executorMetricsUpdate): # noqa: N802,N803 - # type: (Any) -> None + def onExecutorMetricsUpdate(self, executorMetricsUpdate: Any) -> None: pass - def onExecutorRemoved(self, executorRemoved): # noqa: N802,N803 - # type: (Any) -> None + def onExecutorRemoved(self, executorRemoved: Any) -> None: pass - def onJobEnd(self, jobEnd): # noqa: N802,N803 - # type: (Any) -> None + def onJobEnd(self, jobEnd: Any) -> None: pass - def onJobStart(self, jobStart): # noqa: N802,N803 - # type: (Any) -> None + def onJobStart(self, jobStart: Any) -> None: pass - def onNodeBlacklisted(self, nodeBlacklisted): # noqa: N802,N803 - # type: (Any) -> None + def onNodeBlacklisted(self, nodeBlacklisted: Any) -> None: pass - def onNodeBlacklistedForStage(self, nodeBlacklistedForStage): # noqa: N802,N803 - # type: (Any) -> None + def onNodeBlacklistedForStage(self, nodeBlacklistedForStage: Any) -> None: pass - def onNodeUnblacklisted(self, nodeUnblacklisted): # noqa: N802,N803 - # type: (Any) -> None + def onNodeUnblacklisted(self, nodeUnblacklisted: Any) -> None: pass - def onOtherEvent(self, event): # noqa: N802,N803 - # type: (Any) -> None + def onOtherEvent(self, event: Any) -> None: pass - def onSpeculativeTaskSubmitted(self, speculativeTask): # noqa: N802,N803 - # type: (Any) -> None + def onSpeculativeTaskSubmitted(self, speculativeTask: Any) -> None: pass - def onStageCompleted(self, stageCompleted): # noqa: N802,N803 - # type: (Any) -> None + def onStageCompleted(self, stageCompleted: Any) -> None: pass - def onStageSubmitted(self, stageSubmitted): # noqa: N802,N803 - # type: (Any) -> None + def onStageSubmitted(self, stageSubmitted: Any) -> None: pass - def onTaskEnd(self, taskEnd): # noqa: N802,N803 - # type: (Any) -> None + def onTaskEnd(self, taskEnd: Any) -> None: pass - def onTaskGettingResult(self, taskGettingResult): # noqa: N802,N803 - # type: (Any) -> None + def onTaskGettingResult(self, taskGettingResult: Any) -> None: pass - def onTaskStart(self, taskStart): # noqa: N802,N803 - # type: (Any) -> None + def onTaskStart(self, taskStart: Any) -> None: pass - def onUnpersistRDD(self, unpersistRDD): # noqa: N802,N803 - # type: (Any) -> None + def onUnpersistRDD(self, unpersistRDD: Any) -> None: pass class Java: @@ -230,25 +198,22 @@ class Java: class SentryListener(SparkListener): def _add_breadcrumb( self, - level, # type: str - message, # type: str - data=None, # type: Optional[dict[str, Any]] - ): - # type: (...) -> None + level: str, + message: str, + data: Optional[dict[str, Any]] = None, + ) -> None: sentry_sdk.get_isolation_scope().add_breadcrumb( level=level, message=message, data=data ) - def onJobStart(self, jobStart): # noqa: N802,N803 - # type: (Any) -> None + def onJobStart(self, jobStart: Any) -> None: sentry_sdk.get_isolation_scope().clear_breadcrumbs() message = "Job {} Started".format(jobStart.jobId()) self._add_breadcrumb(level="info", message=message) _set_app_properties() - def onJobEnd(self, jobEnd): # noqa: N802,N803 - # type: (Any) -> None + def onJobEnd(self, jobEnd: Any) -> None: level = "" message = "" data = {"result": jobEnd.jobResult().toString()} @@ -262,8 +227,7 @@ def onJobEnd(self, jobEnd): # noqa: N802,N803 self._add_breadcrumb(level=level, message=message, data=data) - def onStageSubmitted(self, stageSubmitted): # noqa: N802,N803 - # type: (Any) -> None + def onStageSubmitted(self, stageSubmitted: Any) -> None: stage_info = stageSubmitted.stageInfo() message = "Stage {} Submitted".format(stage_info.stageId()) @@ -275,8 +239,7 @@ def onStageSubmitted(self, stageSubmitted): # noqa: N802,N803 self._add_breadcrumb(level="info", message=message, data=data) _set_app_properties() - def onStageCompleted(self, stageCompleted): # noqa: N802,N803 - # type: (Any) -> None + def onStageCompleted(self, stageCompleted: Any) -> None: from py4j.protocol import Py4JJavaError # type: ignore stage_info = stageCompleted.stageInfo() @@ -300,8 +263,7 @@ def onStageCompleted(self, stageCompleted): # noqa: N802,N803 self._add_breadcrumb(level=level, message=message, data=data) -def _get_attempt_id(stage_info): - # type: (Any) -> Optional[int] +def _get_attempt_id(stage_info: Any) -> Optional[int]: try: return stage_info.attemptId() except Exception: diff --git a/sentry_sdk/integrations/spark/spark_worker.py b/sentry_sdk/integrations/spark/spark_worker.py index 5340a0b350..ce42c752f5 100644 --- a/sentry_sdk/integrations/spark/spark_worker.py +++ b/sentry_sdk/integrations/spark/spark_worker.py @@ -1,3 +1,4 @@ +from __future__ import annotations import sys import sentry_sdk @@ -23,15 +24,13 @@ class SparkWorkerIntegration(Integration): identifier = "spark_worker" @staticmethod - def setup_once(): - # type: () -> None + def setup_once() -> None: import pyspark.daemon as original_daemon original_daemon.worker_main = _sentry_worker_main -def _capture_exception(exc_info): - # type: (ExcInfo) -> None +def _capture_exception(exc_info: ExcInfo) -> None: client = sentry_sdk.get_client() mechanism = {"type": "spark", "handled": False} @@ -53,22 +52,20 @@ def _capture_exception(exc_info): if rv: rv.reverse() hint = event_hint_with_exc_info(exc_info) - event = {"level": "error", "exception": {"values": rv}} # type: Event + event: Event = {"level": "error", "exception": {"values": rv}} _tag_task_context() sentry_sdk.capture_event(event, hint=hint) -def _tag_task_context(): - # type: () -> None +def _tag_task_context() -> None: from pyspark.taskcontext import TaskContext scope = sentry_sdk.get_isolation_scope() @scope.add_event_processor - def process_event(event, hint): - # type: (Event, Hint) -> Optional[Event] + def process_event(event: Event, hint: Hint) -> Optional[Event]: with capture_internal_exceptions(): integration = sentry_sdk.get_client().get_integration( SparkWorkerIntegration @@ -103,8 +100,7 @@ def process_event(event, hint): return event -def _sentry_worker_main(*args, **kwargs): - # type: (*Optional[Any], **Optional[Any]) -> None +def _sentry_worker_main(*args: Optional[Any], **kwargs: Optional[Any]) -> None: import pyspark.worker as original_worker try: