Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

[This document is complete up to rev 1460.]

How to upgrade to CherryPy 3.0

This page discusses changes between CherryPy 2.2 (February 2006) and 3.0 (now in beta) which might require you to modify your code when you upgrade. Bugfixes aren't listed here.

Configuration

In CherryPy 2.2, configuration entries for the server, the application, and the request process were all mixed together. In CherryPy 3.0, they have been separated by two mechanisms. First, each mounted application now has its own config (which is usually provided in the tree.mount call); this holds per-application config (in a "/" section) and per-path config. Second, cherrypy.config is now for global entries only (things which affect all applications). Third, all config names are now of the form "namespace.key", where "namespace" is one of the following: "engine", "hooks", "log", "request", "response", "server", "tools". Entries from each namespace may be placed in the global, application root ("/") or per-path config, or a combination:

Scope GlobalApplication RootApp Path
engine X
hooks XXX
log XX
request XXX
responseXXX
server X
tools XXX
wsgi X

In addition to specifying config entries in a config file, you may now attach config data directly to page handlers or their containers via the _cp_config attribute (a dict). This attribute (in conjunction with hooks and tools, see below) replaces the old _cp_filters, _cp_on_error, and _cp_on_http_error attributes. Note that _cp_config entries apply to each handler (or branch in the CherryPy tree), whereas entries in config files apply based on the URI, which is not always mapped 1:1 with handlers.

You may now instantiate objects in config. See [1045].

Hooks replace Filters

By far the biggest change is the transformation of filters to hooks and tools. All use of the word "filter" has been purged to make it easier for you to find places in your code that need upgrading.

Every Request object now possesses a "hooks" attribute, a _cprequest.HookMap object. A HookMap? works like a dict, where the keys are "hook points" and the values are lists of Hooks:

  • The "hook points" are the old filter method names: 'on_start_resource', 'before_request_body', 'before_handler', 'before_finalize', 'on_end_resource', 'on_end_request', 'before_error_response', and 'after_error_response'.
  • A Hook is a callback function, wrapped up into a Hook object. Each Hook instance also possesses a 'failsafe' attribute, a bool. If True, the callback is guaranteed to run, even if other Hooks at the same hook point fail. It also possesses a 'priority', a number from 0 to 100. Lower numbers run first.

The HookMap? has an "attach" method to make this process easier. Call it like this: cherrypy.request.hooks.attach(point, callback, failsafe=None, priority=None, **kwargs). Any code can do this, and can do it on the fly! See the new caching tool for an example; if the request is served from cache inside the "before_handler" hook, then the logic which would cache the page handler output is never attached, and therefore never invoked.

Tools package up Hooks

Tools provide a standard way to "wrap up" a set of hooks and other behavior into a single component. Tools provide:

  • Standardized config All registered tools are automatically configurable: "tools.mytool.on = True" turns on the tool, and all "tools.mytool.xxx = yyy" entries are automatically sent to the hook as "mytool(xxx=yyy)" keyword arguments.
  • Common invocation The cherrypy.Tool base class automatically makes your callback usable as a decorator: "@tools.mytool(xxx=yyy)". The HandlerTool? base class provides a "handler" method, so you can write, for example, "class Root: files = tools.staticdir.handler(section='/files', dir='static', root=absDir)".
  • Easy reflection When you wrap your callback up in a tool, all of its function arguments become attributes of the Tool, so that users of the Tool can see the arguments easily. If your IDE provides code-completion, just "import tools" while writing your config; the IDE can pop up a calltip when you've typed, say, "tools.gzip. ", showing you which arguments the gzip tool takes.

Rewriting filters as tools is a fairly straightforward operation. If your filter only has one method, pull it out of the class and rename it to say what it *really* does (like "gzip" or "staticfile"). Then, make a Tool for it like so: cherrypy.tools.mytool = cherrypy.Tool('before_handler', mymodule.myfunc). If you have more complicated needs, you can subclass cherrypy.Tool and override the _setup method. See cherrypy._cptools for some examples.

Starting, mounting, and stopping

Starting with [1092], the Server class (which controls an HTTP server) is no longer a subclass of Engine (the app server). This means that each can and must be started and stopped independently. In addition, you must now use cherrypy.tree.mount instead of cherrypy.root. In other words, instead of writing:

cherrypy.root = Root()
cherrypy.server.start()

you must now write:

cherrypy.tree.mount(Root())
cherrypy.server.quickstart()
cherrypy.engine.start()

However, rather than make 3 separate calls to tree.mount, server.quickstart, and engine.start, there's a new cherrypy.quickstart function. To do the same thing as above, you can simply write:

cherrypy.quickstart(Root())

Here's the function in its entirety:

def quickstart(root, script_name="", config=None):
    """Mount the given app, start the engine and builtin server, then block."""
    if config:
        cherrypy.config.update(config)
    tree.mount(root, script_name, config)
    server.quickstart()
    engine.start()
    engine.block()

If you used the old init_only argument to server.start, you should now write this:

cherrypy.tree.mount(Root())
cherrypy.server.quickstart()
cherrypy.engine.start(blocking=False)

Nested Generator Responses

If you were using this extremely rare feature of CherryPy 2, you need to turn on a Tool now. A 'nested generator' is a page handler that is a (or returns a) generator that itself yields generators. In CherryPy 2, support for these was automatic. In CherryPy 3, just add tools.flatten.on = True to your config for such handlers.

Module changes

  1. The cherrypy/lib/filter folder, which was emptied in 2.2, has been removed.
  2. The cherrypy/filters folder has been replaced by the _cptools module.
  3. The deprecated cherrypy/lib/form and cherrypy/lib/defaultformmask modules have been removed.
  4. _cphttptools is now called _cprequest.
  5. cherrypy/lib/httptools is now cherrypy/lib/http.
  6. cherrypy.config was a module, and is now an instance of the new cherrypy._cpconfig.Config.
  7. All of the test modules have been renamed, dropping the word "filter".
  8. _cpwsgiserver is now called wsgiserver (see [1460]).

Name changes

NOTE: All of the name changes which were optional in CherryPy 2.2 are now mandatory (unless changed further below). If you did not upgrade those names when moving from 2.1 to 2.2?, you should do so now and then come back here.

Beginning with CP 3.0 beta 2 [1373], there is a new cherrypy._cpconfig.check_compatibility(config) function to help you migrate. Pass it a config file, filename, or dict, and it will warn you of obsolete entries.

Filter changes

Old nameNew name
baseurl_filtertools.proxy
cache_filtertools.caching
cache_filter.cacheClasstools.caching.cache_class
decoding_filtertools.decode
encoding_filtertools.encode
gzip_filtertoos.gzip
log_debug_info_filterno equivalent
nsgmls_filtertools.nsgmls
response_headers_filtertools.response_headers
session_authenticate_filtertools.session_auth
session_authenticate_filter.load_user_by_usernametools.session_auth.on_check
session_authenticate_filter.check_login_and_passwordtools.session_auth.check_username_and_password
session_authenticate_filter.not_logged_intools.session_auth.anonymous
session_auth form param: 'login'form param: 'username'
session_filtertools.sessions
session_filter.clean_up_delaytools.sessions.clean_freq
session_filter.cookie_nametools.sessions.name
session_filter.cookie_domaintools.sessions.domain
session_filter.cookie_pathtools.sessions.path
session_filter.cookie_securetools.sessions.secure
session_filter.cookie_path_from_headertools.sessions.path_header
static_filter.dirtools.staticdir.dir
static_filter.filetools.staticfile.filename
tidy_filtertools.tidy
virtual_host_filterrequest.dispatch: cherrypy.dispatch.VirtualHost(**{domain: path})
wsgiappfiltertools.wsgiapp
xmlrpc_filterrequest.dispatch: cherrypy.dispatch.XMLRPCDispatcher()

Config changes

Old nameNew name
server.default_content_typetools.response_headers.headers=[('Content-Type', 'text/html')]
log_access_filelog.access_file
log_config_optionsno equivalent
log_filelog.error_file
log_file_not_foundno equivalent
log_request_headerstools.log_headers.on = True
log_to_screenlog.screen
show_tracebacksrequest.show_tracebacks
throw_errorsrequest.throw_errors
profiler.oncherrypy.tree.mount(profiler.make_app(cherrypy.Application(Root())))
environment = 'development'on by default
environment = 'embedded'environment = 'production'
autoreload.onengine.autoreload_on
autoreload.frequencyengine.autoreload_frequency
autoreload.matchengine.autoreload_match

Other name changes

Old nameNew name
server.on_start_server_listengine.on_start_engine_list
server.on_stop_server_listengine.on_stop_engine_list
server.on_start_thread_listengine.on_start_thread_list
server.on_stop_thread_listengine.on_stop_thread_list
cherrypy.server.httpservercherrypy.server.httpservers.keys()[0]
cherrypy.server.startcherrypy.server.quickstart; cherrypy.engine.start
cheryrpy.server.request(clientAddress, remoteHost, scheme='http')cherrypy.engine.request(local_host, remote_host, scheme="http", server_protocol="HTTP/1.1")
cherrypy.server.start_with_callback(func, args=None, kwargs=None, server_class=<object object>, serverClass=None)cherrypy.server.quickstart(server=None); cherrypy.engine.start_with_callback(func, args=None, kwargs=None)
request.object_pathrequest.path_info
no equivalentrequest.script_name
request.pathstrict: request.script_name + request.path_info
But you should probably use cherrypy.url() or just request.path_info instead.
request.browser_urlcherrypy.url()
request.remote_addrrequest.remote.ip
request.remote_portrequest.remote.port
request.remote_hostrequest.remote.name
request.mapPathToObjectrequest.dispatch
request.simple_cookierequest.cookie
response.simple_cookieresponse.cookie
HeaderMap?.sorted_listHeaderMap?.output
cherrypy.response.versioncherrypy.request.protocol
_cp_log_messagelog.error
_cp_log_accesslog.access
_cp_log_messagelog.error
_cputil.logtimecherrypy.log.time
_cp_on_http_errorno equivalent
_cp_on_errorrequest.error_response
cherrypy.servingcherrypy._serving
cherrypy.lowercase_apinot needed
cherrypy.InternalErrorno equivalent
cherrypy.NotReadycherrypy.HTTPError(503)
cherrypy.WrongConfigValueno equivalent
cherrypy.RequestHandledrequest.handler = None
cptools.decorateno equivalent
cptools.decorateAllno equivalent
cptools.ExposeItemsno equivalent
before_mainbefore_handler
filters.initnot needed
filters.applyFiltersrequest.hooks.run
filters.input_filters/output_filtersrequest.hooks.attach
config.getAllno equivalent
config.dict_from_config_file_cpconfig._Parser.dict_from_file
cherrypy.rootcherrypy.request.app.root
_cptree.Root/Branchno equivalent
cherrypy.tree.mount(root, conf={})cherrypy.tree.mount(root, config={})
cherrypy.tree.mount_pointcherrypy.tree.script_name
cherrypy.tree.mount_pointscherrypy.tree.apps
_cputil.bareError_cperror.bare_error
_cputil.formatExc_cperror.format_exc
lib.cptools.serveFile(path, contentType, disposition, name)lib.static.serve_file(path, content_type, disposition, name)
_cpwsgi.WSGIServer_cpwsgi.CPWSGIServer
cherrypy.session["_id"]cherrypy.session.id

Hosted by WebFaction

Log in as guest/cpguest to create tickets