Skip to content

Commit cb84e92

Browse files
committed
python 3.16
1 parent cab17a4 commit cb84e92

File tree

10 files changed

+53
-36
lines changed

10 files changed

+53
-36
lines changed

sentry_sdk/_compat.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import sys
2+
import asyncio
3+
import inspect
24

35
from typing import TYPE_CHECKING
46

57
if TYPE_CHECKING:
68
from typing import Any
79
from typing import TypeVar
10+
from typing import Callable
811

912
T = TypeVar("T")
13+
_F = TypeVar("_F", bound=Callable[..., Any])
1014

1115

1216
PY37 = sys.version_info[0] == 3 and sys.version_info[1] >= 7
@@ -15,6 +19,23 @@
1519
PY311 = sys.version_info[0] == 3 and sys.version_info[1] >= 11
1620

1721

22+
# Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for
23+
# inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker.
24+
# The latter is replaced with the inspect.markcoroutinefunction decorator.
25+
# Until 3.12 is the minimum supported Python version, provide a shim.
26+
# This was adapted from https://github.com/django/asgiref/blob/main/asgiref/sync.py
27+
if hasattr(inspect, "markcoroutinefunction"):
28+
iscoroutinefunction = inspect.iscoroutinefunction
29+
markcoroutinefunction = inspect.markcoroutinefunction
30+
else:
31+
iscoroutinefunction = asyncio.iscoroutinefunction # type: ignore[assignment]
32+
33+
def markcoroutinefunction(func):
34+
# type: (_F) -> _F
35+
func._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore
36+
return func
37+
38+
1839
def with_metaclass(meta, *bases):
1940
# type: (Any, *Any) -> Any
2041
class MetaClass(type):

sentry_sdk/ai/monitoring.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import inspect
22
from functools import wraps
33

4+
from sentry_sdk._compat import iscoroutinefunction
45
from sentry_sdk.consts import SPANDATA
56
import sentry_sdk.utils
67
from sentry_sdk import start_span
@@ -89,7 +90,7 @@ async def async_wrapped(*args, **kwargs):
8990
_ai_pipeline_name.set(None)
9091
return res
9192

92-
if inspect.iscoroutinefunction(f):
93+
if iscoroutinefunction(f):
9394
return wraps(f)(async_wrapped) # type: ignore
9495
else:
9596
return wraps(f)(sync_wrapped) # type: ignore

sentry_sdk/integrations/asgi.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from functools import partial
1111

1212
import sentry_sdk
13+
from sentry_sdk._compat import iscoroutinefunction
1314
from sentry_sdk.api import continue_trace
1415
from sentry_sdk.consts import OP
1516
from sentry_sdk.integrations._asgi_common import (
@@ -76,10 +77,10 @@ def _looks_like_asgi3(app):
7677
if inspect.isclass(app):
7778
return hasattr(app, "__await__")
7879
elif inspect.isfunction(app):
79-
return asyncio.iscoroutinefunction(app)
80+
return iscoroutinefunction(app)
8081
else:
8182
call = getattr(app, "__call__", None) # noqa
82-
return asyncio.iscoroutinefunction(call)
83+
return iscoroutinefunction(call)
8384

8485

8586
class SentryAsgiMiddleware:

sentry_sdk/integrations/django/asgi.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.core.handlers.wsgi import WSGIRequest
1414

1515
import sentry_sdk
16+
from sentry_sdk._compat import iscoroutinefunction, markcoroutinefunction
1617
from sentry_sdk.consts import OP
1718

1819
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
@@ -35,20 +36,7 @@
3536
_F = TypeVar("_F", bound=Callable[..., Any])
3637

3738

38-
# Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for
39-
# inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker.
40-
# The latter is replaced with the inspect.markcoroutinefunction decorator.
41-
# Until 3.12 is the minimum supported Python version, provide a shim.
42-
# This was copied from https://github.com/django/asgiref/blob/main/asgiref/sync.py
43-
if hasattr(inspect, "markcoroutinefunction"):
44-
iscoroutinefunction = inspect.iscoroutinefunction
45-
markcoroutinefunction = inspect.markcoroutinefunction
46-
else:
47-
iscoroutinefunction = asyncio.iscoroutinefunction # type: ignore[assignment]
48-
49-
def markcoroutinefunction(func: "_F") -> "_F":
50-
func._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore
51-
return func
39+
5240

5341

5442
def _make_asgi_request_event_processor(request):

sentry_sdk/integrations/fastapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from functools import wraps
44

55
import sentry_sdk
6+
from sentry_sdk._compat import iscoroutinefunction
67
from sentry_sdk.integrations import DidNotEnable
78
from sentry_sdk.scope import should_send_default_pii
89
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
@@ -75,7 +76,7 @@ def _sentry_get_request_handler(*args, **kwargs):
7576
if (
7677
dependant
7778
and dependant.call is not None
78-
and not asyncio.iscoroutinefunction(dependant.call)
79+
and not iscoroutinefunction(dependant.call)
7980
):
8081
old_call = dependant.call
8182

sentry_sdk/integrations/google_genai/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616

1717
import sentry_sdk
18+
from sentry_sdk._compat import iscoroutinefunction
1819
from sentry_sdk.ai.utils import set_data_normalized
1920
from sentry_sdk.consts import OP, SPANDATA
2021
from sentry_sdk.scope import should_send_default_pii
@@ -318,7 +319,7 @@ def wrapped_tool(tool):
318319
tool_name = getattr(tool, "__name__", "unknown")
319320
tool_doc = tool.__doc__
320321

321-
if inspect.iscoroutinefunction(tool):
322+
if iscoroutinefunction(tool):
322323
# Async function
323324
@wraps(tool)
324325
async def async_wrapped(*args, **kwargs):

sentry_sdk/integrations/quart.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from functools import wraps
44

55
import sentry_sdk
6+
from sentry_sdk._compat import iscoroutinefunction
67
from sentry_sdk.integrations import DidNotEnable, Integration
78
from sentry_sdk.integrations._wsgi_common import _filter_headers
89
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
@@ -113,7 +114,7 @@ def _sentry_route(*args, **kwargs):
113114
def decorator(old_func):
114115
# type: (Any) -> Any
115116

116-
if inspect.isfunction(old_func) and not asyncio.iscoroutinefunction(
117+
if inspect.isfunction(old_func) and not iscoroutinefunction(
117118
old_func
118119
):
119120

sentry_sdk/integrations/starlette.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from json import JSONDecodeError
77

88
import sentry_sdk
9+
from sentry_sdk._compat import iscoroutinefunction
910
from sentry_sdk.consts import OP
1011
from sentry_sdk.integrations import (
1112
DidNotEnable,
@@ -415,8 +416,8 @@ def _is_async_callable(obj):
415416
while isinstance(obj, functools.partial):
416417
obj = obj.func
417418

418-
return asyncio.iscoroutinefunction(obj) or (
419-
callable(obj) and asyncio.iscoroutinefunction(obj.__call__)
419+
return iscoroutinefunction(obj) or (
420+
callable(obj) and iscoroutinefunction(obj.__call__)
420421
)
421422

422423

sentry_sdk/tracing_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import uuid
1212

1313
import sentry_sdk
14+
from sentry_sdk._compat import iscoroutinefunction
1415
from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS, SPANTEMPLATE
1516
from sentry_sdk.utils import (
1617
capture_internal_exceptions,
@@ -912,7 +913,7 @@ def sync_wrapper(*args, **kwargs):
912913
except Exception:
913914
pass
914915

915-
if inspect.iscoroutinefunction(f):
916+
if iscoroutinefunction(f):
916917
return async_wrapper
917918
else:
918919
return sync_wrapper

tests/integrations/httpx/test_httpx.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import sentry_sdk
1111
from sentry_sdk import capture_message, start_transaction
12+
from sentry_sdk._compat import iscoroutinefunction
1213
from sentry_sdk.consts import MATCH_ALL, SPANDATA
1314
from sentry_sdk.integrations.httpx import HttpxIntegration
1415
from tests.conftest import ApproxDict
@@ -32,7 +33,7 @@ def before_breadcrumb(crumb, hint):
3233
with start_transaction():
3334
events = capture_events()
3435

35-
if asyncio.iscoroutinefunction(httpx_client.get):
36+
if iscoroutinefunction(httpx_client.get):
3637
response = asyncio.get_event_loop().run_until_complete(
3738
httpx_client.get(url)
3839
)
@@ -86,7 +87,7 @@ def test_crumb_capture_client_error(
8687
with start_transaction():
8788
events = capture_events()
8889

89-
if asyncio.iscoroutinefunction(httpx_client.get):
90+
if iscoroutinefunction(httpx_client.get):
9091
response = asyncio.get_event_loop().run_until_complete(
9192
httpx_client.get(url)
9293
)
@@ -137,7 +138,7 @@ def test_outgoing_trace_headers(sentry_init, httpx_client, httpx_mock):
137138
op="greeting.sniff",
138139
trace_id="01234567890123456789012345678901",
139140
) as transaction:
140-
if asyncio.iscoroutinefunction(httpx_client.get):
141+
if iscoroutinefunction(httpx_client.get):
141142
response = asyncio.get_event_loop().run_until_complete(
142143
httpx_client.get(url)
143144
)
@@ -180,7 +181,7 @@ def test_outgoing_trace_headers_append_to_baggage(
180181
op="greeting.sniff",
181182
trace_id="01234567890123456789012345678901",
182183
) as transaction:
183-
if asyncio.iscoroutinefunction(httpx_client.get):
184+
if iscoroutinefunction(httpx_client.get):
184185
response = asyncio.get_event_loop().run_until_complete(
185186
httpx_client.get(url, headers={"baGGage": "custom=data"})
186187
)
@@ -333,7 +334,7 @@ def test_option_trace_propagation_targets(
333334

334335
# Must be in a transaction to propagate headers
335336
with sentry_sdk.start_transaction():
336-
if asyncio.iscoroutinefunction(httpx_client.get):
337+
if iscoroutinefunction(httpx_client.get):
337338
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
338339
else:
339340
httpx_client.get(url)
@@ -420,7 +421,7 @@ def test_request_source_disabled(
420421
url = "http://example.com/"
421422

422423
with start_transaction(name="test_transaction"):
423-
if asyncio.iscoroutinefunction(httpx_client.get):
424+
if iscoroutinefunction(httpx_client.get):
424425
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
425426
else:
426427
httpx_client.get(url)
@@ -457,7 +458,7 @@ def test_request_source_enabled(sentry_init, capture_events, httpx_client, httpx
457458
url = "http://example.com/"
458459

459460
with start_transaction(name="test_transaction"):
460-
if asyncio.iscoroutinefunction(httpx_client.get):
461+
if iscoroutinefunction(httpx_client.get):
461462
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
462463
else:
463464
httpx_client.get(url)
@@ -494,7 +495,7 @@ def test_request_source(sentry_init, capture_events, httpx_client, httpx_mock):
494495
url = "http://example.com/"
495496

496497
with start_transaction(name="test_transaction"):
497-
if asyncio.iscoroutinefunction(httpx_client.get):
498+
if iscoroutinefunction(httpx_client.get):
498499
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
499500
else:
500501
httpx_client.get(url)
@@ -547,7 +548,7 @@ def test_request_source_with_module_in_search_path(
547548
url = "http://example.com/"
548549

549550
with start_transaction(name="test_transaction"):
550-
if asyncio.iscoroutinefunction(httpx_client.get):
551+
if iscoroutinefunction(httpx_client.get):
551552
from httpx_helpers.helpers import async_get_request_with_client
552553

553554
asyncio.get_event_loop().run_until_complete(
@@ -578,7 +579,7 @@ def test_request_source_with_module_in_search_path(
578579
is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep
579580
assert is_relative_path
580581

581-
if asyncio.iscoroutinefunction(httpx_client.get):
582+
if iscoroutinefunction(httpx_client.get):
582583
assert data.get(SPANDATA.CODE_FUNCTION) == "async_get_request_with_client"
583584
else:
584585
assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_client"
@@ -618,7 +619,7 @@ def fake_start_span(*args, **kwargs):
618619
"sentry_sdk.integrations.httpx.start_span",
619620
fake_start_span,
620621
):
621-
if asyncio.iscoroutinefunction(httpx_client.get):
622+
if iscoroutinefunction(httpx_client.get):
622623
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
623624
else:
624625
httpx_client.get(url)
@@ -670,7 +671,7 @@ def fake_start_span(*args, **kwargs):
670671
"sentry_sdk.integrations.httpx.start_span",
671672
fake_start_span,
672673
):
673-
if asyncio.iscoroutinefunction(httpx_client.get):
674+
if iscoroutinefunction(httpx_client.get):
674675
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
675676
else:
676677
httpx_client.get(url)
@@ -720,7 +721,7 @@ def test_span_origin(sentry_init, capture_events, httpx_client, httpx_mock):
720721
url = "http://example.com/"
721722

722723
with start_transaction(name="test_transaction"):
723-
if asyncio.iscoroutinefunction(httpx_client.get):
724+
if iscoroutinefunction(httpx_client.get):
724725
asyncio.get_event_loop().run_until_complete(httpx_client.get(url))
725726
else:
726727
httpx_client.get(url)

0 commit comments

Comments
 (0)