This is a pre-production deployment of Warehouse. Changes made here affect the production instance of PyPI (pypi.python.org).
Help us improve Python packaging - Donate today!
Project Description

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>
Release History

Release History

0.1.0

This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.7

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.6

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.5

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.4

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.3

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.2

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

0.0.1

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Download Files

Download Files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
aio.web.page-0.1.0.tar.gz (7.4 kB) Copy SHA256 Checksum SHA256 Source May 24, 2015

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting