From 57f0968470d214ffac8cbb89088b2ab517356264 Mon Sep 17 00:00:00 2001 From: Steven Loria Date: Mon, 26 Oct 2015 23:55:04 -0400 Subject: [PATCH] Add mako rendering example and link to examples in docs --- docs/index.rst | 11 +++-- examples/mako_example.py | 93 ++++++++++++++++++++++++++++++++++++++++ tests/test_examples.py | 23 ++++++++++ 3 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 examples/mako_example.py diff --git a/docs/index.rst b/docs/index.rst index 995fe39..98d2960 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -49,15 +49,18 @@ Release v\ |version|. (:ref:`Changelog `) ) Install -======= +------- :: $ pip install aiohttp_utils -Utilities ---------- -Below is a listing of available utility modules. +**Ready to get started?** Go on to one of the the usage guides below or check out some `examples `_. + +Guides +------ + +Below are usage guides for each of the modules. .. toctree:: :maxdepth: 1 diff --git a/examples/mako_example.py b/examples/mako_example.py new file mode 100644 index 0000000..e37718b --- /dev/null +++ b/examples/mako_example.py @@ -0,0 +1,93 @@ +"""Example of using content negotiation to support HTML representations, using +Mako for templating. Also demonstrates app configuration. + +Start the app with +:: + $ pip install mako + $ python examples/mako_example.py + +Try it out: +:: + + $ pip install httpie + $ http :8000/ Accept:application/json + $ http :8000/ Accept:text/html +""" +from collections import OrderedDict, Mapping +from asyncio import coroutine + +from aiohttp import web +from aiohttp_utils import Response, negotiation, run + +from mako.lookup import TemplateLookup + +##### Templates ##### + +lookup = TemplateLookup() +# Note: In a real app, this would be in a file. +template = """ + + +

${message}

+ + +""" +lookup.put_string('index.html', template) + +##### Handlers ##### + +@coroutine +def index(request): + return Response({ + 'message': 'Hello ' + request.GET.get('name', 'World') + }) + +##### Custom router ##### + +class RoutingWithTemplating(web.UrlDispatcher): + """Optionally save a template name on a handler function's __dict__.""" + + def add_route(self, method, path, handler, template: str=None, **kwargs): + if template: + handler.__dict__['template'] = template + super().add_route(method, path, handler, **kwargs) + +##### Renderer ##### + +def render_mako(request, data, handler): + template_name = handler.__dict__.get('template', None) + if not template_name: + raise web.HTTPNotAcceptable(text='text/html not supported.') + if not isinstance(data, Mapping): + raise web.HTTPInternalServerError( + text="context should be mapping, not {}".format(type(data))) + template = request.app['mako_lookup'].get_template(template_name) + text = template.render_unicode(**data) + return web.Response(text=text, content_type=request['selected_media_type']) + +##### Configuration ##### + +CONFIG = { + 'AIOHTTP_UTILS': { + 'RENDERERS': OrderedDict([ + ('application/json', negotiation.render_json), + ('text/html', render_mako), + ]) + } +} + +##### Application ##### + +app = web.Application(router=RoutingWithTemplating(), debug=True) +app['mako_lookup'] = lookup +app.update(CONFIG) +negotiation.setup(app) +app.router.add_route('GET', '/', index, template='index.html') + +if __name__ == "__main__": + run( + app, + app_uri='examples.mako_example:app', + reload=True, + port=8000, + ) diff --git a/tests/test_examples.py b/tests/test_examples.py index 7ff8e7b..d90c2f8 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -2,6 +2,7 @@ import pytest from examples.kitchen_sink import app as kitchen_sink_app +from examples.mako_example import app as mako_app class TestKitchenSinkApp: @@ -34,3 +35,25 @@ def test_api_index_merge_slashes(self, client): assert res.status_code == 200 assert res.request.path == '/api/' +class TestMakoApp: + + @pytest.fixture() + def client(self, loop, create_client): + mako_app._loop = loop + return create_client(mako_app) + + def test_json_request(self, client): + res = client.get('/', headers={'Accept': 'application/json'}) + assert res.content_type == 'application/json' + assert res.json == {'message': 'Hello World'} + + def test_json_request_with_query_params(self, client): + res = client.get('/?name=Ada', headers={'Accept': 'application/json'}) + assert res.content_type == 'application/json' + assert res.json == {'message': 'Hello Ada'} + + def test_html_request(self, client): + res = client.get('/', headers={'Accept': 'text/html'}) + assert res.status_code == 200 + assert res.content_type == 'text/html' + assert res.html.find('h1').text == 'Hello World'