Robert Brewer avatar Robert Brewer committed 6e177f1

More doc work.

Comments (0)

Files changed (19)

cherrypy/process/servers.py

       )
     } # end of $HTTP["url"] =~ "^/"
 
-Please see `Lighttpd FastCGI Docs 
-<http://trac.lighttpd.net/trac/wiki/Docs:ModFastCGI>`_ for an explanation 
+Please see `Lighttpd FastCGI Docs
+<http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModFastCGI>`_ for an explanation 
 of the possible configuration options.
 """
 

sphinx/source/concepts/basics.rst

+*******************************
+Your first CherryPy application
+*******************************
+
+The standard 'Hello world!' application takes less than 10 lines of code
+when written using CherryPy::
+
+    import cherrypy
+    
+    class HelloWorld:
+        def index(self):
+            return "Hello world!"
+        index.exposed = True
+    
+    cherrypy.quickstart(HelloWorld())
+
+We assume that you already have :doc:`installed </intro/install>` CherryPy.
+Copy the file above and save it locally as ``hello.py``, then start the
+application at the command prompt::
+
+    $ python hello.py
+
+Direct your favorite web browser to http://localhost:8080 and you should
+see ``Hello world!`` printed there.
+
+How does it work?
+-----------------
+
+Let's take a look at ``hello.py``:
+
+ * The ``import cherrypy`` statement imports the main CherryPy module.
+   This is all that is required to have CherryPy working. Feel free to
+   "import cherrypy" in an interactive session and see what's available!
+   ``help(cherrypy)`` is also quite useful.
+ * We declare a class named ``HelloWorld``. An instance of this class is the
+   object that will be published by CherryPy. It contains a single method,
+   named ``index``, which will get called when the root URL for the site is
+   requested (for example, ``http://localhost/``). This method returns the
+   **contents** of the Web page; in this case, the ``'Hello World!'`` string.
+   Note that you don't have to subclass any framework-provided classes; in fact,
+   you don't even have to use classes at all! But let's start with them for now.
+ * The ``index.exposed = True`` is a necessary step to tell CherryPy that the
+   ``index()`` method will be **exposed**. Only exposed methods can be called
+   to answer a request. This feature allows the user to select which methods
+   of an object will be accessible via the Web; non-exposed methods can't be
+   accessed.
+ * ``cherrypy.quickstart(HelloWorld())`` mounts an instance of the HelloWorld
+   class, and starts the embedded webserver. It runs until explicitly
+   interrupted, either with ``Ctrl-C`` or via a suitable signal (a simple
+   ``kill`` on Unix will do it).
+
+When the application is executed, the CherryPy server is started with the
+default configuration. It will listen on ``localhost`` at port ``8080``. These
+defaults can be overridden by using a configuration file or dictionary
+(more on this later).
+
+Finally, the web server receives the request for the URL
+``http://localhost:8080``. It searches for the best method to handle the
+request, starting from the ``HelloWorld`` instance. In this particular case,
+the root of the site is automatically mapped to the ``index()`` method (similar
+to the ``index.html`` that is the standard page for conventional Web servers).
+The HelloWorld class defines an ``index()`` method and exposes it. CherryPy
+calls ``HelloWorld().index()``, and the result of the call is sent back to
+the browser as the contents of the index page for the website. All the
+dispatching and HTTP-processing work is
+done automatically; the application programmer only needs to provide the
+desired content as the return value of the ``index`` method.
+
+CherryPy structure
+------------------
+
+Most of the features of CherryPy are available through the :mod:`cherrypy`
+module. It contains several members:
+
+ * :class:`cherrypy.engine <cherrypy.process.wspbus.Bus>`
+   controls process startup, shutdown, and other events, including your own
+   Plugins. See :doc:`/concepts/engine`.
+ * :class:`cherrypy.server <cherrypy._cpserver.Server>` configures and controls
+   the HTTP server.
+ * :class:`cherrypy.request <cherrypy._cprequest.Request>` contains all
+   the information that comes with the HTTP request, after it is parsed and
+   analyzed by CherryPy.
+ * :attr:`cherrypy.request.headers <cherrypy.lib.httputil.HeaderMap>`
+   contains a mapping with the header options that were sent as part of
+   the request.
+ * :class:`cherrypy.session <cherrypy.lib.sessions.Session>` is a special
+   mapping that is automatically generated and encoded by CherryPy; it can
+   be used to store session-data in a persistent cookie. For it to work you
+   have to enable the session functionality by setting 'tools.session.on' to
+   True in your config. 
+ * :class:`cherrypy.response <cherrypy._cprequest.Response>` contains the
+   data that is used to build the HTTP response. 
+ * :attr:`cherrypy.response.headers <cherrypy.lib.httputil.HeaderMap>`
+   contains a mapping with the header options that will be returned by the
+   server, before the contents get sent.
+ * :attr:`cherrypy.response.body <cherrypy._cprequest.Response.body>` contains
+   the actual contents of the webpage that will be sent as a response.
+

sphinx/source/concepts/config.rst

+:tocdepth: 3
+
+*************
+Configuration
+*************
+
+Configuration in CherryPy is implemented via dictionaries. Keys are strings
+which name the mapped value; values may be of any type.
+
+In CherryPy 3, you use configuration (files or dicts) to set attributes
+directly on the engine, server, request, response, and log objects. So the
+best way to know the full range of what's available in the config file is to
+simply import those objects and see what ``help(obj)`` tells you.
+
+Architecture
+============
+
+The first thing you need to know about CherryPy 3's configuration is that it
+separates *global* config from *application* config. If you're deploying
+multiple *applications* at the same *site* (and more and more people are,
+as Python web apps are tending to decentralize), you need to be careful to
+separate the configurations, as well. There's only ever one "global config",
+but there is a separate "app config" for each app you deploy.
+
+CherryPy *Requests* are part of an *Application*, which runs in a *global*
+context, and configuration data may apply to any of those three scopes.
+Let's look at each of those scopes in turn.
+
+Global config
+-------------
+
+Global config entries apply everywhere, and are stored in
+:class:`cherrypy.config <cherrypy._cpconfig.Config>`. This flat dict only holds
+global config data; that is, "site-wide" config entries which affect all
+mounted applications.
+
+Global config is stored in the
+:class:`cherrypy.config <cherrypy._cpconfig.Config>` dict,
+and you therefore update it by calling ``cherrypy.config.update(conf)``.
+The ``conf`` argument can be either a filename, an open file, or a dict of
+config entries. Here's an example of passing a dict argument::
+
+    cherrypy.config.update({'server.socket_host': '64.72.221.48',
+                            'server.socket_port': 80,
+                           })
+
+The ``server.socket_host`` option n this example determines on which network
+interface CherryPy will listen. The ``server.socket_port`` option declares
+the TCP port on which to listen.
+
+Application config
+------------------
+
+Application entries apply to a single mounted application, and are stored on
+each Application object itself as
+:attr:`app.config <cherrypy._cptree.Application.config>`. This is a two-level
+dict where each top-level key is a path, or "relative URL" (for example,
+``"/"`` or ``"/my/page"``), and each value is a dict of config entries.
+The URL's are relative to the script name (mount point) of the Application.
+Usually, all this data is provided in the call to
+``tree.mount(root(), script_name='/path/to', config=conf)``,
+although you may also use ``app.merge(conf)``.
+The ``conf`` argument can be either a filename, an open file, or a dict of
+config entries.
+
+Configuration file example::
+
+    [/]
+    tools.trailing_slash.on = False
+    request.dispatch: cherrypy.dispatch.MethodDispatcher()
+
+or, in python code::
+
+    config = {'/': 
+        {
+            'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
+            'tools.trailing_slash.on': False,
+        }
+    }
+    cherrypy.tree.mount(Root(), "/", config=config)
+
+CherryPy doesn't use any sections that don't start with ``"/"`` (except
+``[global]``, see below). That means you can place your own configuration
+entries in a CherryPy config file by giving them a section name which does not
+start with ``"/"``. For example, you might include database entries like this::
+
+    [global]
+    server.socket_host: "0.0.0.0"
+
+    [Databases]
+    driver: "postgres"
+    host: "localhost"
+    port: 5432
+
+    [/path]
+    response.timeout: 6000
+
+Then, in your application code you can read these values during request time
+via ``cherrypy.request.app.config['Databases']``. For code that is outside the
+request process, you'll have to pass a reference to your Application around.
+
+Request config
+--------------
+
+Each Request object possesses a single
+:attr:`request.config <cherrypy._cprequest.Request.config>` dict. Early in the
+request process, this dict is populated by merging Global config, Application
+config, and any config acquired while looking up the page handler (see next).
+This dict contains only those config entries which apply to the given request.
+
+.. note::
+
+   when you do an :class:`InternalRedirect<cherrypy._cperror.InternalRedirect`,
+   this config attribute is recalculated for the new path.
+
+Declaration
+===========
+
+Configuration data may be supplied as a Python dictionary, as a filename,
+or as an open file object.
+
+Configuration files
+-------------------
+
+When you supply a filename or file, CherryPy uses Python's builtin ConfigParser;
+you declare Application config by writing each path as a section header,
+and each entry as a ``"key: value"`` (or ``"key = value"``) pair::
+
+    [/path/to/my/page]
+    response.stream: True
+    tools.trailing_slash.extra = False
+
+Combined Configuration Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you are only deploying a single application, you can make a single config
+file that contains both global and app entries. Just stick the global entries
+into a config section named ``[global]``, and pass the same file to both
+:func:`config.update <cherrypy._cpconfig.Config.update>` and
+:func:`tree.mount <cherrypy._cptree.Tree.mount`. If you're calling
+``cherrypy.quickstart(app root, script name, config)``, it will pass the
+config to both places for you. But as soon as you decide to add another
+application to the same site, you need to separate the two config files/dicts.
+
+Separate Configuration Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you're deploying more than one application in the same process, you need
+(1) file for global config, plus (1) file for *each* Application.
+The global config is applied by calling
+:func:`cherrypy.config.update <cherrypy._cpconfig.Config.update>`,
+and application config is usually passed in a call to
+:func:`cherrypy.tree.mount <cherrypy._cptree.Tree.mount>`.
+
+In general, you should set global config first, and then mount each
+application with its own config. Among other benefits, this allows you to set
+up global logging so that, if something goes wrong while trying to mount
+an application, you'll see the tracebacks. In other words, use this order::
+
+    # global config
+    cherrypy.config.update({'environment': 'production',
+                            'log.error_file': 'site.log',
+                            # ...
+                            })
+
+    # Mount each app and pass it its own config
+    cherrypy.tree.mount(root1, "/", appconf1)
+    cherrypy.tree.mount(root2, "/forum", appconf2)
+    cherrypy.tree.mount(root3, "/blog", appconf3)
+
+    if hasattr(cherrypy.engine, 'block'):
+        # 3.1 syntax
+        cherrypy.engine.start()
+        cherrypy.engine.block()
+    else:
+        # 3.0 syntax
+        cherrypy.server.quickstart()
+        cherrypy.engine.start()
+
+Values in config files use Python syntax
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Config entries are always a key/value pair, like ``server.socket_port = 8080``.
+The key is always a name, and the value is always a Python object. That is,
+if the value you are setting is an ``int`` (or other number), it needs to look
+like a Python ``int``; for example, ``8080``. If the value is a string, it
+needs to be quoted, just like a Python string. Arbitrary objects can also be
+created, just like in Python code (assuming they can be found/imported).
+Here's an extended example, showing you some of the different types::
+
+    [global]
+    log.error_file: "/home/fumanchu/myapp.log"
+    environment = 'production'
+    server.max_request_body_size: 1200
+
+    [/myapp]
+    tools.trailing_slash.on = False
+    request.dispatch: cherrypy.dispatch.MethodDispatcher()
+
+.. _cp_config:
+
+_cp_config: attaching config to handlers
+----------------------------------------
+
+Config files have a severe limitation: values are always keyed by URL.
+For example::
+
+    [/path/to/page]
+    methods_with_bodies = ("POST", "PUT", "PROPPATCH")
+
+It's obvious that the extra method is the norm for that path; in fact,
+the code could be considered broken without it. In CherryPy, you can attach
+that bit of config directly on the page handler::
+
+    def page(self):
+        return "Hello, world!"
+    page.exposed = True
+    page._cp_config = {"request.methods_with_bodies": ("POST", "PUT", "PROPPATCH")}
+
+``_cp_config`` is a reserved attribute which the dispatcher looks for at
+each node in the object tree. The ``_cp_config`` attribute must be a CherryPy
+config dictionary. If the dispatcher finds a ``_cp_config`` attribute,
+it merges that dictionary into the rest of the config. The entire merged
+config dictionary is placed in
+:attr:`cherrypy.request.config <cherrypy._cprequest.Request.config>`.
+
+This can be done at any point in the tree of objects; for example, we could have
+attached that config to a class which contains the page method::
+
+    class SetOPages:
+
+        _cp_config = {"request.methods_with_bodies": ("POST", "PUT", "PROPPATCH")}
+
+        def page(self):
+            return "Hullo, Werld!"
+        page.exposed = True
+
+.. note::
+
+   This behavior is only guaranteed for the default dispatcher. Other
+   dispatchers may have different restrictions on where you can attach
+   ``_cp_config`` attributes.
+
+This technique allows you to:
+
+ * Put config near where it's used for improved readability and maintainability.
+ * Attach config to objects instead of URL's. This allows multiple URL's to
+   point to the same object, yet you only need to define the config once.
+ * Provide defaults which are still overridable in a config file.
+
+.. _namespaces:
+
+Namespaces
+==========
+
+Because config entries usually just set attributes on objects, they're almost
+all of the form: ``object.attribute``. A few are of the form:
+``object.subobject.attribute``. They look like normal Python attribute chains,
+because they work like them. We call the first name in the chain the
+*"config namespace"*. When you provide a config entry, it is bound as early
+as possible to the actual object referenced by the namespace; for example,
+the entry ``response.stream`` actually sets the ``stream`` attribute of
+:class:`cherrypy.response <cherrypy._cprequest.Response>`! In this way,
+you can easily determine the default value by firing up a python interpreter
+and typing::
+
+    >>> import cherrypy
+    >>> cherrypy.response.stream
+    False
+
+Each config namespace has its own handler; for example, the "request" namespace
+has a handler which takes your config entry and sets that value on the
+appropriate "request" attribute. There are a few namespaces, however, which
+don't work like normal attributes behind the scenes; however, they still use
+dotted keys and are considered to "have a namespace".
+
+Builtin namespaces
+------------------
+
+engine
+^^^^^^
+Entries in this namespace controls the 'application engine'. These can only be
+declared in the global config. Any attribute of `cherrypy.engine` may be set
+in config; however, there are a few extra entries available in config:
+
+ * Plugin attributes. Many of the :ref:`Engine Plugin<plugins>` are themselves
+   attributes of `engine`. You can set any attribute of an attached plugin
+   by simply naming it. For example, there is an instance of the
+   :class:`Autoreloader<cherrypy.process.plugins.Autoreloader>` class at
+   `engine.autoreload`; you can set its "frequency" attribute via the config
+   entry `engine.autoreload.frequency = 60`. In addition, you can turn such
+   plugins on and off by setting `engine.autoreload.on = True` or `False`.
+ * `engine.SIGHUP/SIGTERM`: These entries can be used to set the list of
+   listeners for the given :ref:`channel<channels>`. Mostly, this is used
+   to turn off the signal handling one gets automatically via
+   func:`cherrypy.quickstart`.
+
+hooks
+^^^^^
+
+Declares additional request-processing functions. Use this to append your own
+:class:`Hook<cherrypy._cprequest.Hook>` functions to the request. For example,
+to add `my_hook_func` to the `before_handler` hookpoint:
+
+    [/]
+    hooks.before_handler = myapp.my_hook_func
+
+log
+^^^
+
+Configures logging. These can only be declared in the global config (for global
+logging) or `[/]` config (for each application).
+See :class:`LogManager<cherrypy._cplogging.LogManager>` for the list of
+configurable attributes. Typically, the "access_file", "error_file", and
+"screen" attributes are the most commonly configured.
+
+request
+^^^^^^^
+
+Sets attributes on each Request. See the
+:class:`Request<cherrypy._cprequest.Request>` class for a complete list.
+
+response
+^^^^^^^^
+
+Sets attributes on each Response. See the
+:class:`Response<cherrypy._cprequest.Response>` class for a complete list.
+
+server
+^^^^^^
+Controls the default HTTP server via
+:class:`cherrypy.server<cherrypy._cpserver.Server>` (see that class for a
+complete list of configurable attribtues). These can only be
+declared in the global config.
+
+tools
+^^^^^
+
+Enables and configures additional request-processing packages. See the
+:doc:`/concepts/tools` overview for more information.
+
+wsgi
+^^^^
+
+Adds WSGI middleware to an Application's "pipeline". These can only be
+declared in the app's root config ("/").
+
+ * `wsgi.pipeline`: Appends to the WSGi pipeline. The value must be a list of
+   (name, app factory) pairs. Each app factory must be a WSGI callable class
+   (or callable that returns a WSGI callable); it must take an initial
+   'nextapp' argument, plus any optional keyword arguments. The optional
+   arguments may be configured via `wsgi.<name>.<arg>`.
+ * `wsgi.response_class`: Overrides the default
+   :class:`Response<cherrypy._cprequest.Response>` class.
+
+checker     Controls the 'checker', which looks for common errors in app state (including config) when the engine starts. Global config only.
+========    =======================
+
+Entries from each namespace may be allowed 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
+==========  ======  ==================  =========
+
+Custom config namespaces
+------------------------
+
+You can define your own namespaces if you like, and they can do far more than
+simply set attributes. The ``test/test_config`` module, for example, shows an
+example of a custom namespace that coerces incoming params and outgoing body
+content. The :mod:`cherrypy._cpwsgi` module includes an additional, builtin
+namespace for invoking WSGI middleware.
+
+In essence, a config namespace handler is just a function, that gets passed
+any config entries in its namespace. You add it to a namespaces registry
+(a dict), where keys are namespace names and values are handler functions.
+When a config entry for your namespace is encountered, the corresponding
+handler function will be called, passing the config key and value; that is,
+``namespaces[namespace](k, v)``. For example, if you write::
+
+    def db_namespace(k, v):
+        if k == 'connstring':
+            orm.connect(v)
+    cherrypy.config.namespaces['db'] = db_namespace
+
+then ``cherrypy.config.update({"db.connstring": "Oracle:host=1.10.100.200;sid=TEST"})``
+will call ``db_namespace('connstring', 'Oracle:host=1.10.100.200;sid=TEST')``.
+
+The point at which your namespace handler is called depends on where you add it:
+
+===========  =============================================================================  ===================================
+Scope        Namespace dict                                                                 Handler is called in  
+-----------  -----------------------------------------------------------------------------  -----------------------------------
+Global       :attr:`cherrypy.config.namespaces <cherrypy._cpconfig.Config.namespaces>`      cherrypy.config.update
+Application  :attr:`app.namespaces <cherrypy._cptree.Application.namespaces>`               Application.merge (which is called by cherrypy.tree.mount)
+Request      :attr:`app.request_class.namespaces <cherrypy._cprequest.Request.namespaces>`  Request.configure (called for each request, after the handler is looked up)
+===========  =============================================================================  ===================================
+
+The name can be any string, and the handler must be either a callable or a
+(Python 2.5 style) context manager.
+
+If you need additional code to run when all your namespace keys are collected,
+you can supply a callable context manager in place of a normal function for
+the handler. Context managers are defined in :pep:`343`.
+
+.. _environments:
+
+Environments
+============
+
+The only key that does not exist in a namespace is the *"environment"* entry.
+This special entry *imports* other config entries from a template stored in
+``cherrypy._cpconfig.environments[environment]``. It only applies to the
+global config, and only when you use
+:func:`cherrypy.config.update <cherrypy._cpconfig.Config.update>`.
+
+If you find the set of existing environments (production, staging, etc) too
+limiting or just plain wrong, feel free to extend them or add new environments::
+
+    cherrypy._cpconfig.environments['staging']['log.screen'] = False
+
+    cherrypy._cpconfig.environments['Greek'] = {
+        'tools.encode.encoding': 'ISO-8859-7',
+        'tools.decode.encoding': 'ISO-8859-7',
+        }
+

sphinx/source/concepts/dispatching.rst

+***********
+Dispatching
+***********
+
+    The resource is not the storage object. The resource is not a mechanism
+    that the server uses to handle the storage object. The resource is a
+    conceptual mapping -- the server receives the identifier (which identifies
+    the mapping) and applies it to its current mapping implementation (usually
+    a combination of collection-specific deep tree traversal and/or hash tables)
+    to find the currently responsible handler implementation and the handler
+    implementation then selects the appropriate action+response based on the
+    request content. All of these implementation-specific issues are hidden
+    behind the Web interface; their nature cannot be assumed by a client that
+    only has access through the Web interface.
+    
+    `Roy Fielding <http://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm>`_
+
+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.
+
+For the user, a web application is just like a website with static files.
+The user types (or clicks) a URL, and gets to the desired webpage. A
+conventional webserver uses the URL to retrieve a static file from the
+filesystem. A web application server, on the other hand, not only serves
+the content from static files; it can also map the URL it receives into some
+object and call it. The result is then sent back to the user's browser,
+where it is rendered into a viewable page. The result is a dynamic web
+application; for each URL, a unique object can be called into action.
+The key to understand how to write a new web application is to understand
+how this mapping occurs.
+
+CherryPy takes the output of the appropriate page handler function, binds it
+to :attr:`cherrypy.response.body <cherrypy._cprequest.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 :attr:`cherrypy.response.status <cherrypy._cprequest.Response.status>`
+and :attr:`cherrypy.response.headers <cherrypy._cprequest.Response.headers>`
+as desired.
+
+Dispatchers
+===========
+
+Before CherryPy can call your page handlers, it has to know 1) where they are,
+and 2) which one to call for a given 'identifier' (URI). In CherryPy, we use
+a Dispatcher object to:
+
+1. Understand the arrangement of handlers
+2. Find the appropriate page handler function
+3. Wrap your actual handler function in a
+   :class:`PageHandler <cherrypy._cpdispatch.PageHandler>` object (see below)
+4. Set :attr:`cherrypy.request.handler <cherrypy._cprequest.Request.handler>`
+   (to the :class:`PageHandler <cherrypy._cpdispatch.PageHandler>` wrapper)
+5. Collect configuration entries into
+   :attr:`cherrypy.request.config <cherrypy._cprequest.Request.config>`
+6. Collect "virtual path" components
+
+CherryPy has a default arrangement of handlers (see next), but also allows you
+to trade it for any arrangement you can think up and implement.
+
+.. _defaultdispatcher:
+
+Default Dispatcher
+------------------
+
+By default, CherryPy uses a fairly straightforward mapping procedure. The root
+of the site is the :attr:`Application.root <cherrypy._cptree.Application.root>`
+object. When it receives a URL, it breaks it into its path components, and
+proceeds looking down into the site until it finds an object that is the
+'best match' for that particular URL. For each path component it tries to find
+an object with the same name, starting from ``root``, and going down for each
+component it finds, until it can't find a match. An example shows it better::
+
+    root = HelloWorld()
+    root.onepage = OnePage()
+    root.otherpage = OtherPage()
+
+In the example above, the URL ``http://localhost/onepage`` will point at the
+first object and the URL ``http://localhost/otherpage`` will point at the
+second one. As usual, this search is done automatically. But it goes even further::
+
+    root.some = Page()
+    root.some.page = Page()
+
+In this example, the URL ``http://localhost/some/page`` will be mapped to the
+``root.some.page`` object. If this object is exposed (or alternatively, its
+``index`` method is), it will be called for that URL.
+
+In our HelloWorld example, adding the ``http://onepage/`` mapping
+to ``OnePage().index`` could be done like this::
+
+    class OnePage(object):
+        def index(self):
+            return "one page!"
+        index.exposed = True
+
+    class HelloWorld(object):
+        onepage = OnePage()
+     
+        def index(self):
+            return "hello world"
+        index.exposed = True
+
+    cherrypy.quickstart(HelloWorld())
+
+Normal methods
+^^^^^^^^^^^^^^^
+
+.. index:: methods; normal
+
+CherryPy can directly call methods on the mounted objects, if it receives a
+URL that is directly mapped to them. For example::
+
+    def foo(self):
+        return 'Foo!'
+    foo.exposed = True
+    
+    root.foo = foo
+
+In the example, ``root.foo`` contains a function object, named ``foo``. When
+CherryPy receives a request for the ``/foo`` URL, it will automatically call
+the ``foo()`` function. Note that it can be a plain function, or a method of
+any object; any callable will do it.
+
+.. _indexmethods:
+
+Index methods
+^^^^^^^^^^^^^
+
+.. index:: index, methods; index
+
+The ``index`` method has a special role in CherryPy: it handles intermediate
+URI's that end in a slash; for example, the URI ``/orders/items/`` might map
+to ``root.orders.items.index``. The ``index`` method can take additional
+keyword arguments if the request includes querystring or POST params; see
+:ref:`kwargs`, next. However,
+unlike all other page handlers, it *cannot* take positional arguments (see
+:ref:`args`, below).
+
+The default dispatcher will always try to find a method named `index` at the
+end of the branch traversal. In the example above, the URI "/onepage/" would
+result in the call: ``app.root.onepage.index()``. Depending on the use of the
+:func:`trailing_slash Tool <cherrypy.lib.cptools.trailing_slash>`,
+that might be interrupted with an HTTPRedirect, but
+otherwise, both ``"/onepage"`` (no trailing slash) and ``"/onepage/"``
+(trailing slash) will result in the same call.
+
+.. _kwargs:
+
+Keyword Arguments
+^^^^^^^^^^^^^^^^^
+
+.. index:: forms, **kwargs
+
+Any page handler that is called by CherryPy (``index``, or any other suitable
+method) can receive additional data from HTML or other forms using
+*keyword arguments*. For example, the following login form sends the
+``username`` and the ``password`` as form arguments using the POST method::
+
+    <form action="doLogin" method="post">
+        <p>Username</p>
+        <input type="text" name="username" value="" 
+            size="15" maxlength="40"/>
+        <p>Password</p>
+        <input type="password" name="password" value="" 
+            size="10" maxlength="40"/>
+        <p><input type="submit" value="Login"/></p>
+        <p><input type="reset" value="Clear"/></p>
+    </form>
+
+The following code can be used to handle this URL::
+
+    class Root:
+        def doLogin(self, username=None, password=None):
+            # check the username & password
+            ...
+        doLogin.exposed = True
+
+Both arguments have to be declared as *keyword arguments*. The default value
+can be used either to provide a suitable default value for optional arguments,
+or to provide means for the application to detect if some values were missing
+from the request.
+
+CherryPy supports both the GET and POST method for HTML forms. Arguments are
+passed the same way, regardless of the original method used by the browser to
+send data to the web server.
+
+.. _args:
+
+Positional Arguments
+^^^^^^^^^^^^^^^^^^^^
+
+.. index:: path, virtual path, path segments, *args, positional arguments
+
+When a request is processed, the URI is split into its components, and each
+one is matched in order against the nodes in the tree. Any trailing components
+are "virtual path" components and are passed as positional arguments. For
+example, the URI ``"/branch/leaf/4"`` might result in
+the call: ``app.root.branch.leaf(4)``, or ``app.root.index(branch, leaf, 4)``
+depending on how you have your handlers arranged.
+
+Partial matches can happen when a URL contains components that do not map to
+the object tree. This can happen for a number of reasons. For example, it may
+be an error; the user just typed the wrong URL. But it also can mean that the
+URL contains extra arguments.
+
+For example, assume that you have a blog-like application written in CherryPy
+that takes the year, month and day as part of the URL
+``http://localhost/blog/2005/01/17``. This URL can be handled by the
+following code::
+
+    class Root:
+        def blog(self, year, month, day):
+            ...
+        blog.exposed = True
+    
+    root = Root()
+
+So the URL above will be mapped as a call to::
+
+    root.blog('2005', '1', '17')
+
+In this case, there is a partial match up to the ``blog`` component. The rest
+of the URL can't be found in the mounted object tree. In this case, the
+``blog()`` method will be called, and the positional parameters will
+receive the remaining path segments as arguments. The values are passed as
+strings; in the above mentioned example, the arguments would still need to be
+converted back into numbers, but the idea is correctly presented.
+
+.. _defaultmethods:
+
+Default methods
+^^^^^^^^^^^^^^^
+
+.. index:: default, methods; default
+
+If the default dispatcher is not able to locate a suitable page handler by
+walking down the tree, it has a last-ditch option: it starts walking back
+''up'' the tree looking for `default` methods. Default methods work just like
+any other method with positional arguments, but are defined one level further
+down, in case you have multiple methods to expose. For example, we could have
+written the above "blog" example equivalently with a "default" method instead::
+
+    class Blog:
+        def default(self, year, month, day):
+            ...
+        default.exposed = True
+    
+    class Root: pass
+    
+    root = Root()
+    root.blog = Blog()
+
+So the URL ``http://localhost/blog/2005/01/17`` will be mapped as a call to::
+
+    root.blog.default('2005', '1', '17')
+
+You could achieve the same effect by defining a ``__call__`` method in this
+case, but "default" just reads better. ;)
+
+Special characters
+^^^^^^^^^^^^^^^^^^
+
+You can use dots in a URI like ``/path/to/my.html``, but Python method names
+don't allow dots. To work around this, the default dispatcher converts all dots
+in the URI to underscores before trying to find the page handler. In the
+example, therefore, you would name your page handler "def my_html". However,
+this means the page is also available at the URI ``/path/to/my_html``.
+If you need to protect the resource (e.g. with authentication), **you must
+protect both URLs**.
+
+.. versionadded:: 3.2
+   The default dispatcher now takes a 'translate' argument, which converts all
+   characters in string.punctuation to underscores using the builtin
+   :meth:`str.translate <str.translate>` method of string objects.
+   You are free to specify any other translation string of length 256.
+
+Other Dispatchers
+-----------------
+
+But Mr. Fielding mentions two kinds of "mapping implementations" above: trees
+and hash tables ('dicts' in Python). Some web developers claim trees are
+difficult to change as an application evolves, and prefer to use dicts
+(or a list of tuples) instead. Under these schemes, the mapping key is often
+a regular expression, and the value is the handler function. For example::
+
+    def root_index(name):
+        return "Hello, %s!" % name
+
+    def branch_leaf(size):
+        return str(int(size) + 3)
+
+    mappings = [
+        (r'^/([^/]+)$', root_index),
+        (r'^/branch/leaf/(\d+)$', branch_leaf),
+        ]
+
+CherryPy allows you to use a :class:`Dispatcher<cherrypy._cpdispatch.Dispatcher>`
+other than the default if you wish. By using another
+:class:`Dispatcher <cherrypy._cpdispatch.Dispatcher>` (or writing your own),
+you gain complete control over the arrangement and behavior of your page
+handlers (and config). To use another dispatcher, set the
+``request.dispatch`` config entry to the dispatcher you like::
+
+    d = cherrypy.dispatch.RoutesDispatcher()
+    d.connect(name='hounslow', route='hounslow', controller=City('Hounslow'))
+    d.connect(name='surbiton', route='surbiton', controller=City('Surbiton'),
+              action='index', conditions=dict(method=['GET']))
+    d.mapper.connect('surbiton', controller='surbiton',
+                     action='update', conditions=dict(method=['POST']))
+
+    conf = {'/': {'request.dispatch': d}}
+    cherrypy.tree.mount(root=None, config=conf)
+
+A couple of notes about the example above:
+
+* Since Routes has no controller hierarchy, there's nothing to pass as a
+  root to :func:`cherrypy.tree.mount <cherrypy._cptree.Tree.mount>`;
+  pass ``None`` in this case.
+* Usually you'll use the same dispatcher for an entire app, so specifying it
+  at the root ("/") is common. But you can use different dispatchers for
+  different paths if you like.
+* Because the dispatcher is so critical to finding handlers (and their
+  ancestors), this is one of the few cases where you *cannot* use
+  :ref:`_cp_config <cp_config>`; it's a chicken-and-egg problem:
+  you can't ask a handler you haven't found yet how it wants to be found.
+* Since Routes are explicit, there's no need to set the ``exposed`` attribute.
+  **All routes are always exposed.**
+
+CherryPy ships with additional Dispatchers in :mod:`cherrypy._cpdispatch`.
+
+.. _pagehandlers:
+
+PageHandler Objects
+===================
+
+Because the Dispatcher sets
+:attr:`cherrypy.request.handler <cherrypy._cprequest.Request.handler>`,
+it can also control
+the input and output of that handler function by wrapping the actual handler.
+The default Dispatcher passes "virtual path" components as positional arguments
+and passes query-string and entity (GET and POST) parameters as keyword
+arguments. It uses a :class:`PageHandler <cherrypy._cpdispatch.PageHandler>`
+object for this, which looks a lot like::
+
+    class PageHandler(object):
+        """Callable which sets response.body."""
+        
+        def __init__(self, callable, *args, **kwargs):
+            self.callable = callable
+            self.args = args
+            self.kwargs = kwargs
+        
+        def __call__(self):
+            return self.callable(*self.args, **self.kwargs)
+
+The actual default PageHandler is a little bit more complicated (because the
+args and kwargs are bound later), but you get the idea. And you can see how
+easy it would be to provide your own behavior, whether your own inputs or your
+own way of modifying the output. Remember, whatever is returned from the
+handler will be bound to
+:attr:`cherrypy.response.body <cherrypy._cprequest.Response.body>` and will
+be used as the response entity.
+
+Replacing page handlers
+-----------------------
+
+The handler that's going to be called during a request is available at
+:attr:`cherrypy.request.handler <cherrypy._cprequest.Request.handler`,
+which means your code has a chance to replace it before the handler runs.
+It's a snap to write a Tool to do so with a
+:class:`HandlerWrapperTool <cherrypy._cptools.HandlerWrapperTool>`::
+
+    to_skip = (KeyboardInterrupt, SystemException, cherrypy.HTTPRedirect)
+    def PgSQLWrapper(next_handler, *args, **kwargs):
+        trans.begin()
+        try:
+            result = next_handler(*args, **kwargs)
+            trans.commit()
+        except Exception, e:
+            if not isinstance(e, to_skip):
+                trans.rollback()
+            raise
+        trans.end()
+        return result
+
+    cherrypy.tools.pgsql = cherrypy._cptools.HandlerWrapperTool(PgSQLWrapper)
+
+Configuration
+=============
+
+The default arrangement of CherryPy handlers is a tree. This enables a very
+powerful configuration technique: config can be attached to a node in the tree
+and cascade down to all children of that node. Since the mapping of URI's to
+handlers is not always 1:1, this provides a flexibility which is not as easily
+definable in other, flatter arrangements.
+
+However, because the arrangement of config is directly related to the
+arrangement of handlers, it is the responsibility of the Dispatcher to collect
+per-handler config, merge it with per-URI and global config, and bind the
+resulting dict to :attr:`cherrypy.request.config <cherrypy._cprequest.Request.config>`.
+This dict is of depth 1 and will contain all config entries which are in
+effect for the current request.
+

sphinx/source/concepts/engine.rst

+*******************
+The CherryPy Engine
+*******************
+
+The :class:`cherrypy.engine<cherrypy.process.wspbus.Bus>` object contains and
+manages site-wide behavior: daemonization, HTTP server start/stop, process
+reload, signal handling, drop privileges, PID file management, logging for
+all of these, and many more.
+
+Any task that needs to happen outside of the request process is managed by
+the Engine via *Plugins*. You can add your own site-wide
+behaviors, too; see :doc:`/progguide/extending/customplugins`. The Engine
+handles these tasks whether you start your site from a script, from an external
+server process like Apache, or via :doc:`cherryd</deployguide/cherryd>`.
+
+State Management
+================
+
+The Engine manages the *state* of the site. Engine methods like
+:func:`cherrypy.engine.start<cherrypy.process.wspbus.start>` move it
+from one state to another::
+
+                        O
+                        |
+                        V
+       STOPPING --> STOPPED --> EXITING -> X
+          A   A         |
+          |    \___     |
+          |        \    |
+          |         V   V
+        STARTED <-- STARTING
+
+Note in particular that the Engine allows you to stop and restart it again
+without stopping the process. This can be used to build highly dynamic sites,
+and is invaluable for debugging live servers.
+
+.. _channels:
+
+Channels
+========
+
+The Engine uses topic-based publish-subscribe messaging to manage event-driven
+behaviors like autoreload and daemonization. When the Engine moves from one
+state to another, it *publishes* a message on a *channel* named after the
+activity. For example, when you call
+:func:`cherrypy.engine.start<cherrypy.process.wspbus.start>`, the Engine
+moves from the STOPPED state to the STARTING state, publishes a message on
+the "start" *channel*, and then moves to the STARTED state.
+
+.. _plugins:
+
+Plugins
+=======
+
+Engine Plugins package up channel listeners into easy-to-use components.
+
+Engine Plugins have a :func:`subscribe<cherrypy.process.plugins.SimplePlugin.subscribe>`
+method which you can use to "turn them on"; that is, they will start listening
+for messages published on event channels. For example, to turn on PID file
+management::
+
+    from cherrypy.process.plugins import PIDFile
+    p = PIDFile(cherrypy.engine, "/var/run/myapp.pid")
+    p.subscribe()
+
+If you want to turn off a plugin, call ``p.unsubscribe()``.
+
+The following builtin plugins are subscribed by default:
+
+ * :doc:`Timeout Monitor</progguide/responsetimeouts>`
+ * :class:`Autoreloader<cherrypy.process.plugins.Autoreloader>` (off in the "production" :ref:`environment<environments>`)
+ * :class:`cherrypy.server<cherrypy._cpserver.Server>`
+ * :class:`cherrypy.checker<cherrypy._cpchecker.Checker>`
+ * Engine log messages go to :class:`cherrypy.log<cherrypy._GlobalLogManager>`.
+ * A :class:`Signal Handler<cherrypy.process.plugins.SignalHandler>`.
+

sphinx/source/concepts/exposing.rst

+********
+Exposing
+********
+
+Any object that is attached to the root object is traversible via the internal
+URL-to-object mapping routine. However, it does not mean that the object itself
+is directly accessible via the Web. For this to happen, the object has to be
+**exposed**.
+
+Exposing objects
+----------------
+
+CherryPy maps URL requests to objects and invokes the suitable callable
+automatically. The callables that can be invoked as a result of external
+requests are said to be **exposed**.
+
+Objects are **exposed** in CherryPy by setting the ``exposed`` attribute.
+Most often, a method on an object is the callable that is to be invoked. In
+this case, one can directly set the exposed attribute::
+
+    class Root:
+        def index(self):
+            ...
+        index.exposed = True
+
+
+or use a decorator::
+
+        @cherrypy.expose
+        def index(self):
+            ...
+
+
+When it is a special method, such as ``__call__``, that is to be invoked,
+the exposed attribute must be set on the class itself::
+
+    class Node:
+        exposed = True
+        def __call__(self):
+            ...
+
+

sphinx/source/concepts/index.rst

+*********************
+Tutorial and Concepts
+*********************
+
+What is this tutorial about?
+============================
+
+This tutorial covers the basic steps for a newcomer to come to grips with
+CherryPy's unique approach to web application development. After following
+this tutorial, you will be able to understand how CherryPy
+applications work, and also to implement simple but yet powerful applications
+on your own. Some knowledge of the Python programming language is assumed.
+One does not need to be an expert to work with CherryPy, but a good
+understanding of object-oriented basics is strongly recommended.
+
+This tutorial only covers the basic features of CherryPy, but it tries to
+present them in a way that makes it easier for you to discover how to
+use them. The CherryPy distribution comes with several good tutorial applications;
+however, the best way to master CherryPy is to use it to write your own
+Web applications. The embedded web server makes it easy for anyone not only
+to try, but also to deploy local applications, or even small Internet-enabled
+web sites. Try it, and let us know what you did with it!
+
+Knowledge required
+------------------
+
+It is assumed that the user has:
+
+ * Some knowledge of the Python programming language
+ * Some experience with basic object oriented programming
+ * Some knowledge of HTML, which is necessary to build the Web pages
+
+Learning Python
+---------------
+
+As stated above, this is not a guide to the Python language. There are plenty of
+good resources for those learning Python (just to name a few among the best:
+`Python course in Bioinformatics <http://www.pasteur.fr/recherche/unites/sis/formation/python/>`_,
+`A Byte Of Python <http://www.byteofpython.info/>`_ and
+`Dive into Python <http://www.diveintopython.org/>`_).
+The `official Python website <http://www.python.org>`_ lists some good
+resources, including an excellent
+`tutorial <http://docs.python.org/tut/tut.html>`_.
+
+Start the Tutorial
+==================
+
+.. toctree::
+   :maxdepth: 2
+
+   basics
+   exposing
+   dispatching
+   config
+   tools
+   engine
+

sphinx/source/concepts/tools.rst

+*****
+Tools
+*****
+
+CherryPy core is extremely light and clean. It contains only the necessary
+features to support the HTTP protocol and to call the correct object for
+each request. Additional request-time features can be added to it using
+**modular tools**.
+
+Tools are a great way to package up behavior that happens outside your page
+handlers. A tool is an object that has a chance to work on a request as it
+goes through the usual CherryPy processing stages, both before and after it
+gets to your handler. Several tools are provided
+as part of the standard CherryPy library, available in
+:mod:`cherrypy.tools <cherrypy._cptools>`. See :doc:`/progguide/builtintools`.
+
+Tools provide a lot of flexibility. Different tools can be applied to different
+parts of the site, and the order of tools can be changed. The user can write
+custom tools for special applications, changing the behavior of CherryPy
+without the need to change its internals.
+See :doc:`/progguide/extending/customtools`.
+
+Using Tools
+===========
+
+Config Files
+------------
+
+You can turn on Tools in config, whether a file or a dict.
+For example, you can add static directory serving with the builtin
+``staticdir`` tool with just a few lines in your config file::
+
+    [/docroot]
+    tools.staticdir.on: True
+    tools.staticdir.root: "/path/to/app"
+    tools.staticdir.dir: 'static'
+
+This turns on the ``staticdir`` tool for all *URLs* that start with "/docroot".
+
+_cp_config
+----------
+
+You can also enable and configure tools *per controller* or *per handler*
+using :ref:`_cp_config <cp_config>`::
+
+    class docroot(object):
+
+        _cp_config = {'tools.staticdir.on': True,
+                      'tools.staticdir.root: "/path/to/app",
+                      'tools.staticdir.dir': 'static'}
+
+Decorators
+----------
+
+But we can do even better by using the **builtin decorator support** that all
+Tools have::
+
+    class docroot(object):
+
+        @tools.staticdir(root="/path/to/app", dir='static')
+        def page(self):
+           # ...
+
+
+Page Handlers
+-------------
+
+...and in this case, we can do even **better** because tools.staticdir is a
+:class:`HandlerTool <cherrypy._cptools.HandlerTool>`, and therefore can be
+used directly as a page handler::
+
+    class docroot(object):
+
+        static = tools.staticdir.handler(
+                     section='static', root="/path/to/app", dir='static')
+
+Direct invocation
+-----------------
+
+Finally, you can use (most) Tools directly, by calling the function they wrap.
+They expose this via the 'callable' attribute::
+
+    def page(self):
+        tools.response_headers.callable([('Content-Language', 'fr')])
+        return "Bonjour, le Monde!"
+    page.exposed = True
+
+help(Tool)
+==========
+
+Because the underlying function is wrapped in a tool, you need to call
+``help(tools.whatevertool.callable)`` if you want the docstring for it.
+Using ``help(tools.whatevertool)`` will give you help on how to use it
+as a Tool (for example, as a decorator).
+
+Tools also are also **inspectable** automatically. They expose their own
+arguments as attributes::
+
+    >>> dir(cherrypy.tools.session_auth)
+    [..., 'anonymous', 'callable', 'check_username_and_password',
+    'do_check', 'do_login', 'do_logout', 'handler', 'login_screen',
+    'on_check', 'on_login', 'on_logout', 'run', 'session_key']
+
+This makes IDE calltips especially useful, even when writing config files!
+

sphinx/source/deployguide/configlist.rst

-*******************
-Configuration items
-*******************
-

sphinx/source/deployguide/index.rst

 Deployment Guide
 ****************
 
+Servers
+=======
+
 .. toctree::
    :maxdepth: 2
 
    apache
-   cherryd
-   configlist
-   /refman/process/plugins/daemonizer
-   /refman/process/plugins/dropprivileges
    /refman/process/servers
-   /refman/process/plugins/pidfile
-   /refman/process/plugins/signalhandler
    standalone
    wsgiserver
 
 
+Environment
+===========
+
+.. toctree::
+   :maxdepth: 2
+
+   cherryd
+   /refman/process/plugins/daemonizer
+   /refman/process/plugins/dropprivileges
+   /refman/process/plugins/pidfile
+   /refman/process/plugins/signalhandler
+
+

sphinx/source/index.rst

    :hidden:
 
    intro/index
+   concepts/index
    progguide/index
    deployguide/index
    refman/index
 ---------------------------------
 *The who, what, and why of CherryPy*
 
+:doc:`Concepts <concepts/index>`
+---------------------------------
+*The basics of CherryPy*
+
 :doc:`Programmer's Guide <progguide/index>`
 -------------------------------------------
 *How to perform common tasks*

sphinx/source/intro/concepts/basics.rst

-*******************************
-Your first CherryPy application
-*******************************
-
-The standard 'Hello world!' application takes less than 10 lines of code
-when written using CherryPy::
-
-    import cherrypy
-    
-    class HelloWorld:
-        def index(self):
-            return "Hello world!"
-        index.exposed = True
-    
-    cherrypy.quickstart(HelloWorld())
-
-We assume that you already have :doc:`installed </intro/install>` CherryPy.
-Copy the file above and save it locally as ``hello.py``, then start the
-application at the command prompt::
-
-    $ python hello.py
-
-Direct your favorite web browser to http://localhost:8080 and you should
-see ``Hello world!`` printed there.
-
-How does it work?
------------------
-
-Let's take a look at ``hello.py``:
-
- * The ``import cherrypy`` statement imports the main CherryPy module.
-   This is all that is required to have CherryPy working. Feel free to
-   "import cherrypy" in an interactive session and see what's available!
-   ``help(cherrypy)`` is also quite useful.
- * We declare a class named ``HelloWorld``. An instance of this class is the
-   object that will be published by CherryPy. It contains a single method,
-   named ``index``, which will get called when the root URL for the site is
-   requested (for example, ``http://localhost/``). This method returns the
-   **contents** of the Web page; in this case, the ``'Hello World!'`` string.
-   Note that you don't have to subclass any framework-provided classes; in fact,
-   you don't even have to use classes at all! But let's start with them for now.
- * The ``index.exposed = True`` is a necessary step to tell CherryPy that the
-   ``index()`` method will be **exposed**. Only exposed methods can be called
-   to answer a request. This feature allows the user to select which methods
-   of an object will be accessible via the Web; non-exposed methods can't be
-   accessed.
- * ``cherrypy.quickstart(HelloWorld())`` mounts an instance of the HelloWorld
-   class, and starts the embedded webserver. It runs until explicitly
-   interrupted, either with ``Ctrl-C`` or via a suitable signal (a simple
-   ``kill`` on Unix will do it).
-
-When the application is executed, the CherryPy server is started with the
-default configuration. It will listen on ``localhost`` at port ``8080``. These
-defaults can be overridden by using a configuration file or dictionary
-(more on this later).
-
-Finally, the web server receives the request for the URL
-``http://localhost:8080``. It searches for the best method to handle the
-request, starting from the ``HelloWorld`` instance. In this particular case,
-the root of the site is automatically mapped to the ``index()`` method (similar
-to the ``index.html`` that is the standard page for conventional Web servers).
-The HelloWorld class defines an ``index()`` method and exposes it. CherryPy
-calls ``HelloWorld().index()``, and the result of the call is sent back to
-the browser as the contents of the index page for the website. All the
-dispatching and HTTP-processing work is
-done automatically; the application programmer only needs to provide the
-desired content as the return value of the ``index`` method.
-
-CherryPy structure
-------------------
-
-Most of the features of CherryPy are available through the :mod:`cherrypy`
-module. It contains several members:
-
- * :class:`cherrypy.engine <cherrypy.process.wspbus.Bus>`
-   controls process startup, shutdown, and other events, including your own
-   Plugins. See :doc:`/intro/concepts/engine`.
- * :class:`cherrypy.server <cherrypy._cpserver.Server>` configures and controls
-   the HTTP server.
- * :class:`cherrypy.request <cherrypy._cprequest.Request>` contains all
-   the information that comes with the HTTP request, after it is parsed and
-   analyzed by CherryPy.
- * :attr:`cherrypy.request.headers <cherrypy.lib.httputil.HeaderMap>`
-   contains a mapping with the header options that were sent as part of
-   the request.
- * :class:`cherrypy.session <cherrypy.lib.sessions.Session>` is a special
-   mapping that is automatically generated and encoded by CherryPy; it can
-   be used to store session-data in a persistent cookie. For it to work you
-   have to enable the session functionality by setting 'tools.session.on' to
-   True in your config. 
- * :class:`cherrypy.response <cherrypy._cprequest.Response>` contains the
-   data that is used to build the HTTP response. 
- * :attr:`cherrypy.response.headers <cherrypy.lib.httputil.HeaderMap>`
-   contains a mapping with the header options that will be returned by the
-   server, before the contents get sent.
- * :attr:`cherrypy.response.body <cherrypy._cprequest.Response.body>` contains
-   the actual contents of the webpage that will be sent as a response.
-

sphinx/source/intro/concepts/config.rst

-:tocdepth: 3
-
-*************
-Configuration
-*************
-
-Configuration in CherryPy is implemented via dictionaries. Keys are strings
-which name the mapped value; values may be of any type.
-
-In CherryPy 3, you use configuration (files or dicts) to set attributes
-directly on the engine, server, request, response, and log objects. So the
-best way to know the full range of what's available in the config file is to
-simply import those objects and see what ``help(obj)`` tells you.
-
-Architecture
-============
-
-The first thing you need to know about CherryPy 3's configuration is that it
-separates *global* config from *application* config. If you're deploying
-multiple *applications* at the same *site* (and more and more people are,
-as Python web apps are tending to decentralize), you need to be careful to
-separate the configurations, as well. There's only ever one "global config",
-but there is a separate "app config" for each app you deploy.
-
-CherryPy *Requests* are part of an *Application*, which runs in a *global*
-context, and configuration data may apply to any of those three scopes.
-Let's look at each of those scopes in turn.
-
-Global config
--------------
-
-Global config entries apply everywhere, and are stored in
-:class:`cherrypy.config <cherrypy._cpconfig.Config>`. This flat dict only holds
-global config data; that is, "site-wide" config entries which affect all
-mounted applications.
-
-Global config is stored in the
-:class:`cherrypy.config <cherrypy._cpconfig.Config>` dict,
-and you therefore update it by calling ``cherrypy.config.update(conf)``.
-The ``conf`` argument can be either a filename, an open file, or a dict of
-config entries. Here's an example of passing a dict argument::
-
-    cherrypy.config.update({'server.socket_host': '64.72.221.48',
-                            'server.socket_port': 80,
-                           })
-
-The ``server.socket_host`` option n this example determines on which network
-interface CherryPy will listen. The ``server.socket_port`` option declares
-the TCP port on which to listen.
-
-Application config
-------------------
-
-Application entries apply to a single mounted application, and are stored on
-each Application object itself as
-:attr:`app.config <cherrypy._cptree.Application.config>`. This is a two-level
-dict where each top-level key is a path, or "relative URL" (for example,
-``"/"`` or ``"/my/page"``), and each value is a dict of config entries.
-The URL's are relative to the script name (mount point) of the Application.
-Usually, all this data is provided in the call to
-``tree.mount(root(), script_name='/path/to', config=conf)``,
-although you may also use ``app.merge(conf)``.
-The ``conf`` argument can be either a filename, an open file, or a dict of
-config entries.
-
-Configuration file example::
-
-    [/]
-    tools.trailing_slash.on = False
-    request.dispatch: cherrypy.dispatch.MethodDispatcher()
-
-or, in python code::
-
-    config = {'/': 
-        {
-            'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
-            'tools.trailing_slash.on': False,
-        }
-    }
-    cherrypy.tree.mount(Root(), "/", config=config)
-
-CherryPy doesn't use any sections that don't start with ``"/"`` (except
-``[global]``, see below). That means you can place your own configuration
-entries in a CherryPy config file by giving them a section name which does not
-start with ``"/"``. For example, you might include database entries like this::
-
-    [global]
-    server.socket_host: "0.0.0.0"
-
-    [Databases]
-    driver: "postgres"
-    host: "localhost"
-    port: 5432
-
-    [/path]
-    response.timeout: 6000
-
-Then, in your application code you can read these values during request time
-via ``cherrypy.request.app.config['Databases']``. For code that is outside the
-request process, you'll have to pass a reference to your Application around.
-
-Request config
---------------
-
-Each Request object possesses a single
-:attr:`request.config <cherrypy._cprequest.Request.config>` dict. Early in the
-request process, this dict is populated by merging Global config, Application
-config, and any config acquired while looking up the page handler (see next).
-This dict contains only those config entries which apply to the given request.
-
-.. note::
-
-   when you do an :class:`InternalRedirect<cherrypy._cperror.InternalRedirect`,
-   this config attribute is recalculated for the new path.
-
-Declaration
-===========
-
-Configuration data may be supplied as a Python dictionary, as a filename,
-or as an open file object.
-
-Configuration files
--------------------
-
-When you supply a filename or file, CherryPy uses Python's builtin ConfigParser;
-you declare Application config by writing each path as a section header,
-and each entry as a ``"key: value"`` (or ``"key = value"``) pair::
-
-    [/path/to/my/page]
-    response.stream: True
-    tools.trailing_slash.extra = False
-
-Combined Configuration Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-If you are only deploying a single application, you can make a single config
-file that contains both global and app entries. Just stick the global entries
-into a config section named ``[global]``, and pass the same file to both
-:func:`config.update <cherrypy._cpconfig.Config.update>` and
-:func:`tree.mount <cherrypy._cptree.Tree.mount`. If you're calling
-``cherrypy.quickstart(app root, script name, config)``, it will pass the
-config to both places for you. But as soon as you decide to add another
-application to the same site, you need to separate the two config files/dicts.
-
-Separate Configuration Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-If you're deploying more than one application in the same process, you need
-(1) file for global config, plus (1) file for *each* Application.
-The global config is applied by calling
-:func:`cherrypy.config.update <cherrypy._cpconfig.Config.update>`,
-and application config is usually passed in a call to
-:func:`cherrypy.tree.mount <cherrypy._cptree.Tree.mount>`.
-
-In general, you should set global config first, and then mount each
-application with its own config. Among other benefits, this allows you to set
-up global logging so that, if something goes wrong while trying to mount
-an application, you'll see the tracebacks. In other words, use this order::
-
-    # global config
-    cherrypy.config.update({'environment': 'production',
-                            'log.error_file': 'site.log',
-                            # ...
-                            })
-
-    # Mount each app and pass it its own config
-    cherrypy.tree.mount(root1, "/", appconf1)
-    cherrypy.tree.mount(root2, "/forum", appconf2)
-    cherrypy.tree.mount(root3, "/blog", appconf3)
-
-    if hasattr(cherrypy.engine, 'block'):
-        # 3.1 syntax
-        cherrypy.engine.start()
-        cherrypy.engine.block()
-    else:
-        # 3.0 syntax
-        cherrypy.server.quickstart()
-        cherrypy.engine.start()
-
-Values in config files use Python syntax
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Config entries are always a key/value pair, like ``server.socket_port = 8080``.
-The key is always a name, and the value is always a Python object. That is,
-if the value you are setting is an ``int`` (or other number), it needs to look
-like a Python ``int``; for example, ``8080``. If the value is a string, it
-needs to be quoted, just like a Python string. Arbitrary objects can also be
-created, just like in Python code (assuming they can be found/imported).
-Here's an extended example, showing you some of the different types::
-
-    [global]
-    log.error_file: "/home/fumanchu/myapp.log"
-    environment = 'production'
-    server.max_request_body_size: 1200
-
-    [/myapp]
-    tools.trailing_slash.on = False
-    request.dispatch: cherrypy.dispatch.MethodDispatcher()
-
-.. _cp_config:
-
-_cp_config: attaching config to handlers
-----------------------------------------
-
-Config files have a severe limitation: values are always keyed by URL.
-For example::
-
-    [/path/to/page]
-    methods_with_bodies = ("POST", "PUT", "PROPPATCH")
-
-It's obvious that the extra method is the norm for that path; in fact,
-the code could be considered broken without it. In CherryPy, you can attach
-that bit of config directly on the page handler::
-
-    def page(self):
-        return "Hello, world!"
-    page.exposed = True
-    page._cp_config = {"request.methods_with_bodies": ("POST", "PUT", "PROPPATCH")}
-
-``_cp_config`` is a reserved attribute which the dispatcher looks for at
-each node in the object tree. The ``_cp_config`` attribute must be a CherryPy
-config dictionary. If the dispatcher finds a ``_cp_config`` attribute,
-it merges that dictionary into the rest of the config. The entire merged
-config dictionary is placed in
-:attr:`cherrypy.request.config <cherrypy._cprequest.Request.config>`.
-
-This can be done at any point in the tree of objects; for example, we could have
-attached that config to a class which contains the page method::
-
-    class SetOPages:
-
-        _cp_config = {"request.methods_with_bodies": ("POST", "PUT", "PROPPATCH")}
-
-        def page(self):
-            return "Hullo, Werld!"
-        page.exposed = True
-
-.. note::
-
-   This behavior is only guaranteed for the default dispatcher. Other
-   dispatchers may have different restrictions on where you can attach
-   ``_cp_config`` attributes.
-
-This technique allows you to:
-
- * Put config near where it's used for improved readability and maintainability.
- * Attach config to objects instead of URL's. This allows multiple URL's to
-   point to the same object, yet you only need to define the config once.
- * Provide defaults which are still overridable in a config file.
-
-.. _namespaces:
-
-Namespaces
-==========
-
-Because config entries usually just set attributes on objects, they're almost
-all of the form: ``object.attribute``. A few are of the form:
-``object.subobject.attribute``. They look like normal Python attribute chains,
-because they work like them. We call the first name in the chain the
-*"config namespace"*. When you provide a config entry, it is bound as early
-as possible to the actual object referenced by the namespace; for example,
-the entry ``response.stream`` actually sets the ``stream`` attribute of
-:class:`cherrypy.response <cherrypy._cprequest.Response>`! In this way,
-you can easily determine the default value by firing up a python interpreter
-and typing::
-
-    >>> import cherrypy
-    >>> cherrypy.response.stream
-    False
-
-Each config namespace has its own handler; for example, the "request" namespace
-has a handler which takes your config entry and sets that value on the
-appropriate "request" attribute. There are a few namespaces, however, which
-don't work like normal attributes behind the scenes; however, they still use
-dotted keys and are considered to "have a namespace".
-
-Builtin namespaces
-------------------
-
-========    =======================
-engine      Controls the 'application engine', including autoreload. These can only be declared in the global config.
-hooks       Declares additional request-processing functions.
-log         Configures the logging for each application. These can only be declared in the global or / config.
-request     Adds attributes to each Request.
-response    Adds attributes to each Response.
-server      Controls the default HTTP server via cherrypy.server. These can only be declared in the global config.
-tools       Runs and configures additional request-processing packages.
-wsgi        Adds WSGI middleware to an Application's "pipeline". These can only be declared in the app's root config ("/").
-checker     Controls the 'checker', which looks for common errors in app state (including config) when the engine starts. Global config only.
-========    =======================
-
-Entries from each namespace may be allowed 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
-==========  ======  ==================  =========
-
-Custom config namespaces
-------------------------
-
-You can define your own namespaces if you like, and they can do far more than
-simply set attributes. The ``test/test_config`` module, for example, shows an
-example of a custom namespace that coerces incoming params and outgoing body
-content. The :mod:`cherrypy._cpwsgi` module includes an additional, builtin
-namespace for invoking WSGI middleware.
-
-In essence, a config namespace handler is just a function, that gets passed
-any config entries in its namespace. You add it to a namespaces registry
-(a dict), where keys are namespace names and values are handler functions.
-When a config entry for your namespace is encountered, the corresponding
-handler function will be called, passing the config key and value; that is,
-``namespaces[namespace](k, v)``. For example, if you write::
-
-    def db_namespace(k, v):
-        if k == 'connstring':
-            orm.connect(v)
-    cherrypy.config.namespaces['db'] = db_namespace
-
-then ``cherrypy.config.update({"db.connstring": "Oracle:host=1.10.100.200;sid=TEST"})``
-will call ``db_namespace('connstring', 'Oracle:host=1.10.100.200;sid=TEST')``.
-
-The point at which your namespace handler is called depends on where you add it:
-
-===========  =============================================================================  ===================================
-Scope        Namespace dict                                                                 Handler is called in  
------------  -----------------------------------------------------------------------------  -----------------------------------
-Global       :attr:`cherrypy.config.namespaces <cherrypy._cpconfig.Config.namespaces>`      cherrypy.config.update
-Application  :attr:`app.namespaces <cherrypy._cptree.Application.namespaces>`               Application.merge (which is called by cherrypy.tree.mount)
-Request      :attr:`app.request_class.namespaces <cherrypy._cprequest.Request.namespaces>`  Request.configure (called for each request, after the handler is looked up)
-===========  =============================================================================  ===================================
-
-The name can be any string, and the handler must be either a callable or a
-(Python 2.5 style) context manager.
-
-If you need additional code to run when all your namespace keys are collected,
-you can supply a callable context manager in place of a normal function for
-the handler. Context managers are defined in :pep:`343`.
-
-.. _environments:
-
-Environments
-============
-
-The only key that does not exist in a namespace is the *"environment"* entry.
-This special entry *imports* other config entries from a template stored in
-``cherrypy._cpconfig.environments[environment]``. It only applies to the
-global config, and only when you use
-:func:`cherrypy.config.update <cherrypy._cpconfig.Config.update>`.
-
-If you find the set of existing environments (production, staging, etc) too
-limiting or just plain wrong, feel free to extend them or add new environments::
-
-    cherrypy._cpconfig.environments['staging']['log.screen'] = False
-
-    cherrypy._cpconfig.environments['Greek'] = {
-        'tools.encode.encoding': 'ISO-8859-7',
-        'tools.decode.encoding': 'ISO-8859-7',
-        }
-

sphinx/source/intro/concepts/dispatching.rst

-***********
-Dispatching
-***********
-
-    The resource is not the storage object. The resource is not a mechanism
-    that the server uses to handle the storage object. The resource is a
-    conceptual mapping -- the server receives the identifier (which identifies
-    the mapping) and applies it to its current mapping implementation (usually
-    a combination of collection-specific deep tree traversal and/or hash tables)
-    to find the currently responsible handler implementation and the handler
-    implementation then selects the appropriate action+response based on the
-    request content. All of these implementation-specific issues are hidden
-    behind the Web interface; their nature cannot be assumed by a client that
-    only has access through the Web interface.
-    
-    `Roy Fielding <http://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm>`_
-
-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.
-
-For the user, a web application is just like a website with static files.
-The user types (or clicks) a URL, and gets to the desired webpage. A
-conventional webserver uses the URL to retrieve a static file from the
-filesystem. A web application server, on the other hand, not only serves
-the content from static files; it can also map the URL it receives into some
-object and call it. The result is then sent back to the user's browser,
-where it is rendered into a viewable page. The result is a dynamic web
-application; for each URL, a unique object can be called into action.
-The key to understand how to write a new web application is to understand
-how this mapping occurs.
-
-CherryPy takes the output of the appropriate page handler function, binds it
-to :attr:`cherrypy.response.body <cherrypy._cprequest.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 :attr:`cherrypy.response.status <cherrypy._cprequest.Response.status>`
-and :attr:`cherrypy.response.headers <cherrypy._cprequest.Response.headers>`
-as desired.
-
-Dispatchers
-===========
-
-Before CherryPy can call your page handlers, it has to know 1) where they are,
-and 2) which one to call for a given 'identifier' (URI). In CherryPy, we use
-a Dispatcher object to:
-
-1. Understand the arrangement of handlers
-2. Find the appropriate page handler function
-3. Wrap your actual handler function in a
-   :class:`PageHandler <cherrypy._cpdispatch.PageHandler>` object (see below)
-4. Set :attr:`cherrypy.request.handler <cherrypy._cprequest.Request.handler>`
-   (to the :class:`PageHandler <cherrypy._cpdispatch.PageHandler>` wrapper)
-5. Collect configuration entries into
-   :attr:`cherrypy.request.config <cherrypy._cprequest.Request.config>`
-6. Collect "virtual path" components
-
-CherryPy has a default arrangement of handlers (see next), but also allows you
-to trade it for any arrangement you can think up and implement.
-
-.. _defaultdispatcher:
-
-Default Dispatcher
-------------------
-
-By default, CherryPy uses a fairly straightforward mapping procedure. The root
-of the site is the :attr:`Application.root <cherrypy._cptree.Application.root>`
-object. When it receives a URL, it breaks it into its path components, and
-proceeds looking down into the site until it finds an object that is the
-'best match' for that particular URL. For each path component it tries to find
-an object with the same name, starting from ``root``, and going down for each
-component it finds, until it can't find a match. An example shows it better::
-
-    root = HelloWorld()
-    root.onepage = OnePage()
-    root.otherpage = OtherPage()
-
-In the example above, the URL ``http://localhost/onepage`` will point at the
-first object and the URL ``http://localhost/otherpage`` will point at the
-second one. As usual, this search is done automatically. But it goes even further::
-
-    root.some = Page()
-    root.some.page = Page()
-
-In this example, the URL ``http://localhost/some/page`` will be mapped to the
-``root.some.page`` object. If this object is exposed (or alternatively, its
-``index`` method is), it will be called for that URL.
-
-In our HelloWorld example, adding the ``http://onepage/`` mapping
-to ``OnePage().index`` could be done like this::
-
-    class OnePage(object):
-        def index(self):
-            return "one page!"
-        index.exposed = True
-
-    class HelloWorld(object):
-        onepage = OnePage()
-     
-        def index(self):
-            return "hello world"
-        index.exposed = True
-
-    cherrypy.quickstart(HelloWorld())
-
-Normal methods
-^^^^^^^^^^^^^^^
-
-.. index:: methods; normal
-
-CherryPy can directly call methods on the mounted objects, if it receives a
-URL that is directly mapped to them. For example::
-
-    def foo(self):
-        return 'Foo!'
-    foo.exposed = True
-    
-    root.foo = foo
-
-In the example, ``root.foo`` contains a function object, named ``foo``. When
-CherryPy receives a request for the ``/foo`` URL, it will automatically call
-the ``foo()`` function. Note that it can be a plain function, or a method of
-any object; any callable will do it.
-
-.. _indexmethods:
-
-Index methods
-^^^^^^^^^^^^^
-
-.. index:: index, methods; index
-
-The ``index`` method has a special role in CherryPy: it handles intermediate
-URI's that end in a slash; for example, the URI ``/orders/items/`` might map
-to ``root.orders.items.index``. The ``index`` method can take additional
-keyword arguments if the request includes querystring or POST params; see
-:ref:`kwargs`, next. However,
-unlike all other page handlers, it *cannot* take positional arguments (see
-:ref:`args`, below).
-
-The default dispatcher will always try to find a method named `index` at the
-end of the branch traversal. In the example above, the URI "/onepage/" would
-result in the call: ``app.root.onepage.index()``. Depending on the use of the
-:func:`trailing_slash Tool <cherrypy.lib.cptools.trailing_slash>`,
-that might be interrupted with an HTTPRedirect, but
-otherwise, both ``"/onepage"`` (no trailing slash) and ``"/onepage/"``
-(trailing slash) will result in the same call.
-
-.. _kwargs:
-
-Keyword Arguments
-^^^^^^^^^^^^^^^^^
-
-.. index:: forms, **kwargs
-
-Any page handler that is called by CherryPy (``index``, or any other suitable
-method) can receive additional data from HTML or other forms using
-*keyword arguments*. For example, the following login form sends the
-``username`` and the ``password`` as form arguments using the POST method::
-
-    <form action="doLogin" method="post">
-        <p>Username</p>
-        <input type="text" name="username" value="" 
-            size="15" maxlength="40"/>
-        <p>Password</p>
-        <input type="password" name="password" value="" 
-            size="10" maxlength="40"/>
-        <p><input type="submit" value="Login"/></p>
-        <p><input type="reset" value="Clear"/></p>
-    </form>
-
-The following code can be used to handle this URL::
-
-    class Root:
-        def doLogin(self, username=None, password=None):
-            # check the username & password
-            ...
-        doLogin.exposed = True
-
-Both arguments have to be declared as *keyword arguments*. The default value
-can be used either to provide a suitable default value for optional arguments,
-or to provide means for the application to detect if some values were missing
-from the request.
-
-CherryPy supports both the GET and POST method for HTML forms. Arguments are
-passed the same way, regardless of the original method used by the browser to
-send data to the web server.
-
-.. _args:
-
-Positional Arguments
-^^^^^^^^^^^^^^^^^^^^
-
-.. index:: path, virtual path, path segments, *args, positional arguments
-
-When a request is processed, the URI is split into its components, and each
-one is matched in order against the nodes in the tree. Any trailing components
-are "virtual path" components and are passed as positional arguments. For
-example, the URI ``"/branch/leaf/4"`` might result in
-the call: ``app.root.branch.leaf(4)``, or ``app.root.index(branch, leaf, 4)``
-depending on how you have your handlers arranged.
-
-Partial matches can happen when a URL contains components that do not map to
-the object tree. This can happen for a number of reasons. For example, it may
-be an error; the user just typed the wrong URL. But it also can mean that the
-URL contains extra arguments.
-
-For example, assume that you have a blog-like application written in CherryPy
-that takes the year, month and day as part of the URL
-``http://localhost/blog/2005/01/17``. This URL can be handled by the
-following code::
-
-    class Root:
-        def blog(self, year, month, day):
-            ...
-        blog.exposed = True
-    
-    root = Root()
-
-So the URL above will be mapped as a call to::
-
-    root.blog('2005', '1', '17')
-
-In this case, there is a partial match up to the ``blog`` component. The rest
-of the URL can't be found in the mounted object tree. In this case, the
-``blog()`` method will be called, and the positional parameters will
-receive the remaining path segments as arguments. The values are passed as
-strings; in the above mentioned example, the arguments would still need to be
-converted back into numbers, but the idea is correctly presented.
-
-.. _defaultmethods:
-
-Default methods
-^^^^^^^^^^^^^^^
-
-.. index:: default, methods; default
-
-If the default dispatcher is not able to locate a suitable page handler by
-walking down the tree, it has a last-ditch option: it starts walking back
-''up'' the tree looking for `default` methods. Default methods work just like
-any other method with positional arguments, but are defined one level further
-down, in case you have multiple methods to expose. For example, we could have
-written the above "blog" example equivalently with a "default" method instead::
-
-    class Blog:
-        def default(self, year, month, day):
-            ...
-        default.exposed = True
-    
-    class Root: pass
-    
-    root = Root()
-    root.blog = Blog()
-
-So the URL ``http://localhost/blog/2005/01/17`` will be mapped as a call to::
-
-    root.blog.default('2005', '1', '17')
-
-You could achieve the same effect by defining a ``__call__`` method in this
-case, but "default" just reads better. ;)
-
-Special characters
-^^^^^^^^^^^^^^^^^^
-
-You can use dots in a URI like ``/path/to/my.html``, but Python method names
-don't allow dots. To work around this, the default dispatcher converts all dots
-in the URI to underscores before trying to find the page handler. In the
-example, therefore, you would name your page handler "def my_html". However,
-this means the page is also available at the URI ``/path/to/my_html``.
-If you need to protect the resource (e.g. with authentication), **you must
-protect both URLs**.
-
-.. versionadded:: 3.2
-   The default dispatcher now takes a 'translate' argument, which converts all
-   characters in string.punctuation to underscores using the builtin
-   :meth:`str.translate <str.translate>` method of string objects.
-   You are free to specify any other translation string of length 256.
-
-Other Dispatchers
------------------
-
-But Mr. Fielding mentions two kinds of "mapping implementations" above: trees
-and hash tables ('dicts' in Python). Some web developers claim trees are
-difficult to change as an application evolves, and prefer to use dicts
-(or a list of tuples) instead. Under these schemes, the mapping key is often
-a regular expression, and the value is the handler function. For example::
-
-    def root_index(name):
-        return "Hello, %s!" % name
-
-    def branch_leaf(size):