summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt9
-rw-r--r--docs/glossary.rst26
-rw-r--r--docs/index.rst1
-rw-r--r--docs/narr/MyProject/myproject/configure.zcml2
-rw-r--r--docs/narr/MyProject/myproject/run.py12
-rw-r--r--docs/narr/project.rst23
-rw-r--r--docs/narr/startup.rst169
-rw-r--r--docs/narr/traversal.rst138
-rw-r--r--docs/notes.txt7
9 files changed, 302 insertions, 85 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index e8a7b1e71..c4ae68324 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,7 +1,16 @@
Next Release
+ Features
+
+ - Add startup process docs.
+
Bug Fixes
+ - Move core repoze.bfg ZCML into a ``repoze.bfg.includes`` package so we can
+ use repoze.bfg better as a namespace package. Adjust the code generator to
+ use it. We've left around the older configure.zcml in the repoze.bfg
+ package directly so as not to break older apps.
+
- When a zcml application registry cache was unpickled, and it
contained a reference to an object that no longer existed (such as
a view), bfg would not start properly.
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 439b39424..1dd5fa821 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -31,6 +31,15 @@ Glossary
files that have the suffix of ``.egg``, ``.tar.gz``, or ``.zip``.
Distributions are the target of Setuptools commands such as
``easy_install``.
+ Entry Point
+ A :term:`setuptools` indirection, defined within a setuptools
+ :term:`distribution` setup.py. It is usually a name which refers
+ to a function somewhere in a package which is held by the
+ distribution.
+ Dotted Python name
+ A reference to a Python object by name using a string, in the form
+ ``path.to.modulename:attributename``. Often used in Paste and
+ setuptools configurations.
View
A "view" is a callable which returns a response object. It should
accept two values: context and request.
@@ -52,6 +61,11 @@ Glossary
model in order to find a :term:`context`. The :mod:`repoze.bfg`
*router* performs traversal of model objects. See the
:ref:`traversal_chapter` chapter for more information.
+ Router
+ The :term:`WSGI` application created when you start a
+ :mod:`repoze.bfg` application. The router intercepts requests,
+ invokes traversal, calls view functions, and returns responses to
+ the WSGI server.
URL dispatch
An alternative to graph traversal as a mechanism for locating a
:term:`context` for a :term:`view`. When you use :term:`Routes`
@@ -156,6 +170,12 @@ Glossary
encoding, and other functions. See `WSGI.org <http://wsgi.org>`_
or `PyPI <http://python.org/pypi>`_ to find middleware for your
application.
+ Pipeline
+ The :term:`Paste` term for a single configuration of a WSGI
+ server, a WSGI application, with a set of middleware in-between.
+ mod_wsgi
+ An `Apache module <http://code.google.com/p/modwsgi/>`_ for hosting
+ Python WSGI applications.
Zope
`The Z Object Publishing Framework <http://zope.org>`_. The granddaddy
of Python web frameworks.
@@ -220,4 +240,8 @@ Glossary
A `plain text format <http://docutils.sourceforge.net/rst.html>`_
that is the defacto standard for descriptive text shipped in
:term:`distribution` files, and Python docstrings.
-
+ Subpath
+ A list of element "left over" after the :term:`router` has
+ performed a successful traversal to a view. The subpath is a
+ sequence of strings, e.g. ``['left', 'over', 'names']``.
+
diff --git a/docs/index.rst b/docs/index.rst
index 3d18c115f..5362b9681 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -25,6 +25,7 @@ Narrative documentation in chapter form explaining how to use
narr/introduction
narr/install
narr/project
+ narr/startup
narr/urlmapping
narr/traversal
narr/urldispatch
diff --git a/docs/narr/MyProject/myproject/configure.zcml b/docs/narr/MyProject/myproject/configure.zcml
index 174b27354..c9bb92565 100644
--- a/docs/narr/MyProject/myproject/configure.zcml
+++ b/docs/narr/MyProject/myproject/configure.zcml
@@ -3,7 +3,7 @@
i18n_domain="repoze.bfg">
<!-- this must be included for the view declarations to work -->
- <include package="repoze.bfg" />
+ <include package="repoze.bfg.includes" />
<bfg:view
for=".models.IMyModel"
diff --git a/docs/narr/MyProject/myproject/run.py b/docs/narr/MyProject/myproject/run.py
index 07241ccc7..33d534f2d 100644
--- a/docs/narr/MyProject/myproject/run.py
+++ b/docs/narr/MyProject/myproject/run.py
@@ -2,12 +2,10 @@ from repoze.bfg.router import make_app
from repoze.bfg.registry import get_options
def app(global_config, **kw):
- # paster app config callback
+ """ This function returns a repoze.bfg.router.Router object. It
+ is usually called by the PasteDeploy framework during ``paster
+ serve``"""
from myproject.models import get_root
import myproject
- return make_app(get_root, myproject, options=get_options(kw))
-
-if __name__ == '__main__':
- from paste import httpserver
- httpserver.serve(app(None), host='0.0.0.0', port='6543')
-
+ options = get_options(kw)
+ return make_app(get_root, myproject, options=options)
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 8daac5e32..1dca10991 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -1,6 +1,6 @@
.. _project_narr:
-Starting a :mod:`repoze.bfg` Project
+Creating a :mod:`repoze.bfg` Project
====================================
You can use :mod:`repoze.bfg` 's sample application generator to get
@@ -224,6 +224,8 @@ wants to install your package does not have :term:`Setuptools` already
installed. It is only imported by and used by ``setup.py``, so we
won't describe it here.
+.. _MyProject_ini:
+
``MyProject.ini``
~~~~~~~~~~~~~~~~~
@@ -256,9 +258,11 @@ invoked against this configuration file. The name ``main`` is a
convention signifying that it the default application.
The ``use`` setting is required in the ``[app:main]`` section. The
-``use`` setting points at a :term:`setuptools` "entry point" named
-``MyProject#app`` (the ``egg:`` prefix in ``egg:MyProject#app``
-indicates that this is an entry point specifier).
+``use`` setting points at a :term:`setuptools` :term:`entry point`
+named ``MyProject#app`` (the ``egg:`` prefix in ``egg:MyProject#app``
+indicates that this is an entry point *URI* specifier, where the
+"scheme" is "egg"; there are no other schemes currently, so the
+``egg:`` prefix is arguably not very useful).
.. note::
@@ -442,7 +446,10 @@ registry`. It looks like so:
:mod:`repoze.bfg` -specific configuration directives.
#. Line 6 initializes :mod:`repoze.bfg`-specific configuration
- directives by including it as a package.
+ directives by including the ``repoze.bfg.includes`` package. This
+ causes all of the ZCML within the ``configure.zcml`` of the
+ ``repoze.bfg.includes`` package (which can be found in the main
+ :mod:`repoze.bfg` sources).
#. Lines 8-11 register a single view. It is ``for`` model objects
that support the IMyModel interface. The ``view`` attribute points
@@ -552,15 +559,11 @@ without the PasteDeploy configuration file:
#. Lines 1 - 2 import functions from :mod:`repoze.bfg` that we use later.
-#. Lines 4-9 define a function that returns a :mod:`repoze.bfg` Router
+#. Lines 4-12 define a function that returns a :mod:`repoze.bfg` Router
application from :ref:`router_module` . This is meant to be called
by the :term:`PasteDeploy` framework as a result of running
``paster serve``.
-#. Lines 11 - 13 allow this file to serve optionally as a shortcut for
- executing our program if the ``run.py`` file is executed directly.
- It starts our application under a web server on port 6543.
-
``templates/mytemplate.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst
new file mode 100644
index 000000000..a0ca8354f
--- /dev/null
+++ b/docs/narr/startup.rst
@@ -0,0 +1,169 @@
+.. _startup_chapter:
+
+Startup
+=======
+
+When you cause :mod:`repoze.bfg` to start up in the foreground, you'll
+see something much like this show up on your console::
+
+ $ paster serve myproject/MyProject.ini
+ Starting server in PID 16601.
+ serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
+
+This chapter explains what happens between the time you press the
+"Return" key on your keyboard after typing ``paster serve
+myproject/MyProject.ini`` and the resulting output of the line
+``serving on 0.0.0:6543 ...`` to your console.
+
+The Startup Process
+-------------------
+
+The easiest and best-documented way to start and serve a
+:mod:`repoze.bfg` application is to use the ``paster serve`` command
+against a :term:`PasteDeploy` ``.ini`` file. This uses the ``.ini``
+file to infer settings and starts a server listening on a port. For
+the purposes of this discussion, we'll assume that you are using this
+command to run your :mod:`repoze.bfg` application.
+
+.. note:: ``paster serve`` is by no means the only way to start up and
+ serve a :mod:`repoze.bfg` application. Any :term:`WSGI` server is
+ capable of running a :mod:`repoze.bfg` application, and some WSGI
+ servers (such as :term:`mod_wsgi`) don't require the
+ :term:`PasteDeploy` framework's ``paster serve`` command to do
+ server process management. Each :term:`WSGI` server has its own
+ documentation about how it creates a process to run an application,
+ and there are many of them, so we cannot provide the details for
+ each here. But the concepts are largely the same, whatever server
+ you happen to use.
+
+Here's a high-level time-ordered overview of what happens when you
+press ``return`` after running ``paster serve MyProject.ini``.
+
+#. The :term:`PasteDeploy` ``paster`` command is invoked under your
+ shell with the arguments ``serve`` and ``MyProject.ini``. As a
+ result, the :term:`PasteDeploy` framework recognizes that it is
+ meant to begin to run and serve an application using the
+ information contained within the ``MyProject.ini`` file.
+
+#. The PasteDeploy framework finds a section named either
+ ``[app:main]`` or ``[pipeline:main]`` in the ``.ini`` file. This
+ section represents the configuration of a :term:`WSGI` application
+ that will be served. If you're using a simple application (e.g. an
+ ``[app:main]`` section of a default-generated :mod:`repoze.bfg`
+ project), the application :term:`entry point` or :term:`dotted
+ Python name` will be named on the ``use=`` line within the
+ section's configuration. If, instead of a simple application,
+ you're using a WSGI :term:`pipeline` (e.g. a ``[pipeline:main]``
+ section), the application named on the "last" element will refer to
+ your :mod:`repoze.bfg` application.
+
+#. The application's *constructor* (named by the entry point reference
+ or dotted Python name on the ``use=`` line) is passed the key/value
+ parameters mentioned within the section in which it's defined. The
+ constructor is meant to return :term:`router` instance.
+
+ For ``repoze.bfg`` applications, the constructor will be a function
+ named ``app`` in the ``run.py`` file within the :term:`package` in
+ which your application lives. If this function succeeds, it will
+ return a :mod:`repoze.bfg` :term:`router` instance. Here's the
+ contents of an example ``run.py`` module:
+
+ .. literalinclude:: MyProject/myproject/run.py
+ :linenos:
+
+ Note that the constructor function accepts a ``global_config``
+ argument (which are the key/value pairs mentioned in the
+ ``[DEFAULT]`` section of the configuration file. It also accepts a
+ ``**kw`` argument, which collects arbitrary key/value pairs. The
+ arbitrary key/value pairs received by this function in ``**kw``
+ will be composed of all the key/value pairs that are present in the
+ ``[app:main]`` section (except for the ``use=`` setting) when this
+ function is called by the :term:`PasteDeploy` framework when you
+ run ``paster serve``.
+
+ Our generated ``MyProject.ini`` file looks like so:
+
+ .. literalinclude:: MyProject/MyProject.ini
+ :linenos:
+
+ In this case, the ``myproject.run:app`` function referred to by the
+ entry point URI ``egg:MyProject#app`` (see :ref:`MyProject_ini` for
+ more information about entry point URIs, and how they relate to
+ callables), will receive the key/value pairs
+ ``{'reload_templates':'true'}``.
+
+#. The constructor itself is invoked. A generated :mod:`repoze.bfg`
+ ``app`` function will look like the below.
+
+ .. literalinclude:: MyProject/myproject/run.py
+ :linenos:
+
+ Note that the app function imports the ``get_root`` function from
+ the ``myproject.models`` Python module. It then also imports the
+ "bare" ``myproject`` package, and passes ``get_root``,
+ ``myproject``, and the result of ``get_options(kw)`` as the
+ ``options`` keyword to the ``make_app`` function of the
+ ``repoze.bfg.router`` module.
+
+ ``get_options`` is a function imported from a :mod:`repoze.bfg`
+ package which allows the user to pass framework-related (as opposed
+ to application-related) options to an application constructor. It
+ picks off framework-related options from the ``*kw`` dict passed in
+ to the constructor. We actually use a framework option named
+ ``reload_templates`` in our configuration. Note that we make no
+ use of this option in our application, but the fact that we use
+ ``get_options`` to parse the ``*kw`` dict, and subsequently pass
+ along the result as the ``options`` argument to ``make_app``.
+
+ ``get_root`` is the first argument to ``make_app``, and it is a
+ callable that is invoked on every request to retrieve the
+ application root. It is not called during startup, only when a
+ request is handled.
+
+ We pass in the bare ``myproject`` package so that the ``make_app``
+ callback knows where to look for the :term:`application registry`
+ file (conventially named ``configure.zcml``). ``make_app`` will
+ use the package's path and look for ``configure.zcml`` within that
+ package's filesystem directory. If you for some reason need or
+ want to load a different application registry filename for your
+ application, you can pass an optional ``filename=`` paramter to
+ make_app (e.g. ``make_app(get_root, myproject,
+ filename='meta.zcml', options=options``). If the filename is
+ absolute, the package is ignored.
+
+#. The ``make_app`` function does its work. It parses the ZCML
+ represented by the application registry file (or may obtain the
+ application registry from a previously cached pickle file,
+ e.g. ``configure.zcml.cache``). If it fails to parse one or more
+ ZCML files, a ``XMLConfigurationError`` is raised. If it succeeds,
+ the :term:`application registry` is created, a :term:`router`
+ instance is created, and the router is associated with the
+ application registry. The router represents your application; the
+ settings in this application registry will be used for your
+ application.
+
+#. A ``WSGIApplicationCreatedEvent`` event is emitted (see
+ :ref:`events_chapter` for more informations about events).
+
+#. Assuming there were no errors, our ``myproject`` ``app`` function
+ returns the router instance created by ``make_app`` back to
+ PasteDeploy. As far as PasteDeploy is concerned, it is just
+ another WSGI application.
+
+#. PasteDeploy starts the WSGI *server* defined within the
+ ``[server:main]`` section. In our case, this is the "CherryPy"
+ server (``use = egg:PasteScript#cherrypy``), and it will listen on
+ all interfaces (``host = 0.0.0.0``), on port number 6543 (``port =
+ 6543``). It will serve up the application using 4 simultaneous
+ threads (``numthreads = 4``), which means it will handle four
+ simultaneous requests before needing to put a request in a wait
+ queue. The server code itself is what prints `serving on
+ 0.0.0.0:6543 view at http://127.0.0.1:6543``.
+
+#. The application is running.
+
+
+
+
+
+
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index f03a22c9e..d57cf8f02 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -62,72 +62,74 @@ When a user requests a page from your :mod:`repoze.bfg` -powered
application, the system uses this algorithm to determine which Python
code to execute:
- 1. The request for the page is presented to :mod:`repoze.bfg`'s
+#. The request for the page is presented to :mod:`repoze.bfg`'s
"router" in terms of a standard :term:`WSGI` request, which is
represented by a WSGI environment and a ``start_response``
callable.
- 2. The router creates a :term:`WebOb` request object based on the
- WSGI environment.
-
- 3. The router uses the WSGI environment's ``PATH_INFO`` variable to
- determine the path segments to traverse. The leading slash is
- stripped off ``PATH_INFO``, and the remaining path segments are
- split on the slash character to form a traversal sequence, so a
- request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
- traversal sequence ``['a', 'b', 'c']``.
-
- 4. :term:`Traversal` begins at the root object. For the traversal
- sequence ``['a', 'b', 'c']``, the root object's ``__getitem__``
- is called with the name ``a``. Traversal continues through the
- sequence. In our example, if the root object's ``__getitem__``
- called with the name ``a`` returns an object (aka "object A"),
- that object's ``__getitem__`` is called with the name ``b``. If
- object A returns an object when asked for ``b``, object B's
- ``__getitem__`` is then asked for the name ``c``, and may return
- object C.
-
- 5. Traversal ends when a) the entire path is exhausted or b) when
- any graph element raises a ``KeyError`` from its ``__getitem__``
- or c) when any non-final path element traversal does not have a
- ``__getitem__`` method (resulting in a ``NameError``) or d) when
- any path element is prefixed with the set of characters ``@@``
- (indicating that the characters following the ``@@`` token should
- be treated as a "view name").
-
- 6. When traversal ends for any of the reasons in the previous step,
- the the last object found during traversal is deemed to be the
- :term:`context`. If the path has been exhausted when traversal
- ends, the "view name" is deemed to be the empty string (``''``).
- However, if the path was *not* exhausted before traversal
- terminated, the first remaining path element is treated as the
- view name.
-
- Any subseqent path elements after the view name are deemed the
- *subpath*. For instance, if ``PATH_INFO`` was ``/a/b`` and the
- root returned an "A" object, and the "A" object returned a "B"
- object, the router deems that the context is "object B", the view
- name is the empty string, and the subpath is the empty sequence.
- On the other hand, if ``PATH_INFO`` was ``/a/b/c`` and "object A"
- was found but raised a ``KeyError`` for the name ``b``, the
- router deems that the context is object A, the view name is ``b``
- and the subpath is ``['c']``.
-
- 7. If a :term:`security policy` is configured, the router performs a
- permission lookup. If a permission declaration is found for the
- view name and context implied by the current request, the
- security policy is consulted to see if the "current user" (also
- determined by the security policy) can perform the action. If he
- can, processing continues. If he cannot, an ``HTTPUnauthorized``
- error is raised.
-
- 8. Armed with the context, the view name, and the subpath, the
- router performs a view lookup. It attemtps to look up a view
- from the :mod:`repoze.bfg` :term:`application registry` using the
- view name and the context. If a view function is found, it is
- called with the context and the request. It returns a response,
- which is fed back upstream. If a view is not found, a generic
- WSGI ``NotFound`` application is constructed.
+#. The router creates a :term:`WebOb` request object based on the
+ WSGI environment.
+
+#. The router uses the WSGI environment's ``PATH_INFO`` variable to
+ determine the path segments to traverse. The leading slash is
+ stripped off ``PATH_INFO``, and the remaining path segments are
+ split on the slash character to form a traversal sequence, so a
+ request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
+ traversal sequence ``['a', 'b', 'c']``.
+
+#. :term:`Traversal` begins at the root object. For the traversal
+ sequence ``['a', 'b', 'c']``, the root object's ``__getitem__`` is
+ called with the name ``a``. Traversal continues through the
+ sequence. In our example, if the root object's ``__getitem__``
+ called with the name ``a`` returns an object (aka "object ``a``"),
+ that object's ``__getitem__`` is called with the name ``b``. If
+ object A returns an object when asked for ``b``, "object ``b``"'s
+ ``__getitem__`` is then asked for the name ``c``, and may return
+ "object ``c``".
+
+#. Traversal ends when a) the entire path is exhausted or b) when any
+ graph element raises a ``KeyError`` from its ``__getitem__`` or c)
+ when any non-final path element traversal does not have a
+ ``__getitem__`` method (resulting in a ``NameError``) or d) when
+ any path element is prefixed with the set of characters ``@@``
+ (indicating that the characters following the ``@@`` token should
+ be treated as a "view name").
+
+#. When traversal ends for any of the reasons in the previous step,
+ the the last object found during traversal is deemed to be the
+ :term:`context`. If the path has been exhausted when traversal
+ ends, the "view name" is deemed to be the empty string (``''``).
+ However, if the path was *not* exhausted before traversal
+ terminated, the first remaining path element is treated as the
+ view name.
+
+ Any subseqent path elements after the view name are deemed the
+ :term:`subpath`. The subpath is always a sequence of strings that
+ come from ``PATH_INFO`` that are "left over" after traversal has
+ completed. For instance, if ``PATH_INFO`` was ``/a/b`` and the
+ root returned an "object ``a``", and "object ``a``" subsequently
+ returned an "object ``b``", the router deems that the context is
+ "object ``b``", the view name is the empty string, and the subpath
+ is the empty sequence. On the other hand, if ``PATH_INFO`` was
+ ``/a/b/c`` and "object ``a``" was found but raised a ``KeyError``
+ for the name ``b``, the router deems that the context is "object
+ ``a``", the view name is ``b`` and the subpath is ``['c']``.
+
+#. If a :term:`security policy` is configured, the router performs a
+ permission lookup. If a permission declaration is found for the
+ view name and context implied by the current request, the security
+ policy is consulted to see if the "current user" (also determined
+ by the security policy) can perform the action. If he can,
+ processing continues. If he cannot, an ``HTTPUnauthorized`` error
+ is raised.
+
+#. Armed with the context, the view name, and the subpath, the router
+ performs a view lookup. It attemtps to look up a view from the
+ :mod:`repoze.bfg` :term:`application registry` using the view name
+ and the context. If a view function is found, it is called with
+ the context and the request. It returns a response, which is fed
+ back upstream. If a view is not found, a generic WSGI
+ ``NotFound`` application is constructed.
In either case, the result is returned upstream via the :term:`WSGI`
protocol.
@@ -244,3 +246,15 @@ There are two special cases:
to address views that may have the same names as model instance
names in the graph unambiguously.
+Traversal-Related Side Effects
+------------------------------
+
+The :term:`subpath` will always be available to a view as a the
+``subpath`` attribute of the :term:`request` object. It will be a
+list containing zero or more elements (which will be strings).
+
+The :term:`view name` will always be available to a view as the
+``view_name`` attribute of the :term:`request` object. It will be a
+single string (possibly the empty string if we're rendering a default
+view).
+
diff --git a/docs/notes.txt b/docs/notes.txt
index 4e641234c..d92c95564 100644
--- a/docs/notes.txt
+++ b/docs/notes.txt
@@ -1,9 +1,5 @@
- Document z3c.pt
-- Spaces in project names (allow for separate project / package names?)
-
-- Subpath and view name in request
-
- WebOb Request basics
- "push" style templating
@@ -15,3 +11,6 @@
- Show usage of, e.g. HTTPFound(location=url).
- Document ``make_app`` better; particularly how zcml is found.
+
+- What is ``global_conf`` passed to the app constructor? How is it
+ composed?