asyncio.py 1.1 KB

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