When code must run async coroutines from a synchronous context (or vice versa), be deliberate about correctness, extensibility, and dependency handling:
functools.partial wrappers before testing, since inspect.iscoroutinefunction can give false negatives otherwise:
def iscoroutinefunction(func):
while inspect.ismethod(func):
func = func.__func__
while isinstance(func, functools.partial):
func = func.func
return inspect.iscoroutinefunction(func)
Prefer using the standard library’s version when available instead of reintroducing a compatibility shim.
Make the actual async-to-sync execution step an overridable hook (e.g. a dedicated async_to_sync method) rather than baking the conversion logic into a larger dispatch method. This lets users swap in alternate event-loop/runner implementations without duplicating the coroutine-detection boilerplate.
asgiref) as an optional dependency. Import it lazily inside the function that needs it and raise a clear, actionable error if it’s missing, rather than requiring it unconditionally:
try:
import asgiref
except ImportError:
raise RuntimeError("Install asgiref in order to run async views.")
for blueprint, bp_options in self._blueprints:
bp_options = bp_options.copy() # avoid mutating shared state
Applying these practices keeps async/sync bridges correct across wrapped callables, extensible for custom runners, dependency-light for users who don’t need async, and free of subtle bugs caused by shared mutable state across repeated registrations or invocations.</description> </invoke>