]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
use asyncio.run 1444/head
authorDavid Lord <davidism@gmail.com>
Tue, 18 May 2021 20:22:46 +0000 (13:22 -0700)
committerDavid Lord <davidism@gmail.com>
Tue, 18 May 2021 20:22:46 +0000 (13:22 -0700)
CHANGES.rst
docs/api.rst
src/jinja2/environment.py
tests/test_async.py

index a371b22675332fb4c60c8ca5ec4477e4c8e3ad80..fee54a16d22d78a93384da3cffc875afd5b25e38 100644 (file)
@@ -13,6 +13,9 @@ Unreleased
     extensions shows more relevant context. :issue:`1429`
 -   Fixed calling deprecated ``jinja2.Markup`` without an argument.
     Use ``markupsafe.Markup`` instead. :issue:`1438`
+-   Calling sync ``render`` for an async template uses ``asyncio.run``
+    on Python >= 3.7. This fixes a deprecation that Python 3.10
+    introduces. :issue:`1443`
 
 
 Version 3.0.0
index 127e2b85f7b75b4ce353d196dfbfada11f945a3a..9c6f3a1289ff2cab9df80b02717cbde4d1ac5e65 100644 (file)
@@ -513,12 +513,12 @@ handle async and sync code in an asyncio event loop. This has the
 following implications:
 
 -   Template rendering requires an event loop to be available to the
-    current thread. :func:`asyncio.get_event_loop` must return an event
-    loop.
+    current thread. :func:`asyncio.get_running_loop` must return an
+    event loop.
 -   The compiled code uses ``await`` for functions and attributes, and
     uses ``async for`` loops. In order to support using both async and
     sync functions in this context, a small wrapper is placed around
-    all calls and access, which add overhead compared to purely async
+    all calls and access, which adds overhead compared to purely async
     code.
 -   Sync methods and filters become wrappers around their corresponding
     async implementations where needed. For example, ``render`` invokes
index 9c173b25be3a253db132140765a8fb580df62e00..8a831db82fcde16b8a12698ee26205225c288b2a 100644 (file)
@@ -2,6 +2,7 @@
 options.
 """
 import os
+import sys
 import typing
 import typing as t
 import weakref
@@ -1278,8 +1279,22 @@ class Template:
         if self.environment.is_async:
             import asyncio
 
-            loop = asyncio.get_event_loop()
-            return loop.run_until_complete(self.render_async(*args, **kwargs))
+            close = False
+
+            if sys.version_info < (3, 7):
+                loop = asyncio.get_event_loop()
+            else:
+                try:
+                    loop = asyncio.get_running_loop()
+                except RuntimeError:
+                    loop = asyncio.new_event_loop()
+                    close = True
+
+            try:
+                return loop.run_until_complete(self.render_async(*args, **kwargs))
+            finally:
+                if close:
+                    loop.close()
 
         ctx = self.new_context(dict(*args, **kwargs))
 
@@ -1326,14 +1341,17 @@ class Template:
         if self.environment.is_async:
             import asyncio
 
-            loop = asyncio.get_event_loop()
-            async_gen = self.generate_async(*args, **kwargs)
+            async def to_list() -> t.List[str]:
+                return [x async for x in self.generate_async(*args, **kwargs)]
 
-            try:
-                while True:
-                    yield loop.run_until_complete(async_gen.__anext__())
-            except StopAsyncIteration:
-                return
+            if sys.version_info < (3, 7):
+                loop = asyncio.get_event_loop()
+                out = loop.run_until_complete(to_list())
+            else:
+                out = asyncio.run(to_list())
+
+            yield from out
+            return
 
         ctx = self.new_context(dict(*args, **kwargs))
 
index f8be8dfffab41aeea496043a428a702d05d92f62..e1c8d2345f9560f805097b7c742b4bf18b69b662 100644 (file)
@@ -1,4 +1,5 @@
 import asyncio
+import sys
 
 import pytest
 
@@ -13,9 +14,17 @@ from jinja2.exceptions import UndefinedError
 from jinja2.nativetypes import NativeEnvironment
 
 
-def run(coro):
-    loop = asyncio.get_event_loop()
-    return loop.run_until_complete(coro)
+if sys.version_info < (3, 7):
+
+    def run(coro):
+        loop = asyncio.get_event_loop()
+        return loop.run_until_complete(coro)
+
+
+else:
+
+    def run(coro):
+        return asyncio.run(coro)
 
 
 def test_basic_async():