Skip to main content

werkzeug + twisted.web

Project description

Build Status

Klein is a micro-framework for developing production ready web services with python. It is ‘micro’ in that it has an incredibly small API similar to bottle and flask. It is not ‘micro’ in that it depends on things outside the standard library. This is primarily because it is built on widely used and well tested components like werkzeug and Twisted.

A Klein bottle is an example of a non-orientable surface, and a glass Klein bottle looks like a twisted bottle or twisted flask. This, of course, made it too good of a pun to pass up.

Examples

Here are some basic klein handler functions that return some strings.

from klein import run, route

@route('/')
def home(request):
    return 'Hello, world!'

run("localhost", 8080)

Static files

Helpfully you can also return a twisted.web.resource.IResource such as static.File. If the branch=True is passed to route the returned IResource will also be allowed to handle all children path segments. So http://localhost:8080/static/img.gif should return an image and http://localhost:8080/static/ should return a directory listing.

from twisted.web.static import File
from klein import run, route

@route('/static/', branch=True)
def static(request):
    return File("./static")

@route('/')
def home(request):
    return '<img src="/static/img.gif">'

run("localhost", 8080)

Templates

You can also make easy use of twisted.web.templates by returning anything that implements twisted.web.template.IRenderable such as twisted.web.template.Element in which case the template will be rendered and the result will be sent as the response body.

from twisted.web.template import Element, XMLString, renderer
from klein import run, route

class HelloElement(Element):
    loader = XMLString((
        '<h1 '
        'xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1"'
        '>Hello, <span t:render="name"></span>!</h1>'))

    def __init__(self, name):
        self._name = name

    @renderer
    def name(self, request, tag):
        return self._name


@route('/hello/<string:name>')
def home(request, name='world'):
    return HelloElement(name)

run("localhost", 8080)

Deferreds

And of course, this is twisted. So there is a wealth of APIs that return a twisted.internet.defer.Deferred. A Deferred may also be returned from handler functions and their result will be used as the response body.

Here is a simple Google proxy.

from twisted.web.client import getPage
from klein import run, route

@route('/')
def google(request):
    return getPage('https://www.google.com' + request.uri)


run("localhost", 8080)

twistd

Another very important integration point with Twisted is the twistd application runner. It provides rich logging support, daemonization, reactor selection, profiler integration, and many more incredibly useful features.

To provide access to these features (and others like HTTPS) klein provides the resource function which returns a valid twisted.web.resource.IResource for your application.

Here is our “Hello, World!” application again in a form that can be launched by twistd.

from klein import resource, route

@route('/')
def hello(request):
    return "Hello, world!"

To run the above application we can save it as helloworld.py and use the twistd web plugin.

twistd -n web --class=helloworld.resource

Handling POST

The route decorator supports a methods keyword which is the list of HTTP methods as strings. For example methods=['POST'] will cause the handler to be invoked when an POST request is received. If a handler can support multiple methods the current method can be distinguished with request.method.

Here is our "Hello, world!" example extended to support setting the name we are saying Hello to via a POST request with a name argument.

This also demonstrates the use of the redirect method of the request to redirect back to '/' after handling the POST.

The most specific handler should be defined first. So the POST handler must be defined before the handler with no methods.

from twisted.internet.defer import succeed
from klein import run, route

name='world'

@route('/', methods=['POST'])
def setname(request):
    global name
    name = request.args.get('name', ['world'])[0]
    request.redirect('/')
    return succeed(None)

@route('/')
def hello(request):
    return "Hello, {0}!".format(name)

run("localhost", 8080)

The following curl command can be used to test this behaviour:

curl -v -L -d name='bob' http://localhost:8080/

Non-global state

For obvious reasons it may be desirable for your application to have some non-global state that is used by the your route handlers.

Below we have created a simple ItemStore class that has an instance of Klein as a class variable app. We can now use @app.route to decorate the methods of the class.

import json

from klein import Klein


class ItemStore(object):
    app = Klein()

    def __init__(self):
        self._items = {}

    @app.route('/')
    def items(self, request):
        request.setHeader('Content-Type', 'application/json')
        return json.dumps(self._items)

    @app.route('/<string:name>', methods=['PUT'])
    def save_item(self, request, name):
        request.setHeader('Content-Type', 'application/json')
        body = json.loads(request.content.read())
        self._items[name] = body
        return json.dumps({'success': True})

    @app.route('/<string:name>', methods=['GET'])
    def get_item(self, request, name):
        request.setHeader('Content-Type', 'application/json')
        return json.dumps(self._items.get(name))


if __name__ == '__main__':
    store = ItemStore()
    store.app.run('localhost', 8080)

Project details


Download files

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

Source Distribution

klein-0.2.3.tar.gz (15.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

klein-0.2.3-py27-none-any.whl (19.5 kB view details)

Uploaded Python 2.7

File details

Details for the file klein-0.2.3.tar.gz.

File metadata

  • Download URL: klein-0.2.3.tar.gz
  • Upload date:
  • Size: 15.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for klein-0.2.3.tar.gz
Algorithm Hash digest
SHA256 31ed2b8fd92a379a62d532c3ed75fd1a83af1405ca7de243793c35323b82e2aa
MD5 0aec7a0c1e373ea3e994b1266cf5281f
BLAKE2b-256 b8ebeb289cc571bd9215dea13de181201d5b8b747366595d0d6af5040ca0c164

See more details on using hashes here.

File details

Details for the file klein-0.2.3-py27-none-any.whl.

File metadata

File hashes

Hashes for klein-0.2.3-py27-none-any.whl
Algorithm Hash digest
SHA256 0abde6db11e5384c365c37381d2ae35f6d0d74fa1a82bb9de1f648b26f531e87
MD5 aed3580b8429649c903920e76cf2f99b
BLAKE2b-256 a67ed5f96e26b71523891f5097a19663049a625b803af641a74af6507edc5e51

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page