summaryrefslogtreecommitdiff
path: root/django/utils/asyncio.py
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2019-04-12 06:15:18 -0700
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-06-20 12:29:43 +0200
commita415ce70bef6d91036b00dd2c8544aed7aeeaaed (patch)
tree3583cef22e9b56d2ed52456ab586d9c47620bc51 /django/utils/asyncio.py
parentcce47ff65a4dd3786c049ec14ee889e128ca7de9 (diff)
downloaddjango-a415ce70bef6d91036b00dd2c8544aed7aeeaaed.tar.gz
Fixed #30451 -- Added ASGI handler and coroutine-safety.
This adds an ASGI handler, asgi.py file for the default project layout, a few async utilities and adds async-safety to many parts of Django.
Diffstat (limited to 'django/utils/asyncio.py')
-rw-r--r--django/utils/asyncio.py32
1 files changed, 32 insertions, 0 deletions
diff --git a/django/utils/asyncio.py b/django/utils/asyncio.py
new file mode 100644
index 0000000000..c4de04ba12
--- /dev/null
+++ b/django/utils/asyncio.py
@@ -0,0 +1,32 @@
+import asyncio
+import functools
+
+from django.core.exceptions import SynchronousOnlyOperation
+
+
+def async_unsafe(message):
+ """
+ Decorator to mark functions as async-unsafe. Someone trying to access
+ the function while in an async context will get an error message.
+ """
+ def decorator(func):
+ @functools.wraps(func)
+ def inner(*args, **kwargs):
+ # Detect a running event loop in this thread.
+ try:
+ event_loop = asyncio.get_event_loop()
+ except RuntimeError:
+ pass
+ else:
+ if event_loop.is_running():
+ raise SynchronousOnlyOperation(message)
+ # Pass onwards.
+ return func(*args, **kwargs)
+ return inner
+ # If the message is actually a function, then be a no-arguments decorator.
+ if callable(message):
+ func = message
+ message = 'You cannot call this from an async context - use a thread or sync_to_async.'
+ return decorator(func)
+ else:
+ return decorator