44Based on Tom Christie's `sentry-asgi <https://github.com/encode/sentry-asgi>`_.
55"""
66
7+ import asyncio
78import functools
9+ import inspect
810import urllib
911
1012from sentry_sdk ._types import MYPY
1719 from typing import Dict
1820 from typing import Any
1921 from typing import Optional
22+ from typing import Callable
2023
2124 from sentry_sdk ._types import Event , Hint
2225
@@ -37,26 +40,45 @@ def _capture_exception(hub, exc):
3740 hub .capture_event (event , hint = hint )
3841
3942
43+ def _looks_like_asgi3 (app ):
44+ # type: (Any) -> bool
45+ """
46+ Try to figure out if an application object supports ASGI3.
47+
48+ This is how uvicorn figures out the application version as well.
49+ """
50+ if inspect .isclass (app ):
51+ return hasattr (app , "__await__" )
52+ elif inspect .isfunction (app ):
53+ return asyncio .iscoroutinefunction (app )
54+ else :
55+ call = getattr (app , "__call__" , None ) # noqa
56+ return asyncio .iscoroutinefunction (call )
57+
58+
4059class SentryAsgiMiddleware :
41- __slots__ = ("app" ,)
60+ __slots__ = ("app" , "__call__" )
4261
4362 def __init__ (self , app ):
4463 # type: (Any) -> None
4564 self .app = app
4665
47- def __call__ (self , scope , receive = None , send = None ):
48- # type: (Any, Any, Any) -> Any
49- if receive is None or send is None :
66+ if _looks_like_asgi3 (app ):
67+ self .__call__ = self ._run_asgi3 # type: Callable[..., Any]
68+ else :
69+ self .__call__ = self ._run_asgi2
5070
51- async def run_asgi2 ( receive , send ):
52- # type: (Any, Any) -> Any
53- return await self . _run_app (
54- scope , lambda : self . app ( scope )( receive , send )
55- )
71+ def _run_asgi2 ( self , scope ):
72+ # type: (Any) -> Any
73+ async def inner ( receive , send ):
74+ # type: (Any, Any) -> Any
75+ return await self . _run_app ( scope , lambda : self . app ( scope )( receive , send ) )
5676
57- return run_asgi2
58- else :
59- return self ._run_app (scope , lambda : self .app (scope , receive , send ))
77+ return inner
78+
79+ async def _run_asgi3 (self , scope , receive , send ):
80+ # type: (Any, Any, Any) -> Any
81+ return await self ._run_app (scope , lambda : self .app (scope , receive , send ))
6082
6183 async def _run_app (self , scope , callback ):
6284 # type: (Any, Any) -> Any
0 commit comments