Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async rendering support #393

Merged
merged 30 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cf57c42
Expand typing to tests.
Dreamsorcerer Oct 31, 2020
b4a83ba
Line wrapping
Dreamsorcerer Oct 31, 2020
bbe4732
Unused imports
Dreamsorcerer Oct 31, 2020
8b01b2f
Merge branch 'master' into master
asvetlov Oct 31, 2020
790070d
TypedDict only for 3.8+
Dreamsorcerer Oct 31, 2020
df416b2
Spacing
Dreamsorcerer Oct 31, 2020
6f431f5
...Github...
Dreamsorcerer Oct 31, 2020
396047e
Merge branch 'master' into master
asvetlov Nov 1, 2020
fdcfe9e
Make query_ a proper keyword argument.
Dreamsorcerer Nov 3, 2020
d8445d6
Wrapping
Dreamsorcerer Nov 3, 2020
10e16f4
Fix typing of wrapper.
Dreamsorcerer Nov 3, 2020
2d8feab
Wrapping
Dreamsorcerer Nov 3, 2020
3f439a2
Unused import.
Dreamsorcerer Nov 3, 2020
d7d6fd1
Merge branch 'master' into master
Dreamsorcerer Nov 3, 2020
81481c3
Revert positional parameters.
Dreamsorcerer Nov 3, 2020
8b639da
Protcol only in Python 3.8+
Dreamsorcerer Nov 3, 2020
6f3637a
Wrapping
Dreamsorcerer Nov 3, 2020
3b1178f
Fix fallback.
Dreamsorcerer Nov 3, 2020
9ab8065
Fix fallback.
Dreamsorcerer Nov 3, 2020
b920fd2
Fix typing of wrapper.
Dreamsorcerer Nov 7, 2020
1728574
Fix typing of wrapper.
Dreamsorcerer Nov 7, 2020
13aea24
Line wrapping.
Dreamsorcerer Nov 7, 2020
1e8206d
Comma.
Dreamsorcerer Nov 7, 2020
f4f7c2a
Add async rendering.
Dreamsorcerer Nov 7, 2020
9636c4a
Add tests for async.
Dreamsorcerer Nov 7, 2020
f3b112a
Line wrapping.
Dreamsorcerer Nov 7, 2020
0756023
Comma.
Dreamsorcerer Nov 7, 2020
a4e6b07
Merge master.
Dreamsorcerer Nov 8, 2020
a4dedbb
Merge branch 'master' into async
Dreamsorcerer Nov 8, 2020
61295a2
Fix mypy.
Dreamsorcerer Nov 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ disallow_any_unimported = True
warn_return_any = True

[mypy-tests.*]
disallow_any_decorated = False
disallow_untyped_calls = False
disallow_untyped_defs = False
83 changes: 67 additions & 16 deletions aiohttp_jinja2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
Iterable,
Mapping,
Optional,
Tuple,
TypeVar,
Union,
cast,
Expand Down Expand Up @@ -97,13 +98,12 @@ def get_env(app: web.Application, *, app_key: str = APP_KEY) -> jinja2.Environme
return cast(jinja2.Environment, app.get(app_key))


def render_string(
def _render_string(
template_name: str,
request: web.Request,
context: Mapping[str, Any],
*,
app_key: str = APP_KEY,
) -> str:
app_key: str,
) -> Tuple[jinja2.Template, Mapping[str, Any]]:
env = request.config_dict.get(app_key)
if env is None:
text = (
Expand All @@ -126,26 +126,71 @@ def render_string(
raise web.HTTPInternalServerError(reason=text, text=text)
if request.get(REQUEST_CONTEXT_KEY):
context = dict(request[REQUEST_CONTEXT_KEY], **context)
text = template.render(context)
return text
return template, context


def render_template(
def render_string(
template_name: str,
request: web.Request,
context: Optional[Mapping[str, Any]],
context: Mapping[str, Any],
*,
app_key: str = APP_KEY,
encoding: str = "utf-8",
status: int = 200,
) -> web.Response:
) -> str:
template, context = _render_string(template_name, request, context, app_key)
return template.render(context)


async def render_string_async(
template_name: str,
request: web.Request,
context: Mapping[str, Any],
*,
app_key: str = APP_KEY,
) -> str:
template, context = _render_string(template_name, request, context, app_key)
return await template.render_async(context)


def _render_template(
context: Optional[Mapping[str, Any]],
encoding: str,
status: int,
) -> Tuple[web.Response, Mapping[str, Any]]:
response = web.Response(status=status)
if context is None:
context = {}
text = render_string(template_name, request, context, app_key=app_key)
response.content_type = "text/html"
response.charset = encoding
response.text = text
return response, context


def render_template(
template_name: str,
request: web.Request,
context: Optional[Mapping[str, Any]],
*,
app_key: str = APP_KEY,
encoding: str = "utf-8",
status: int = 200,
) -> web.Response:
response, context = _render_template(context, encoding, status)
response.text = render_string(template_name, request, context, app_key=app_key)
return response


async def render_template_async(
template_name: str,
request: web.Request,
context: Optional[Mapping[str, Any]],
*,
app_key: str = APP_KEY,
encoding: str = "utf-8",
status: int = 200,
) -> web.Response:
response, context = _render_template(context, encoding, status)
response.text = await render_string_async(
template_name, request, context, app_key=app_key
)
return response


Expand Down Expand Up @@ -197,9 +242,15 @@ async def wrapped(*args: Any) -> web.StreamResponse:
else:
request = args[-1]

response = render_template(
template_name, request, context, app_key=app_key, encoding=encoding
)
env = request.config_dict.get(app_key)
if env and env.is_async:
response = await render_template_async(
template_name, request, context, app_key=app_key, encoding=encoding
)
else:
response = render_template(
template_name, request, context, app_key=app_key, encoding=encoding
)
response.set_status(status)
return response

Expand Down
40 changes: 31 additions & 9 deletions tests/test_simple_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
_T = TypeVar("_T")


async def test_func(aiohttp_client):
@pytest.mark.parametrize("enable_async", (False, True))
async def test_func(aiohttp_client, enable_async):
@aiohttp_jinja2.template("tmpl.jinja2")
async def func(request: web.Request) -> Dict[str, str]:
return {"head": "HEAD", "text": "text"}

template = "<html><body><h1>{{head}}</h1>{{text}}</body></html>"
app = web.Application()
aiohttp_jinja2.setup(app, loader=jinja2.DictLoader({"tmpl.jinja2": template}))
aiohttp_jinja2.setup(
app,
enable_async=enable_async,
loader=jinja2.DictLoader({"tmpl.jinja2": template}),
)

app.router.add_route("*", "/", func)

Expand Down Expand Up @@ -137,16 +142,15 @@ async def func(request):
assert "<html><body><h1>HEAD</h1>text</body></html>" == txt


async def test_render_template(aiohttp_client):
async def func(request):
return aiohttp_jinja2.render_template(
"tmpl.jinja2", request, {"head": "HEAD", "text": "text"}
)

async def _test_render_template(func, aiohttp_client, enable_async):
template = "<html><body><h1>{{head}}</h1>{{text}}</body></html>"

app = web.Application()
aiohttp_jinja2.setup(app, loader=jinja2.DictLoader({"tmpl.jinja2": template}))
aiohttp_jinja2.setup(
app,
enable_async=enable_async,
loader=jinja2.DictLoader({"tmpl.jinja2": template}),
)

app.router.add_route("*", "/", func)

Expand All @@ -159,6 +163,24 @@ async def func(request):
assert "<html><body><h1>HEAD</h1>text</body></html>" == txt


async def test_render_template(aiohttp_client):
async def func(request):
return aiohttp_jinja2.render_template(
"tmpl.jinja2", request, {"head": "HEAD", "text": "text"}
)

await _test_render_template(func, aiohttp_client, enable_async=False)


async def test_render_template_async(aiohttp_client):
async def func(request):
return await aiohttp_jinja2.render_template_async(
"tmpl.jinja2", request, {"head": "HEAD", "text": "text"}
)

await _test_render_template(func, aiohttp_client, enable_async=True)


async def test_render_template_custom_status(aiohttp_client):
async def func(request):
return aiohttp_jinja2.render_template(
Expand Down