asyncio.py 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. import asyncio
  2. import functools
  3. import os
  4. from django.core.exceptions import SynchronousOnlyOperation
  5. from django.utils.version import PY37
  6. if PY37:
  7. get_running_loop = asyncio.get_running_loop
  8. else:
  9. get_running_loop = asyncio.get_event_loop
  10. def async_unsafe(message):
  11. """
  12. Decorator to mark functions as async-unsafe. Someone trying to access
  13. the function while in an async context will get an error message.
  14. """
  15. def decorator(func):
  16. @functools.wraps(func)
  17. def inner(*args, **kwargs):
  18. if not os.environ.get('DJANGO_ALLOW_ASYNC_UNSAFE'):
  19. # Detect a running event loop in this thread.
  20. try:
  21. event_loop = get_running_loop()
  22. except RuntimeError:
  23. pass
  24. else:
  25. if PY37 or event_loop.is_running():
  26. raise SynchronousOnlyOperation(message)
  27. # Pass onwards.
  28. return func(*args, **kwargs)
  29. return inner
  30. # If the message is actually a function, then be a no-arguments decorator.
  31. if callable(message):
  32. func = message
  33. message = 'You cannot call this from an async context - use a thread or sync_to_async.'
  34. return decorator(func)
  35. else:
  36. return decorator