From ee225d902b84ad4101dc6d7d13d11b8778856ca4 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sun, 17 Nov 2019 18:14:24 +0100 Subject: [PATCH 1/2] fix: Make ASGI middleware inspectable for ASGI version --- sentry_sdk/integrations/asgi.py | 42 +++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/sentry_sdk/integrations/asgi.py b/sentry_sdk/integrations/asgi.py index 4cd7f402a9..9eaa1e2085 100644 --- a/sentry_sdk/integrations/asgi.py +++ b/sentry_sdk/integrations/asgi.py @@ -4,7 +4,9 @@ Based on Tom Christie's `sentry-asgi `_. """ +import asyncio import functools +import inspect import urllib from sentry_sdk._types import MYPY @@ -37,26 +39,42 @@ def _capture_exception(hub, exc): hub.capture_event(event, hint=hint) +def _looks_like_asgi3(app): + """ + Try to figure out if an application object supports ASGI3. + + This is how uvicorn figures out the application version as well. + """ + if inspect.isclass(app): + return hasattr(app, "__await__") + elif inspect.isfunction(app): + return asyncio.iscoroutinefunction(app) + else: + call = getattr(app, "__call__", None) + return asyncio.iscoroutinefunction(call) + + class SentryAsgiMiddleware: - __slots__ = ("app",) + __slots__ = ("app", "__call__") def __init__(self, app): # type: (Any) -> None self.app = app - def __call__(self, scope, receive=None, send=None): - # type: (Any, Any, Any) -> Any - if receive is None or send is None: + if _looks_like_asgi3(app): + self.__call__ = self._run_asgi3 + else: + self.__call__ = self._run_asgi2 - async def run_asgi2(receive, send): - # type: (Any, Any) -> Any - return await self._run_app( - scope, lambda: self.app(scope)(receive, send) - ) + def _run_asgi2(self, scope): + async def inner(receive, send): + # type: (Any, Any) -> Any + return await self._run_app(scope, lambda: self.app(scope)(receive, send)) - return run_asgi2 - else: - return self._run_app(scope, lambda: self.app(scope, receive, send)) + return inner + + async def _run_asgi3(self, scope, receive, send): + return await self._run_app(scope, lambda: self.app(scope, receive, send)) async def _run_app(self, scope, callback): # type: (Any, Any) -> Any From cd217d6aae2481f98c9f371aa86016810b398cfc Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Mon, 18 Nov 2019 12:53:45 +0100 Subject: [PATCH 2/2] fix: Linters --- sentry_sdk/integrations/asgi.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/asgi.py b/sentry_sdk/integrations/asgi.py index 9eaa1e2085..e8267d539d 100644 --- a/sentry_sdk/integrations/asgi.py +++ b/sentry_sdk/integrations/asgi.py @@ -19,6 +19,7 @@ from typing import Dict from typing import Any from typing import Optional + from typing import Callable from sentry_sdk._types import Event, Hint @@ -40,6 +41,7 @@ def _capture_exception(hub, exc): def _looks_like_asgi3(app): + # type: (Any) -> bool """ Try to figure out if an application object supports ASGI3. @@ -50,7 +52,7 @@ def _looks_like_asgi3(app): elif inspect.isfunction(app): return asyncio.iscoroutinefunction(app) else: - call = getattr(app, "__call__", None) + call = getattr(app, "__call__", None) # noqa return asyncio.iscoroutinefunction(call) @@ -62,11 +64,12 @@ def __init__(self, app): self.app = app if _looks_like_asgi3(app): - self.__call__ = self._run_asgi3 + self.__call__ = self._run_asgi3 # type: Callable[..., Any] else: self.__call__ = self._run_asgi2 def _run_asgi2(self, scope): + # type: (Any) -> Any async def inner(receive, send): # type: (Any, Any) -> Any return await self._run_app(scope, lambda: self.app(scope)(receive, send)) @@ -74,6 +77,7 @@ async def inner(receive, send): return inner async def _run_asgi3(self, scope, receive, send): + # type: (Any, Any, Any) -> Any return await self._run_app(scope, lambda: self.app(scope, receive, send)) async def _run_app(self, scope, callback):