summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2021-05-18 13:31:11 -0700
committerGitHub <noreply@github.com>2021-05-18 13:31:11 -0700
commit77674b9dfb56985f794bb7957a4253151b2c3d86 (patch)
tree74ea646fb8be8d89dbd6ff8ba65123c023359a75
parent94a6423a7710959912bde61d16d88d353b3312bb (diff)
parent7d0b7accff32e0ce9889fb8b81320917451b8454 (diff)
downloadjinja2-77674b9dfb56985f794bb7957a4253151b2c3d86.tar.gz
Merge pull request #1444 from pallets/event-loop
use asyncio.run
-rw-r--r--CHANGES.rst3
-rw-r--r--docs/api.rst6
-rw-r--r--src/jinja2/environment.py36
-rw-r--r--tests/test_async.py15
4 files changed, 45 insertions, 15 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index a371b22..fee54a1 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -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
diff --git a/docs/api.rst b/docs/api.rst
index 127e2b8..9c6f3a1 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -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
diff --git a/src/jinja2/environment.py b/src/jinja2/environment.py
index 9c173b2..8a831db 100644
--- a/src/jinja2/environment.py
+++ b/src/jinja2/environment.py
@@ -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))
diff --git a/tests/test_async.py b/tests/test_async.py
index f8be8df..e1c8d23 100644
--- a/tests/test_async.py
+++ b/tests/test_async.py
@@ -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():