Aio web server
Project description
Detailed documentation
**********************
aio.web.server
==============
Web server for the aio_ asyncio framework
.. _aio: https://github.com/phlax/aio
Build status
------------
.. image:: https://travis-ci.org/phlax/aio.web.server.svg?branch=master
:target: https://travis-ci.org/phlax/aio.web.server
Installation
------------
Install with:
.. code:: bash
pip install aio.web.server
Configuration
-------------
Example configuration for a hello world web page
.. code:: ini
[server/test]
factory = aio.web.server.factory
port = 8080
[web/test/page]
match = /
route = my.example.handler
And the corresponding route handler
.. code:: python
import asyncio
import aiohttp
@asyncio.coroutine
def handler(request):
return aiohttp.web.Response(body=b"Hello, web world")
Running
-------
Run with the aio command
.. code:: bash
aio run
aio.web.server usage
-------------
Configuration
-------------
Let's create a config defining a factory method and using the aio.web.server.protocol for the protocol
In the following configuration example a server named "example-1" is set up.
Any sections that start with "web/example-1/" will be treated as route definitions.
The route definition should provide a "match" and a "route" at a minimum.
The route is given a name derived from the section name. In this case "homepage"
>>> web_server_config = """
... [aio]
... log_level: ERROR
...
... [server/example]
... factory = aio.web.server.factory
... port = 7070
...
... [web/example/homepage]
... match = /
... route = aio.web.server.tests._example_handler
... """
>>> import asyncio
>>> import aiohttp
>>> import aio.web.server.tests
>>> from aio.app.runner import runner
>>> from aio.testing import aiofuturetest
>>> @asyncio.coroutine
... def handler(request):
... return aiohttp.web.Response(body=b"Hello, web world")
>>> aio.web.server.tests._example_handler = handler
>>> @aiofuturetest(sleep=1)
... def run_web_server(config, request_page="http://localhost:7070"):
... yield from runner(['run'], config_string=config)
...
... @asyncio.coroutine
... def call_web_server():
... result = yield from (
... yield from aiohttp.request(
... "GET", request_page)).read()
...
... print(result.decode())
...
... return call_web_server
>>> run_web_server(web_server_config)
Hello, web world
Accessing web apps
------------------
You can access a webapp by name
>>> import aio.web.server
>>> aio.web.server.apps['example']
<Application>
>>> aio.web.server.apps['example']['name']
'example'
Let's clear the web apps, this will also call aio.app.clear()
>>> aio.web.server.clear()
>>> aio.web.server.apps
{}
>>> print(aio.app.config, aio.app.signals)
None None
Static directory
----------------
The "web/" section takes a static_url and a static_dir option for hosting static files
>>> config_static = """
... [aio]
... log_level: ERROR
...
... [server/test]
... factory: aio.web.server.factory
... port: 7070
...
... [web/test]
... static_url: /static
... static_dir: %s
... """
>>> import os
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
... with open(os.path.join(tmp, "test.css"), 'w') as cssfile:
... res = cssfile.write("body {}")
...
... run_web_server(
... config_static % tmp,
... request_page="http://localhost:7070/static/test.css")
body {}
And clear up...
>>> aio.web.server.clear()
Routes, templates and fragments
-------------------------------
aio.web.server uses jinja2 templates under the hood
On setup aio searches the paths of modules listed in the aio:modules option for folders named "templates" and loads any templates it finds from there
>>> config_template = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-2]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-2/homepage]
... match = /
... route = aio.web.server.tests._example_route_handler
... """
Routes
~~~~~~
By decorating a function with @aio.web.server.route, the function is called with the request and the configuration for the route that is being handled
>>> @aio.web.server.route("test_template.html")
... def route_handler(request, config):
... return {
... 'message': 'Hello, world'}
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(config_template)
<html>
<body>
Hello, world
</body>
</html>
>>> aio.web.server.clear()
Templates
~~~~~~~~~
A route handler can defer to other templates, for example according to the path.
The @aio.web.server.route decorator does not require a template, but in that case the decorated function must return an aiohttp.web.StreamResponse object
A route always takes 2 arguments - request and config, a template can take any arguments that it requires
While you can use an @aio.web.template as a route handler, doing so would bypass the normal logging and request handling operations
>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /{path:.*}
... route = aio.web.server.tests._example_route_handler
... """
>>> @aio.web.server.template("test_template.html")
... def template_handler_1(request):
... return {'message': "Hello, world from template handler 1"}
>>> @aio.web.server.template("test_template.html")
... def template_handler_2(request):
... return {'message': "Hello, world from template handler 2"}
>>> @aio.web.server.route
... def route_handler(request, config):
...
... if request.path == "/path1":
... return (yield from template_handler_1(request))
...
... elif request.path == "/path2":
... return (yield from template_handler_2(request))
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path1")
<html>
<body>
Hello, world from template handler 1
</body>
</html>
>>> aio.web.server.clear()
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path2")
<html>
<body>
Hello, world from template handler 2
</body>
</html>
>>> aio.web.server.clear()
Fragments
~~~~~~~~~
Both routes and templates are expected to return a full html page, or an html response object.
Fragments render a snippet of code, and are not expected to return a full page.
Fragments cannot return an html response object, but can raise an html error if required
>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /
... route = aio.web.server.tests._example_route_handler
... """
>>> @aio.web.server.fragment("fragments/test_fragment.html")
... def fragment_handler(request, test_list):
... return {'test_list': test_list}
>>> @aio.web.server.template("test_template.html")
... def template_handler(request, test_list):
... return {'message': (yield from fragment_handler(request, test_list))}
>>> @aio.web.server.route
... def route_handler(request, config):
...
... return (yield from template_handler(request, ["foo", "bar", "baz"]))
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/")
<html>
<body>
<ul>
<li>foo</li><li>bar</li><li>baz</li>
</ul>
</body>
</html>
**********************
aio.web.server
==============
Web server for the aio_ asyncio framework
.. _aio: https://github.com/phlax/aio
Build status
------------
.. image:: https://travis-ci.org/phlax/aio.web.server.svg?branch=master
:target: https://travis-ci.org/phlax/aio.web.server
Installation
------------
Install with:
.. code:: bash
pip install aio.web.server
Configuration
-------------
Example configuration for a hello world web page
.. code:: ini
[server/test]
factory = aio.web.server.factory
port = 8080
[web/test/page]
match = /
route = my.example.handler
And the corresponding route handler
.. code:: python
import asyncio
import aiohttp
@asyncio.coroutine
def handler(request):
return aiohttp.web.Response(body=b"Hello, web world")
Running
-------
Run with the aio command
.. code:: bash
aio run
aio.web.server usage
-------------
Configuration
-------------
Let's create a config defining a factory method and using the aio.web.server.protocol for the protocol
In the following configuration example a server named "example-1" is set up.
Any sections that start with "web/example-1/" will be treated as route definitions.
The route definition should provide a "match" and a "route" at a minimum.
The route is given a name derived from the section name. In this case "homepage"
>>> web_server_config = """
... [aio]
... log_level: ERROR
...
... [server/example]
... factory = aio.web.server.factory
... port = 7070
...
... [web/example/homepage]
... match = /
... route = aio.web.server.tests._example_handler
... """
>>> import asyncio
>>> import aiohttp
>>> import aio.web.server.tests
>>> from aio.app.runner import runner
>>> from aio.testing import aiofuturetest
>>> @asyncio.coroutine
... def handler(request):
... return aiohttp.web.Response(body=b"Hello, web world")
>>> aio.web.server.tests._example_handler = handler
>>> @aiofuturetest(sleep=1)
... def run_web_server(config, request_page="http://localhost:7070"):
... yield from runner(['run'], config_string=config)
...
... @asyncio.coroutine
... def call_web_server():
... result = yield from (
... yield from aiohttp.request(
... "GET", request_page)).read()
...
... print(result.decode())
...
... return call_web_server
>>> run_web_server(web_server_config)
Hello, web world
Accessing web apps
------------------
You can access a webapp by name
>>> import aio.web.server
>>> aio.web.server.apps['example']
<Application>
>>> aio.web.server.apps['example']['name']
'example'
Let's clear the web apps, this will also call aio.app.clear()
>>> aio.web.server.clear()
>>> aio.web.server.apps
{}
>>> print(aio.app.config, aio.app.signals)
None None
Static directory
----------------
The "web/" section takes a static_url and a static_dir option for hosting static files
>>> config_static = """
... [aio]
... log_level: ERROR
...
... [server/test]
... factory: aio.web.server.factory
... port: 7070
...
... [web/test]
... static_url: /static
... static_dir: %s
... """
>>> import os
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
... with open(os.path.join(tmp, "test.css"), 'w') as cssfile:
... res = cssfile.write("body {}")
...
... run_web_server(
... config_static % tmp,
... request_page="http://localhost:7070/static/test.css")
body {}
And clear up...
>>> aio.web.server.clear()
Routes, templates and fragments
-------------------------------
aio.web.server uses jinja2 templates under the hood
On setup aio searches the paths of modules listed in the aio:modules option for folders named "templates" and loads any templates it finds from there
>>> config_template = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-2]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-2/homepage]
... match = /
... route = aio.web.server.tests._example_route_handler
... """
Routes
~~~~~~
By decorating a function with @aio.web.server.route, the function is called with the request and the configuration for the route that is being handled
>>> @aio.web.server.route("test_template.html")
... def route_handler(request, config):
... return {
... 'message': 'Hello, world'}
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(config_template)
<html>
<body>
Hello, world
</body>
</html>
>>> aio.web.server.clear()
Templates
~~~~~~~~~
A route handler can defer to other templates, for example according to the path.
The @aio.web.server.route decorator does not require a template, but in that case the decorated function must return an aiohttp.web.StreamResponse object
A route always takes 2 arguments - request and config, a template can take any arguments that it requires
While you can use an @aio.web.template as a route handler, doing so would bypass the normal logging and request handling operations
>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /{path:.*}
... route = aio.web.server.tests._example_route_handler
... """
>>> @aio.web.server.template("test_template.html")
... def template_handler_1(request):
... return {'message': "Hello, world from template handler 1"}
>>> @aio.web.server.template("test_template.html")
... def template_handler_2(request):
... return {'message': "Hello, world from template handler 2"}
>>> @aio.web.server.route
... def route_handler(request, config):
...
... if request.path == "/path1":
... return (yield from template_handler_1(request))
...
... elif request.path == "/path2":
... return (yield from template_handler_2(request))
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path1")
<html>
<body>
Hello, world from template handler 1
</body>
</html>
>>> aio.web.server.clear()
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path2")
<html>
<body>
Hello, world from template handler 2
</body>
</html>
>>> aio.web.server.clear()
Fragments
~~~~~~~~~
Both routes and templates are expected to return a full html page, or an html response object.
Fragments render a snippet of code, and are not expected to return a full page.
Fragments cannot return an html response object, but can raise an html error if required
>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /
... route = aio.web.server.tests._example_route_handler
... """
>>> @aio.web.server.fragment("fragments/test_fragment.html")
... def fragment_handler(request, test_list):
... return {'test_list': test_list}
>>> @aio.web.server.template("test_template.html")
... def template_handler(request, test_list):
... return {'message': (yield from fragment_handler(request, test_list))}
>>> @aio.web.server.route
... def route_handler(request, config):
...
... return (yield from template_handler(request, ["foo", "bar", "baz"]))
>>> aio.web.server.tests._example_route_handler = route_handler
>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/")
<html>
<body>
<ul>
<li>foo</li><li>bar</li><li>baz</li>
</ul>
</body>
</html>
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
aio.web.server-0.0.3.tar.gz
(7.5 kB
view details)
File details
Details for the file aio.web.server-0.0.3.tar.gz
.
File metadata
- Download URL: aio.web.server-0.0.3.tar.gz
- Upload date:
- Size: 7.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3134fcd3bc4d567916dd7f5dda45aca0df38066ae293bf0fc5262cb4f82fe158 |
|
MD5 | c35e16217f9e698458b5d9e22cb66c51 |
|
BLAKE2b-256 | d8160d6d2db38da6e82fdcc7d161a07b974a40de0952e6480e86f36b12938fde |