Skip to content

Latest commit

 

History

History
368 lines (262 loc) · 7.25 KB

presentation.rst

File metadata and controls

368 lines (262 loc) · 7.25 KB

CherryPy

Organization

Utah Python

Author

Seth House <seth@eseth.com>

Date

2013-05-09

Outline

  • History
  • 2 v 3 v 3.2
  • Basics
  • Good
    • Docs
  • Bad
    • Docs
    • Community size

A minimalist Python web framework

image

History

  • Remi Delon
  • 2002: CherryPy
    • CherryPy class processed to be self-contained module (app & server)
  • 2004: CherryPy 2
    • Object publishing
    • Filters
  • 2005: CherryPy 2.1
    • Shipped with Turbogears
    • Scrutiny; performance; WSGI support
  • 2006: CherryPy 3
    • Book
    • Turbogears 2.x chose Pylons
  • 2011: CherryPy 3.2

Why CherryPy

https://www.ohloh.net/p/cherrypy

Goals

  • Simplicity
  • No deps
  • Lightly opinionated
  • Community driven

Features

  • Small (~600k)
  • Featureful
  • Plain functions or objects
  • Extremely extendible

CherryPy basics

image

Basics

  • Application framework
  • Webserver

Framework

  • Configuration via dictionaries
  • Seven hook functions
    • Called during request/response cycle
  • Caching
  • Encoding
  • Sessions & cookies
  • Authorization
  • Uploads
  • Static content
  • No ORM / no templating / no forms

Server

  • Pure Python (Python 2.3+)
  • HTTP/1.1 compliant
  • Thread pooled
  • Fast (1-2 ms per request)
  • SSL (!)
  • Cheroot: Stand-alone version

Hello world

Application and server:

hello.py

import cherrypy

class HelloWorld:
    def index(self):
        return "Hello world!"
    index.exposed = True

cherrypy.quickstart(HelloWorld())

import cherrypy

help(cherrypy)

Building an app

image

Dispatchers

Default dispatcher

For example:

Or possibly:

Handlers

Resources:

When you wish to serve a resource on the Web, you never actually serve the resource, because “resources” are concepts. What you serve are representations of a resource, and page handlers are what you use in CherryPy to do that. Page handlers are functions that you write; CherryPy calls one for each request and uses its response (a string of HTML, for example) as the representation. […] CherryPy takes the output of the appropriate page handler function, binds it to cherrypy.response.body, and sends it as the HTTP response entity body. Your page handler function (and almost any other part of CherryPy) can directly set cherrypy.response.status and cherrypy.response.headers as desired.

http://docs.cherrypy.org/stable/concepts/dispatching.html

  • Any callable
  • Current handler is cherrypy.request.handler
  • Replace on the fly
  • Must have exposed=True attribute
  • .index attribute will take precedence
  • default callable as fallback
  • POST data available as kwargs:

    class MyHandler(object):
        def search(self, q, lang, page):
            # do something with ``q``

Config

  • Dictionaries (!)
    • Python code (run-time)
    • ConfigParser ini files
    • Python code (execution-time)
  • Configure
    • Dispatcher (per URL)
    • request / response object attributes
    • Hooks
    • Tools
    • Logging
    • Server options
  • Global config
  • Application config
  • Handler config:

    class MyHandler(object):
        _cp_config = {}

Tools

  • Behavior outside handlers
  • Many builtin
  • Register / enable in the config:

    [/images]
    tools.staticdir.on: True
  • Some usable as handler
  • Directly callable
  • Usable as decorators:

    @tools.staticdir(dir='static')
    def images():
        …

Writing tools

def mytool():
    # something!

cherrypy.tools.mytool = Tool('on_some_hook', mytool)

Hooks

on_start_resource

The earliest hook; the Request-Line and request headers have been processed and a dispatcher has set request.handler and request.config.

before_request_body

Tools that are hooked up here run right before the request body would be processed.

before_handler

Right before the request.handler (the “exposed” callable that was found by the dispatcher) is called.

before_finalize

This hook is called right after the page handler has been processed and before CherryPy formats the final response object. It helps you for example to check for what could have been returned by your page handler and change some headers if needed.

on_end_resource

Processing is complete - the response is ready to be returned. This doesn’t always mean that the request.handler (the exposed page handler) has executed! It may be a generator. If your tool absolutely needs to run after the page handler has produced the response body, you need to either use on_end_request instead, or wrap the response.body in a generator which applies your tool as the response body is being generated (what a mouthful–see caching tee.output for an example).

before_error_response

Called right before an error response (status code, body) is set.

after_error_response

Called right after the error response (status code, body) is set and just before the error response is finalized.

on_end_request

The request/response conversation is over, all data has been written to the client, nothing more to see here, move along.

  • on_start_resource
  • before_request_body
  • before_handler
  • before_finalize
  • on_end_resource
  • before_error_response
  • after_error_response
  • on_end_request

Conclusion

image

Good

  • Crazy flexible
  • Lots of documentation
  • Small
  • Fast
  • No deps

Bad

  • Documentation is scattered / some holes
  • CherryPy 2 vs. 3 vs. 3.2
  • Small community
  • Flexibility style can be tough to organize

Walkthrough of a real app

  • Demo of REST interface to Salt
    • Request
    • Response
    • Reading headers
    • Writing headers
    • Redirects
    • Exceptions
  • WSGI Server
  • Writing tests