Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sentry_sdk/integrations/django/asgi.py: 38%
67 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Instrumentation for Django 3.0
4Since this file contains `async def` it is conditionally imported in
5`sentry_sdk.integrations.django` (depending on the existence of
6`django.core.handlers.asgi`.
7"""
9import asyncio
11from sentry_sdk import Hub, _functools
12from sentry_sdk._types import MYPY
14from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
16if MYPY: 16 ↛ 17line 16 didn't jump to line 17, because the condition on line 16 was never true
17 from typing import Any
18 from typing import Union
19 from typing import Callable
21 from django.http.response import HttpResponse
24def patch_django_asgi_handler_impl(cls):
25 # type: (Any) -> None
27 from sentry_sdk.integrations.django import DjangoIntegration
29 old_app = cls.__call__
31 async def sentry_patched_asgi_handler(self, scope, receive, send):
32 # type: (Any, Any, Any, Any) -> Any
33 if Hub.current.get_integration(DjangoIntegration) is None:
34 return await old_app(self, scope, receive, send)
36 middleware = SentryAsgiMiddleware(
37 old_app.__get__(self, cls), unsafe_context_data=True
38 )._run_asgi3
39 return await middleware(scope, receive, send)
41 cls.__call__ = sentry_patched_asgi_handler
44def patch_get_response_async(cls, _before_get_response):
45 # type: (Any, Any) -> None
46 old_get_response_async = cls.get_response_async
48 async def sentry_patched_get_response_async(self, request):
49 # type: (Any, Any) -> Union[HttpResponse, BaseException]
50 _before_get_response(request)
51 return await old_get_response_async(self, request)
53 cls.get_response_async = sentry_patched_get_response_async
56def patch_channels_asgi_handler_impl(cls):
57 # type: (Any) -> None
59 import channels # type: ignore
60 from sentry_sdk.integrations.django import DjangoIntegration
62 if channels.__version__ < "3.0.0":
64 old_app = cls.__call__
66 async def sentry_patched_asgi_handler(self, receive, send):
67 # type: (Any, Any, Any) -> Any
68 if Hub.current.get_integration(DjangoIntegration) is None:
69 return await old_app(self, receive, send)
71 middleware = SentryAsgiMiddleware(
72 lambda _scope: old_app.__get__(self, cls), unsafe_context_data=True
73 )
75 return await middleware(self.scope)(receive, send)
77 cls.__call__ = sentry_patched_asgi_handler
79 else:
80 # The ASGI handler in Channels >= 3 has the same signature as
81 # the Django handler.
82 patch_django_asgi_handler_impl(cls)
85def wrap_async_view(hub, callback):
86 # type: (Hub, Any) -> Any
87 @_functools.wraps(callback)
88 async def sentry_wrapped_callback(request, *args, **kwargs):
89 # type: (Any, *Any, **Any) -> Any
91 with hub.start_span(
92 op="django.view", description=request.resolver_match.view_name
93 ):
94 return await callback(request, *args, **kwargs)
96 return sentry_wrapped_callback
99def _asgi_middleware_mixin_factory(_check_middleware_span):
100 # type: (Callable[..., Any]) -> Any
101 """
102 Mixin class factory that generates a middleware mixin for handling requests
103 in async mode.
104 """
106 class SentryASGIMixin:
107 if MYPY: 107 ↛ 108line 107 didn't jump to line 108, because the condition on line 107 was never true
108 _inner = None
110 def __init__(self, get_response):
111 # type: (Callable[..., Any]) -> None
112 self.get_response = get_response
113 self._acall_method = None
114 self._async_check()
116 def _async_check(self):
117 # type: () -> None
118 """
119 If get_response is a coroutine function, turns us into async mode so
120 a thread is not consumed during a whole request.
121 Taken from django.utils.deprecation::MiddlewareMixin._async_check
122 """
123 if asyncio.iscoroutinefunction(self.get_response): 123 ↛ 124line 123 didn't jump to line 124, because the condition on line 123 was never true
124 self._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore
126 def async_route_check(self):
127 # type: () -> bool
128 """
129 Function that checks if we are in async mode,
130 and if we are forwards the handling of requests to __acall__
131 """
132 return asyncio.iscoroutinefunction(self.get_response)
134 async def __acall__(self, *args, **kwargs):
135 # type: (*Any, **Any) -> Any
136 f = self._acall_method
137 if f is None:
138 if hasattr(self._inner, "__acall__"):
139 self._acall_method = f = self._inner.__acall__ # type: ignore
140 else:
141 self._acall_method = f = self._inner
143 middleware_span = _check_middleware_span(old_method=f)
145 if middleware_span is None:
146 return await f(*args, **kwargs)
148 with middleware_span:
149 return await f(*args, **kwargs)
151 return SentryASGIMixin