Skip to content

fix(django): Use inspect.iscoroutinefunction on Python 3.14+ - #6869

Open
Digenis wants to merge 2 commits into
getsentry:masterfrom
Digenis:master
Open

fix(django): Use inspect.iscoroutinefunction on Python 3.14+#6869
Digenis wants to merge 2 commits into
getsentry:masterfrom
Digenis:master

Conversation

@Digenis

@Digenis Digenis commented Jul 23, 2026

Copy link
Copy Markdown

Description

Fix asyncio.iscoroutinefunction deprecation warning as mentioned in #6085.

This PR touches code that had Python < 3.5 compatibility leftovers
so I dropped them in a preceding commit to reduce churn.

Issues

Notes

Sibling to #3027

@Digenis

Digenis commented Aug 3, 2026

Copy link
Copy Markdown
Author

I misunderstood the contribution guidelines
and thought the workflows' success is needed before removing draft status.

It turns out that maintainers don't see the drafts' workflows queued for approval.

Removing draft status.

@Digenis
Digenis marked this pull request as ready for review August 3, 2026 08:55
@Digenis
Digenis requested a review from a team as a code owner August 3, 2026 08:55
Comment on lines +14 to +16
if sys.version_info >= (3, 14):
from inspect import iscoroutinefunction
else:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not re-use the shim we already have in Django?

# Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for
# inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker.
# The latter is replaced with the inspect.markcoroutinefunction decorator.
# Until 3.12 is the minimum supported Python version, provide a shim.
# This was copied from https://github.com/django/asgiref/blob/main/asgiref/sync.py
if hasattr(inspect, "markcoroutinefunction"):
iscoroutinefunction = inspect.iscoroutinefunction
markcoroutinefunction = inspect.markcoroutinefunction
else:
iscoroutinefunction = asyncio.iscoroutinefunction
def markcoroutinefunction(func: "_F") -> "_F":
func._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore
return func

@Digenis Digenis Aug 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asgi.py imports django.core.handlers.asgi which doesn't exist in django < 3

sentry supports django ≥ 1.8

views.py wraps the asgi import in a try/except block
suppressing the inner import error
caused by the missing module in django < 3
to keep django ≥ 1.8 compatibility

To rely on the shim
I have to redefine the other half of the conditional iscoroutinefunction definition
inside the try/except block
which defeats the purpose of using the shim.

The "conditional import" phrase in the asgi module docstring
was, and still is, misleading people
into imagining an import within an if block.

Maybe I should rephrase it, since I'm touching this sentence in the chore commit anyway.
Examples:

This module imports django.core.handlers.asgi (Django >= 3), so
sentry_sdk.integrations.django imports it via a guarded import that
handles ImportError on older Django versions.

This module is imported from sentry_sdk.integrations.django using
try/except to maintain compatibility with Django versions that do
not provide django.core.handlers.asgi.

Separate commit or fixup on chore(django): Drop Python < 3.5 compatibility ?

But this alone will not be enough to address the same misunderstanding in the future
so maybe a code comment too in views.py is needed.
It's obvious what the code does but not why it's here and not there.

Duplicated from asgi.py because that module is not importable on Django < 3.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough reply. We're not actually concerned about the

from django.core.handlers.asgi import ASGIRequest

import because it's in a type checking block. Our typing environment has newer package versions so there's no risk of ImportError for ASGIRequest.

Also, the except: block exists for Python 2 compatibility (see #851). We're not concerned about Python 2 any more, so we can remove the except : 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants