[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 (December 2006) 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 | Global | Application Root | App Path |
| engine | X | ||
| hooks | X | X | X |
| log | X | X | |
| request | X | X | X |
| response | X | X | X |
| server | X | ||
| tools | X | X | X |
| 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
- The cherrypy/lib/filter folder, which was emptied in 2.2, has been removed.
- The cherrypy/filters folder has been replaced by the _cptools module.
- The deprecated cherrypy/lib/form and cherrypy/lib/defaultformmask modules have been removed.
- _cphttptools is now called _cprequest.
- cherrypy/lib/httptools is now cherrypy/lib/http.
- cherrypy.config was a module, and is now an instance of the new cherrypy._cpconfig.Config.
- All of the test modules have been renamed, dropping the word "filter".
- _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 name | New name |
| baseurl_filter | tools.proxy |
| cache_filter | tools.caching |
| cache_filter.cacheClass | tools.caching.cache_class |
| decoding_filter | tools.decode |
| encoding_filter | tools.encode |
| gzip_filter | toos.gzip |
| log_debug_info_filter | no equivalent |
| nsgmls_filter | tools.nsgmls |
| response_headers_filter | tools.response_headers |
| session_authenticate_filter | tools.session_auth |
| session_authenticate_filter.load_user_by_username | tools.session_auth.on_check |
| session_authenticate_filter.check_login_and_password | tools.session_auth.check_username_and_password |
| session_authenticate_filter.not_logged_in | tools.session_auth.anonymous |
| session_auth form param: 'login' | form param: 'username' |
| session_filter | tools.sessions |
| session_filter.clean_up_delay | tools.sessions.clean_freq |
| session_filter.cookie_name | tools.sessions.name |
| session_filter.cookie_domain | tools.sessions.domain |
| session_filter.cookie_path | tools.sessions.path |
| session_filter.cookie_secure | tools.sessions.secure |
| session_filter.cookie_path_from_header | tools.sessions.path_header |
| static_filter.dir | tools.staticdir.dir |
| static_filter.file | tools.staticfile.filename |
| tidy_filter | tools.tidy |
| virtual_host_filter | request.dispatch: cherrypy.dispatch.VirtualHost(**{domain: path}) |
| wsgiappfilter | tools.wsgiapp |
| xmlrpc_filter | request.dispatch: cherrypy.dispatch.XMLRPCDispatcher() |
Config changes
| Old name | New name |
| server.default_content_type | tools.response_headers.headers=[('Content-Type', 'text/html')] |
| log_access_file | log.access_file |
| log_config_options | no equivalent |
| log_file | log.error_file |
| log_file_not_found | no equivalent |
| log_request_headers | tools.log_headers.on = True |
| log_to_screen | log.screen |
| show_tracebacks | request.show_tracebacks |
| throw_errors | request.throw_errors |
| profiler.on | cherrypy.tree.mount(profiler.make_app(cherrypy.Application(Root()))) |
| environment = 'development' | on by default |
| environment = 'embedded' | environment = 'production' |
| autoreload.on | engine.autoreload_on |
| autoreload.frequency | engine.autoreload_frequency |
| autoreload.match | engine.autoreload_match |
Other name changes
| Old name | New name |
| server.on_start_server_list | engine.on_start_engine_list |
| server.on_stop_server_list | engine.on_stop_engine_list |
| server.on_start_thread_list | engine.on_start_thread_list |
| server.on_stop_thread_list | engine.on_stop_thread_list |
| cherrypy.server.httpserver | cherrypy.server.httpservers.keys()[0] |
| cherrypy.server.start | cherrypy.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_path | request.path_info |
| no equivalent | request.script_name |
| request.path | strict: request.script_name + request.path_info But you should probably use cherrypy.url() or just request.path_info instead. |
| request.browser_url | cherrypy.url() |
| request.remote_addr | request.remote.ip |
| request.remote_port | request.remote.port |
| request.remote_host | request.remote.name |
| request.mapPathToObject | request.dispatch |
| request.simple_cookie | request.cookie |
| response.simple_cookie | response.cookie |
| HeaderMap?.sorted_list | HeaderMap?.output |
| cherrypy.response.version | cherrypy.request.protocol |
| _cp_log_message | log.error |
| _cp_log_access | log.access |
| _cp_log_message | log.error |
| _cputil.logtime | cherrypy.log.time |
| _cp_on_http_error | no equivalent |
| _cp_on_error | request.error_response |
| cherrypy.serving | cherrypy._serving |
| cherrypy.lowercase_api | not needed |
| cherrypy.InternalError | no equivalent |
| cherrypy.NotReady | cherrypy.HTTPError(503) |
| cherrypy.WrongConfigValue | no equivalent |
| cherrypy.RequestHandled | request.handler = None |
| cptools.decorate | no equivalent |
| cptools.decorateAll | no equivalent |
| cptools.ExposeItems | no equivalent |
| before_main | before_handler |
| filters.init | not needed |
| filters.applyFilters | request.hooks.run |
| filters.input_filters/output_filters | request.hooks.attach |
| config.getAll | no equivalent |
| config.dict_from_config_file | _cpconfig._Parser.dict_from_file |
| cherrypy.root | cherrypy.request.app.root |
| _cptree.Root/Branch | no equivalent |
| cherrypy.tree.mount(root, conf={}) | cherrypy.tree.mount(root, config={}) |
| cherrypy.tree.mount_point | cherrypy.tree.script_name |
| cherrypy.tree.mount_points | cherrypy.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 |

