Web page templates for the aio asyncio framework
Build status
Installation
Requires python >= 3.4
Install with:
pip install aio.web.page
Quick start - hello world web page
Save the following into a file “hello.conf”
[aio]
modules = aio.web.server
[server/my_server]
factory = aio.web.server.factory
port = 8080
[web/my_server]
template_dirs = templates
[web/my_server/my_route]
match = /
route = my_example.route_handler
And save the following into a file named “my_example.py”
import aio.web.page
import aio.web.server
@aio.web.page.template('example_page.html')
def template_handler(request):
return {"message": "Hello template world"}
@aio.web.server.route
def route_handler(request, config):
return (yield from template_handler(request))
And the following into a file named “templates/example_page.html”
<html>
<body>
{{ message }}
</body>
</html>
Run with the aio run command
aio run -c hello.conf
aio.web.page usage
aio.web.page provides templates and fragments for building web pages
Lets set up a test to run a server and request a web page
>>> from aio.app.runner import runner >>> import aio.testing >>> import aiohttp
>>> @aio.testing.run_forever(sleep=1) ... def run_web_server(config, request_page="http://localhost:7070"): ... yield from runner(['run'], config_string=config) ... ... def call_web_server(): ... result = yield from ( ... yield from aiohttp.request( ... "GET", request_page)).read() ... aio.web.server.clear() ... ... print(result.decode()) ... ... return call_web_server
Templates
An @aio.web.server.route handler can defer to other templates, for example according to the matched path.
>>> example_config = """
... [aio]
... log_level = CRITICAL
... modules = aio.web.server
... aio.web.server.tests
...
... [server/server_name]
... factory: aio.web.server.factory
... port: 7070
...
... [web/server_name/route_name]
... match = /{path:.*}
... route = aio.web.page.tests._example_route_handler
... """
Lets create a couple of template handlers
>>> import aio.web.page
>>> @aio.web.page.template("test_template.html")
... def template_handler_1(request):
... return {
... 'message': "Hello, world from template handler 1"}
Template handlers can return a response object, in which case the template is not rendered
>>> @aio.web.page.template("test_template.html")
... def template_handler_2(request):
... return aiohttp.web.Response(
... body=b"Hello, world from template handler 2")
And lets set up a route handler which will defer to a template accordingly
>>> import aio.web.server
>>> @aio.web.server.route ... def route_handler(request, config): ... path = request.match_info['path'] ... ... if path == "path1": ... return (yield from template_handler_1(request)) ... ... elif path == "path2": ... return (yield from template_handler_2(request)) ... ... raise aiohttp.web.HTTPNotFound
And make it importable
>>> import aio.web.page.tests >>> aio.web.page.tests._example_route_handler = route_handler
Calling the server at /path1 we get the templated handler
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path1")
<html>
<body>
Hello, world from template handler 1
</body>
</html>
And calling on /path2 we get the response without the template
>>> run_web_server( ... example_config, ... request_page="http://localhost:7070/path2") Hello, world from template handler 2
Templates must always specify a template, even if they dont use it
>>> try:
... @aio.web.page.template
... def template_handler(request, test_list):
... return {'test_list': test_list}
... except Exception as e:
... print(repr(e))
TypeError('Template decorator must specify template: <function template_handler ...>',)
Templates can take arbitrary arguments
>>> @aio.web.page.template("test_template.html")
... def template_handler(request, foo, bar):
... return {
... 'message': "Hello, world with %s and %s" % (foo, bar)}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request, "spam", "tuesday"))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
Hello, world with spam and tuesday
</body>
</html>
The first argument to a template should always be a request object
>>> @aio.web.page.template("test_template.html")
... def template_handler(foo, bar):
... return {
... 'message': "Hello, world with %s and %s" % (foo, bar)}
>>> @aio.web.server.route
... def route_handler(request, config):
... try:
... return (yield from(template_handler("spam", "tuesday")))
... except TypeError as e:
... return aiohttp.web.Response(body=repr(e).encode())
>>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
TypeError("Template handler (<function template_handler at ...>) should be called with a request object, got: <class 'str'> spam",)
Fragments
Fragments render a snippet of html for embedding in other templates.
Fragments can specify a template and return a context object to render it with
A fragment can take an arbitrary number of arguments
>>> @aio.web.page.fragment("fragments/test_fragment.html")
... def fragment_handler(request, foo, bar):
... return {"test_list": [foo, bar]}
>>> @aio.web.page.template("test_template.html")
... def template_handler(request):
... return {'message': (yield from fragment_handler(request, "eggs", "thursday"))}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
<ul>
<li>eggs</li><li>thursday</li>
</ul>
</body>
</html>
The first argument to a fragment should always be an aiohttp.web.Request object
>>> @aio.web.page.fragment("fragments/test_fragment.html")
... def fragment_handler(foo, bar):
... return {"test_list": [foo, bar]}
>>> @aio.web.page.template("test_template.html")
... def template_handler(request):
... try:
... message = (yield from(fragment_handler("eggs", "thursday")))
... except Exception as e:
... message = repr(e)
... return {'message': message}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
TypeError("Fragment handler (<function fragment_handler ...>) should be called with a request object, got: <class 'str'> eggs",)
</body>
</html>
Fragments do not need to specify a template
>>> @aio.web.page.fragment ... def fragment_handler(request): ... return "Hello from fragment"
>>> @aio.web.page.template("test_template.html")
... def template_handler(request):
... return {'message': (yield from fragment_handler(request))}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
Hello from fragment
</body>
</html>
If a fragment doesnt specify a template, it must return a string
>>> @aio.web.page.fragment
... def fragment_handler(request):
... return {"foo": "bar"}
>>> @aio.web.page.template("test_template.html")
... def template_handler(request):
... try:
... fragment = yield from fragment_handler(request)
... except Exception as e:
... fragment = repr(e)
... return {'message': fragment}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
TypeError('Fragment handler (<function fragment_handler at ...>) should specify a template or return a string',)
</body>
</html>
Fragments should only return strings or context dictionaries, and should not return an aiohttp.web.Response object.
>>> @aio.web.page.fragment("fragments/test_fragment.html")
... def fragment_handler(request):
... return aiohttp.web.Response(body=b"Fragments should not return Response objects")
>>> @aio.web.page.template("test_template.html")
... def template_handler(request):
... try:
... fragment = yield from fragment_handler(request)
... except Exception as e:
... fragment = repr(e)
... return {'message': fragment}
>>> @aio.web.server.route ... def route_handler(request, config): ... return (yield from(template_handler(request))) >>> aio.web.page.tests._example_route_handler = route_handler
>>> run_web_server(example_config)
<html>
<body>
TypeError("Fragment handler (<function fragment_handler ...>) should return a string or context dictionary, got: <class 'aiohttp.web_reqrep.Response'> <Response OK not started>",)
</body>
</html>
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file aio.web.page-0.1.0.tar.gz.
File metadata
- Download URL: aio.web.page-0.1.0.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b44ea633143d6eccf30c446a0cb390cdc2af6b5d60ddf72ab061a63e2739899d
|
|
| MD5 |
2b498a3e3bae317198e0895bf9edc039
|
|
| BLAKE2b-256 |
4de5c7caee4398b8d4dbb668a20ccf8476da5b607399138fb7fe36cfec5d4b42
|