diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-07-03 01:41:04 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-07-03 01:41:04 +0000 |
| commit | 7bc20e11b5ed7314e5aaed000242d4d5950fc775 (patch) | |
| tree | 6cb253ea95617ca4f24aa365f145ec2f81bf53fc /docs | |
| parent | c43c358c7ec7d352fd4792b993e4609cbab37dba (diff) | |
| download | pyramid-7bc20e11b5ed7314e5aaed000242d4d5950fc775.tar.gz pyramid-7bc20e11b5ed7314e5aaed000242d4d5950fc775.tar.bz2 pyramid-7bc20e11b5ed7314e5aaed000242d4d5950fc775.zip | |
General editing walkthrough.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/narr/events.rst | 7 | ||||
| -rw-r--r-- | docs/narr/extending.rst | 8 | ||||
| -rw-r--r-- | docs/narr/hooks.rst | 4 | ||||
| -rw-r--r-- | docs/narr/hybrid.rst | 15 | ||||
| -rw-r--r-- | docs/narr/install.rst | 54 | ||||
| -rw-r--r-- | docs/narr/introduction.rst | 35 | ||||
| -rw-r--r-- | docs/narr/models.rst | 5 | ||||
| -rw-r--r-- | docs/narr/project.rst | 72 | ||||
| -rw-r--r-- | docs/narr/security.rst | 52 | ||||
| -rw-r--r-- | docs/narr/startup.rst | 47 | ||||
| -rw-r--r-- | docs/narr/templates.rst | 51 | ||||
| -rw-r--r-- | docs/narr/traversal.rst | 111 | ||||
| -rw-r--r-- | docs/narr/urldispatch.rst | 25 | ||||
| -rw-r--r-- | docs/narr/urlmapping.rst | 26 | ||||
| -rw-r--r-- | docs/narr/views.rst | 37 |
15 files changed, 307 insertions, 242 deletions
diff --git a/docs/narr/events.rst b/docs/narr/events.rst index e54c97a88..ca3ecf3d6 100644 --- a/docs/narr/events.rst +++ b/docs/narr/events.rst @@ -4,7 +4,7 @@ Using Events ============= An *event* is an object broadcast by the :mod:`repoze.bfg` framework -at particularly interesting points during the lifetime of your +at particularly interesting points during the lifetime of an application. You don't need to use, know about, or care about events in order to create most :mod:`repoze.bfg` applications, but they can be useful when you want to do slightly advanced operations, such as @@ -12,7 +12,7 @@ be useful when you want to do slightly advanced operations, such as hostname used to reach the site. Events in :mod:`repoze.bfg` are always broadcast by the framework. -They only become useful when you register a *subscriber*. A +However, they only become useful when you register a *subscriber*. A subscriber is a function that accepts a single argument named `event`: .. code-block:: python @@ -86,7 +86,8 @@ must. Likewise, we know that ``INewResponse`` events have a ``response`` attribute, which is a response object constructed by your application, because the interface defined at ``repoze.bfg.interfaces.INewResponse`` says it must. These particular -interfaces are documented in the :ref:`events_module` API chapter. +interfaces, along with others, are documented in the +:ref:`events_module` API chapter. .. note:: diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst index cbfaeda6a..128e75b26 100644 --- a/docs/narr/extending.rst +++ b/docs/narr/extending.rst @@ -39,10 +39,10 @@ declarations out of the decorators and into :term:`ZCML`. Once this is done, you should be able to extend or modify the application like any other. -To extend or change the behavior of an existing application, the only -hard-and-fast rule is that you need to write some :term:`ZCML`, and -perhaps some implementations of the types of things you'd like to -override (such as views), which is referred to within that ZCML. +To extend or change the behavior of an existing application, you will +need to write some :term:`ZCML`, and perhaps some implementations of +the types of things you'd like to override (such as views), which are +referred to within that ZCML. The general pattern for extending an application looks something like this: diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 086dc16ad..c2f6966de 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -6,6 +6,8 @@ Using ZCML Hooks ZCML "hooks" can be used to influence the behavior of the :mod:`repoze.bfg` framework in various ways. +.. _changing_the_notfound_view: + Changing the Not Found View --------------------------- @@ -38,6 +40,8 @@ implements a minimal NotFound view: This error will be different when the ``debug_notfound`` environment setting is true than it is when it is false. +.. _changing_the_forbidden_view: + Changing the Forbidden View --------------------------- diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst index 70a233005..129d76732 100644 --- a/docs/narr/hybrid.rst +++ b/docs/narr/hybrid.rst @@ -13,14 +13,15 @@ However, for some problems, it's useful to use both traversal *and* URL dispatch within the same application. :mod:`repoze.bfg` makes this possible. -Reasoning about a "hybrid" URL dispatch + traversal model is difficult -because the combination of the two concepts seems to break the law of -`the magical number seven plus or minus 2 +Reasoning about a "hybrid" URL dispatch + traversal model can be +difficult because the combination of the two concepts seems to fall +outside the sweet spot of `the magical number seven plus or minus 2 <http://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two>`_. -This is because, as a user, you need to understand 1) URL pattern -matching, 2) root factories and 3) the traversal algorithm, and the -interactions between all of them. Therefore, use of this pattern is -not recommended unless you *really* need to use it. +To reason successfully about using URL dispatch and traversal +together, you need to understand 1) URL pattern matching, 2) root +factories and 3) the traversal algorithm, and the interactions between +all of them. Therefore, use of this pattern is not recommended unless +you *really* need to use it. This is a advanced topic that has non-trivial corner cases; you may need to understand more deeply how :mod:`repoze.bfg` works to diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 4ba4eee06..26d409e7f 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -20,19 +20,20 @@ run under Python 3.X. .. note:: Installation of :mod:`repoze.bfg` does not require the compilation of any C code, so as long as you have a Python interpreter that meets the above requirements, you do not need to - have development tools installed on the target machine to run + have development tools installed on the target machine to install :mod:`repoze.bfg`. -BFG is known to run properly on all popular (and even some -less-popular) Unix-like systems such as Linux, MacOS X, and FreeBSD. +BFG is known to run properly on all popular Unix-like systems such as +Linux, MacOS X, and FreeBSD. -:mod:`repoze.bfg` runs on Windows systems. However, none of its main -developers use the Windows platform. Therefor, most of the -platform-specific documentation (excepting this chapter) assumes -you're using a UNIX system. If you're using a Windows system, you'll -need to transliterate command lines in the documentation to their -Windows equivalents. :mod:`repoze.bfg` is also known to run on -Google's App Engine. +:mod:`repoze.bfg` does run on Windows systems. However, none of its +developers use Windows as a primary development platform. Therefore, +most of the platform-specific documentation (excepting this chapter) +assumes you're using a UNIX system. If you're using a Windows system, +you'll need to transliterate command lines in the documentation to +their Windows equivalents. + +:mod:`repoze.bfg` is also known to run on Google's App Engine. It is not known whether :mod:`repoze.bfg` will or will not run under Jython or IronPython. @@ -72,10 +73,12 @@ invokable via ``python2.5`` from a shell prompt. Source Compile Method +++++++++++++++++++++ -It's useful to use a Python that *isn't* the "system" Python to -develop your software (the authors of BFG never use the system Python -to run BFG; always a self-compiled one). Often the "system" Python is -compiled with options that aren't optimal for web development. +It's useful to use a Python interpreter that *isn't* the "system" +Python interpreter to develop your software. The authors of +:mod:`repoze.bfg` never use the system Python for development +purposes; always a self-compiled one. Compiling Python is easy, and +often the "system" Python is compiled with options that aren't optimal +for web development. To compile software on your UNIX system, typically you need development tools. Often these can be installed via the package @@ -117,6 +120,8 @@ interpreter executable from `<python.org http://python.org/download/>`_ (the files labeled "Windows Installer"). Once you've downloaded it, double click on the executable and accept the defaults during the installation process. +You may also need to download and install the `Python for Windows +extensions <http://sourceforge.net/projects/pywin32/files/>`_. Installing :mod:`repoze.bfg` on a UNIX System --------------------------------------------- @@ -128,9 +133,9 @@ installed in your Python version (and likewise, to prevent are not compatible with your system Python). To set up a virtualenv to install :mod:`repoze.bfg` within, first -ensure that setuptools is installed. Invoke ``import setuptools`` -within the Python interpreter you'd like to run :mod:`repoze.bfg` -with. +ensure that :term:`setuptools` is installed. Invoke ``import +setuptools`` within the Python interpreter you'd like to run +:mod:`repoze.bfg` under: .. code-block:: bash @@ -143,9 +148,11 @@ with. If ``import setuptools`` does not raise an ``ImportError``, it means that setuptools is already installed into your Python interpreter. If ``import setuptools`` fails, you will need to install setuptools -manually. If you are using a "system" Python (one installed by your -OS distributor or a 3rd-party packager such as Fink or MacPorts), you -can usually install a setuptools package using your system's package +manually. + +If you are using a "system" Python (one installed by your OS +distributor or a 3rd-party packager such as Fink or MacPorts), you can +usually install a setuptools package using your system's package manager. If you cannot do this, or if you're using a self-installed version of Python, you will need to install setuptools "by hand". Installing setuptools "by hand" is always a reasonable thing to do, @@ -169,7 +176,6 @@ the script. To remediate this, you may need to do: $ sudo python ez_setup.py - Installing the ``virtualenv`` Package ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -247,9 +253,9 @@ Installing :mod:`repoze.bfg` on a Windows System <http://python.org/download/releases/2.5.4/>`_ for your system. #. Install the `Python for Windows extensions - <http://www.sourceforge.net/project/showfiles.php?group_id=78018>`_. - Make sure to pick the right download for Python 2.5 and install it - using the same Python installation from the previous step. + <http://sourceforge.net/projects/pywin32/files/>`_. Make sure to + pick the right download for Python 2.5 and install it using the + same Python installation from the previous step. #. Install latest `setuptools` into the Python you obtained/installed/found in the step above: download `ez_setup.py diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index e96d74543..c863b499e 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -9,18 +9,18 @@ and responses. Similarities to Other Frameworks -------------------------------- -:mod:`repoze.bfg` was inspired by :term:`Zope`, :term:`Django`, and -:term:`Pylons`. +:mod:`repoze.bfg` was inspired by :term:`Zope`, :term:`Pylons` and +:term:`Django`. The :mod:`repoze.bfg` concept of traversal is inspired by :term:`Zope`. Additionally, :mod:`repoze.bfg` uses the Zope Component Architecture ("CA") internally, as do Zope 2, Zope 3, and -:term:`Grok`. Application :mod:`repoze.bfg` developers use either +:term:`Grok`. :mod:`repoze.bfg` application developers may use either :term:`ZCML` (an XML dialect, used in Zope) or decorators to perform -various configuration tasks. The decorator support is provided by the -:term:`Grok` project. Like Zope, :mod:`repoze.bfg` allows you to -create applications which do not need to be forked to be extended by a -third party developer. +various application configuration tasks. The decorator support is +provided by the :term:`Grok` project. Like Zope, :mod:`repoze.bfg` +allows you to create applications which do not need to be forked or +otherwise modified to be extended by a third party developer. Like :term:`Pylons`, :mod:`repoze.bfg` is mostly policy-free. It makes no assertions about which database you should use, and its @@ -76,8 +76,8 @@ To learn more about the concepts used by :mod:`repoze.bfg`, visit the Differences from Other Frameworks --------------------------------- -Like :term:`Zope`, the :mod:`repoze.bfg` framework imposes slightly -more `control inversion <http://plope.com/control_inversion>`_ upon +Like :term:`Zope`, the :mod:`repoze.bfg` framework imposes more +`control inversion <http://plope.com/control_inversion>`_ upon application developers than other Python frameworks such as :term:`Pylons`. For example :mod:`repoze.bfg` allows you to explicitly resolve a URL to a :term:`context` object before invoking a @@ -107,7 +107,7 @@ CA behind special-purpose API functions. Also unlike :term:`Zope` and unlike other "full-featured" frameworks such as :term:`Django`, :mod:`repoze.bfg` makes no assumptions about -what persistence mechanisms you want to use to build an application. +which persistence mechanisms you should use to build an application. Zope applications are typically reliant on :term:`ZODB`; :mod:`repoze.bfg` allows you to build :term:`ZODB` applications, but it has no reliance on the ZODB package. Likewise, :term:`Django` @@ -121,8 +121,8 @@ Why? ---- *Familiarity*: As web developers, we've become accustomed to working -in very particular ways (primarily using Zope 2) over the years. This -framework is a canonization of practices that "fit our brains". +in very particular ways over the years. This framework is a +canonization of practices that "fit our brains". *Simplicity*: :mod:`repoze.bfg` attempts to be a *"pay only for what you eat"* framework in which you can be productive quickly with @@ -130,14 +130,13 @@ partial knowledge. We contrast this with *"pay up front for what anyone might eventually want to eat"* frameworks, which tend to expect you to understand a great many concepts and technologies fully before you can be truly productive. :mod:`repoze.bfg` doesn't force you to -use any particular technology to get your application written, and we -try to keep the core set of concepts you need to understand to a -minimum. +use any particular technology to produce an application, and we try to +keep the core set of concepts you need to understand to a minimum. *Minimalism*: :mod:`repoze.bfg` provides only the very basics: *URL to -code mapping*, *templating*, and *security*. There is not much more -to the framework than these pieces: you are expected to provide the -rest. +code mapping*, *templating*, *security*, and *resources*. There is +not much more to the framework than these pieces: you are expected to +provide the rest. *Documentation*: Because :mod:`repoze.bfg` is minimal, it's relatively easy to keep its documentation up-to-date, which is helpful to bring diff --git a/docs/narr/models.rst b/docs/narr/models.rst index b865bcb53..a3613c77c 100644 --- a/docs/narr/models.rst +++ b/docs/narr/models.rst @@ -99,8 +99,9 @@ interface (as opposed to its class). To do so, use the entry = BlogEntry() directlyProvides(IBlogEntry, entry) -If a model object already has instance interface declarations that you -don't want to disturb, use the ``zope.interface.alsoProvides`` API: +If a model object already has instance-level interface declarations +that you don't want to disturb, use the +``zope.interface.alsoProvides`` API: .. code-block:: python :linenos: diff --git a/docs/narr/project.rst b/docs/narr/project.rst index a8b0ccdd4..4b0de4a0e 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -3,9 +3,9 @@ Creating a :mod:`repoze.bfg` Project ==================================== -You can use :mod:`repoze.bfg` 's sample application generator to get -started. This generator uses :term:`Paste` templates to allow -creation of a new project by answering a series of questions. +You can use the :mod:`repoze.bfg` sample application generator to get +started. This generator uses :term:`Paste` templates to aid in +the creation of a new project. .. _creating_a_project: @@ -69,15 +69,15 @@ project we name ``MyProject``: Copying setup.py_tmpl to ./MyProject/setup.py Running /Users/chrism/projects/repoze/bfg/bin/python setup.py egg_info -As a result of the above, a project is created in a directory named -``MyProject``. That directory is a :term:`setuptools` :term:`project` -directory from which a Python setuptools :term:`distribution` can be -created. The ``setup.py`` file in that directory can be used to -distribute your application, or install your application for -deployment or development. A sample :term:`PasteDeploy` ``.ini`` file -named ``MyProject.ini`` will also be created in the project directory. -You will use the ``paster serve`` command against this ``.ini`` file -to run your application. +As a result of invoking ``paster create``, a project is created in a +directory named ``MyProject``. That directory is a :term:`setuptools` +:term:`project` directory from which a Python setuptools +:term:`distribution` can be created. The ``setup.py`` file in that +directory can be used to distribute your application, or install your +application for deployment or development. A sample +:term:`PasteDeploy` ``.ini`` file named ``MyProject.ini`` will also be +created in the project directory. You will use the ``paster serve`` +command against this ``.ini`` file to run your application. The ``MyProject`` project directory contains an additional subdirectory named ``myproject`` (note the case difference) @@ -164,14 +164,27 @@ The Interactive Shell --------------------- Once you've installed your program for development using ``setup.py -develop``, you can use an interactive shell to examine your BFG -application from a Python prompt. To do so, use the ``paster`` -shell command with the ``bfgshell`` argument: +develop``, you can use an interactive shell to examine your +:mod:`repoze.bfg` application :term:`model` objects from a Python +prompt. To do so, use the ``paster`` shell command with the +``bfgshell`` argument: The first argument to ``bfgshell`` is the path to your application's ``.ini`` file. The second is the section name inside the ``.ini`` -file which points to your application. +file which points to your *application* as opposed to any other +section within the ``.ini`` file. For example, if your application +``.ini`` file might have a ``[app:main]`` section that looks like so: +.. code-block: + + [app:main] + use = egg:MyProject#app + reload_templates = true + debug_authorization = false + debug_notfound = false + +If so, you can use the following command to invoke a debug shell using +the name ``main`` as a section name: .. code-block:: bash :linenos: @@ -194,7 +207,7 @@ before the filename: [chrism@vitaminf bfgshellenv]$ ../bin/paster --plugin=repoze.bfg bfgshell MyProject.ini main -Press Ctrl-D to exit the interactive shell. +Press "Ctrl-D" to exit the interactive shell. You should always use a section name argument that refers to the actual ``app`` section within the config file that points at your BFG @@ -302,7 +315,7 @@ We won't describe the ``CHANGES.txt`` or ``README.txt`` files. ``ez_setup.py`` is a file only used by ``setup.py`` in case a user who 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. +won't describe it here either. .. _MyProject_ini: @@ -388,8 +401,9 @@ not require an application restart to be detected. See turned on. Various other settings may exist in this section having to do with -debugging a :mod:`repoze.bfg` application. See -:ref:`environment_chapter` for more information about these settings. +debugging or influencing runtime behavior of a :mod:`repoze.bfg` +application. See :ref:`environment_chapter` for more information +about these settings. The ``[server:main]`` section of the configuration file configures a WSGI server which listens on port 6543. It is configured to listen on @@ -398,10 +412,10 @@ new thread for each request. .. note:: - In general, ``repoze.bfg`` applications should be threading-aware. - It is not required that a ``repoze.bfg`` application be nonblocking - as all application code will run in its own thread, provided by the - server you're using. + In general, :mod:`repoze.bfg` applications should be + threading-aware. It is not required that a :mod:`repoze.bfg` + application be nonblocking as all application code will run in its + own thread, provided by the server you're using. See the :term:`PasteDeploy` documentation for more information about other types of things you can put into this ``.ini`` file, such as @@ -450,8 +464,8 @@ fields which probably don't need any description. ``url`` is a field that should point at your application project's URL (if any). ``packages=find_packages()`` causes all packages within the project to be found when packaging the application. ``include_package_data`` -will include non-Python files when the application is packaged (if -those files are checked into version control). ``zip_safe`` indicates +will include non-Python files when the application is packaged if +those files are checked into version control. ``zip_safe`` indicates that this package is not safe to ship as a zipped egg (it will unpack as a directory, which is more convenient). ``install_requires`` and ``tests_require`` indicate that this package depends on the @@ -688,8 +702,8 @@ The ``tests.py`` module includes unit tests for your application. This sample ``tests.py`` file has a single unit test and a single integration test defined within it. These two tests are executed when -you run ``setup.py test -q``. You may add more tests here as you -build your application. You are not required to write tests to use -:mod:`repoze.bfg`, this file is simply provided as convenience and +you run ``python setup.py test -q``. You may add more tests here as +you build your application. You are not required to write tests to +use :mod:`repoze.bfg`, this file is simply provided as convenience and example. diff --git a/docs/narr/security.rst b/docs/narr/security.rst index e86451570..cd2dc9a50 100644 --- a/docs/narr/security.rst +++ b/docs/narr/security.rst @@ -6,10 +6,11 @@ Security :mod:`repoze.bfg` provides an optional declarative authorization system that prevents a :term:`view` from being invoked when the user represented by credentials in the :term:`request` does not have an -appropriate level of access in a specific context. +appropriate level of access with respect to a specific +:term:`context`. Authorization is enabled by modifying your :term:`application -registry` (aka "configure.zcml"). +registry` (aka ``configure.zcml``). Enabling an Authorization Policy -------------------------------- @@ -65,11 +66,10 @@ and :ref:`creating_an_authorization_policy`. Protecting Views with Permissions --------------------------------- -You declaratively protected a particular view with a -:term:`permission` via the ``configure.zcml`` application registry. -For example, the following declaration protects the view named -``add_entry.html`` when invoked against a ``Blog`` context with the -``add`` permission: +You declaratively protect a particular view using a :term:`permission` +name via the ``configure.zcml`` application registry. For example, +the following declaration protects the view named ``add_entry.html`` +when invoked against a ``Blog`` context with the ``add`` permission: .. code-block:: xml :linenos: @@ -81,9 +81,9 @@ For example, the following declaration protects the view named permission="add" /> -The equivalent view registration including the 'add' permission may be -performed via the ``bfg_view`` decorator within the "views" module of -your project's package +The equivalent view registration including the 'add' permission name +may be performed via the ``bfg_view`` decorator within the "views" +module of your project's package .. code-block:: python :linenos: @@ -101,21 +101,22 @@ normal application operations, the user will need to possess the ``add`` permission against the context to be able to invoke the ``blog_entry_add_view`` view. -Permission names are just strings. They hold no special significance -to the system. You can name permissions whatever you like. +Permission names are usually just strings. They hold no special +significance to the system. You can name permissions whatever you +like. .. _assigning_acls: Assigning ACLs to your Model Objects ------------------------------------ -When :mod:`repoze.bfg` determines whether a user possesses a particular -permission in a :term:`context`, it examines the :term:`ACL` -associated with the context. An ACL is associated with a context by -virtue of the ``__acl__`` attribute of the model object representing -the context. This attribute can be defined on the model *instance* -(if you need instance-level security), or it can be defined on the -model *class* (if you just need type-level security). +When :mod:`repoze.bfg` determines whether a user possesses a +particular permission in a :term:`context`, it examines the +:term:`ACL` associated with the context. An ACL is associated with a +context by virtue of the ``__acl__`` attribute of the model object +representing the context. This attribute can be defined on the model +*instance* (if you need instance-level security), or it can be defined +on the model *class* (if you just need type-level security). For example, an ACL might be attached to model for a blog via its class: @@ -184,7 +185,7 @@ and edit the blog. The third argument in an ACE can also be a sequence of permission names instead of a single permission name. So instead of creating multiple ACEs representing a number of different permission grants to -a single ``group.editors`` group, we can collapse this into a single +a single ``group:editors`` group, we can collapse this into a single ACE, as below. .. code-block:: python @@ -340,6 +341,16 @@ root object's ``__parent__`` is ``None``. See :ref:`location_module` for documentations of functions which use location-awareness. See also :ref:`location_aware`. +Changing the Forbidden View +--------------------------- + +When :mod:`repoze.bfg` denies a view invocation due to an +authorization denial, the special ``forbidden`` view is invoked. "Out +of the box", this forbidden view is very plain. See +:ref:`changing_the_forbidden_view` within :ref:`hooks_chapter` for +instructions on how to create a custom forbidden view and arrange for +it to be called when view authorization is denied. + .. _debug_authorization_section: Debugging View Authorization Failures @@ -612,3 +623,4 @@ examples of how to create a directive. Authorization policy ZCML directives should use the ZCML discriminator value "authorization_policy" in their actions to allow for conflict detection. + diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index 1d8206f14..f657b44c7 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -3,8 +3,8 @@ 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:: +When you cause :mod:`repoze.bfg` to start up in a console window, +you'll see something much like this show up on the console:: $ paster serve myproject/MyProject.ini Starting server in PID 16601. @@ -12,8 +12,8 @@ see something much like this show up on your console:: 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. +myproject/MyProject.ini`` and the the time the line ``serving on +0.0.0:6543 ...`` is output to your console. The Startup Process ------------------- @@ -99,15 +99,15 @@ press ``return`` after running ``paster serve MyProject.ini``. .. literalinclude:: MyProject/myproject/run.py :linenos: - Note that the app function imports the ``get_root`` root factory - function from the ``myproject.models`` Python module. It then also - imports the "bare" ``myproject`` package, and passes ``get_root``, - ``myproject``, and the ``options`` keyword as the ``app`` - function's extra keyword args to the ``make_app`` function of the - ``repoze.bfg.router`` module. ``**kw`` here contains all the - options in the ``[app:main]`` section of our .ini file except the - "use" option (which is internal to paste). In this case, ``**kw`` - will be something like ``{'reload_templates':'true', + Note that the ``app`` function imports the ``get_root`` :term:`root + factory` function from the ``myproject.models`` Python module. It + then also imports the "bare" ``myproject`` package, and passes + ``get_root``, ``myproject``, and the ``options`` keyword as the + ``app`` function's extra keyword args to the ``make_app`` function + of the ``repoze.bfg.router`` module. ``**kw`` here contains all + the options in the ``[app:main]`` section of our .ini file except + the "use" option (which is internal to paste). In this case, + ``**kw`` will be something like ``{'reload_templates':'true', 'debug_authorization':'false', 'debug_notfound':'false'}``. ``get_root`` is the first argument to ``make_app``, and it is a @@ -119,12 +119,13 @@ press ``return`` after running ``paster serve MyProject.ini``. 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`` argument is ignored. + 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`` argument is ignored. #. The ``make_app`` function does its work. It finds and parses the ZCML represented by the application registry file. If it fails to @@ -140,10 +141,10 @@ press ``return`` after running ``paster serve MyProject.ini``. #. 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". +#. Assuming there were no errors, the ``app`` function in + ``myproject`` 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 ``Paste#http`` diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst index c3a49da68..316bd3016 100644 --- a/docs/narr/templates.rst +++ b/docs/narr/templates.rst @@ -1,11 +1,11 @@ Templates ========= -A :term:`template` is a usually file on disk which can be used to -render data provided by a :term:`view`, surrounded by more static -information. :mod:`repoze.bfg` offers a number of ways to perform -templating tasks "out of the box", and provides alternative templating -language support via add-on "bindings" packages. +A :term:`template` is a file on disk which can be used to render +dynamic data provided by a :term:`view`, usually surrounded by +information that is static. :mod:`repoze.bfg` offers a number of ways +to perform templating tasks "out of the box", and provides alternative +templating language support via add-on "bindings" packages. Templating With :term:`Chameleon` ZPT Page Templates ---------------------------------------------------- @@ -16,8 +16,8 @@ language. However, :mod:`repoze.bfg` uses a different implementation of the :term:`ZPT` specification than Zope does: the :term:`Chameleon` :term:`chameleon.zpt` templating engine. This templating engine complies largely with the `Zope Page Template -<http://wiki.zope.org/ZPT/FrontPage>`_ template specification and is -significantly faster. +<http://wiki.zope.org/ZPT/FrontPage>`_ template specification, however +it is significantly faster. .. note:: The language definition documentation for Chameleon ZPT-style templates is available from `the Chameleon website @@ -25,17 +25,6 @@ significantly faster. <http://chameleon.repoze.org/docs/zpt/>`_ for the Chameleon ZPT language specification. -.. note:: As of version 0.8.0, :mod:`repoze.bfg` no longer supports - XSL templates "out of the box". The :mod:`repoze.bfg.xslt` package - is an add-on which provides XSL template bindings. See - :ref:`available_template_system_bindings`. - -.. note:: As of version 0.8.0, :mod:`repoze.bfg` no longer supports - Genshi-style Chameleon bindings "out of the box". The - :mod:`repoze.bfg.chameleon_genshi` package is an add-on which - provides Chameleon Genshi-style template support. See - :ref:`available_template_system_bindings`. - Given that there is a :term:`chameleon.zpt` template named ``foo.pt`` in a directory in your application named ``templates``, you can render the template from a view like so: @@ -55,11 +44,12 @@ Relative to the directory in which the ``views.py`` file which names it lives, which is usually the :mod:`repoze.bfg` application's :term:`package` directory. -A path passed to ``render_template_to_response`` can also be absolute -(starting with a slash on UNIX or a drive letter prefix on Windows). -It can also be a "specification" in the form -``another.dotted.package_name:relative/path`` if the resources lives in -another package. +Although a path is usually just a simple relative pathname, a path +passed to ``render_template_to_response`` can be absolute, starting +with a slash on UNIX or a drive letter prefix on Windows. The path +can alternately be a :term:`resource` "specification" in the form +``some.dotted.package_name:relative/path``, making it possible to +address template resources which live in another package. ``render_template_to_response`` always returns a Response object which has a *status code* of ``200 OK`` and a *content-type* of @@ -248,8 +238,8 @@ environment so that a change to a template will be automatically detected, and the template will be reloaded on the next rendering. .. warning:: auto-template-reload behavior is not recommended for - production sites as it slows rendering; it's usually only - desirable during development. + production sites as it slows rendering slightly; it's + usually only desirable during development. In order to turn on automatic reloading of templates, you can use an environment variable setting or a configuration file setting. @@ -268,6 +258,13 @@ application's configuration section, e.g.:: use = egg:MyProject#app reload_templates = true +:term:`Chameleon` Template Internationalization +----------------------------------------------- + +See `the internationalization chapter +<http://chameleon.repoze.org/docs/zpt/narr/i18n.html>`_ of the +Chameleon documentation for information about supporting +internationalized units of text within Chameleon templates. Templating with other Templating Languages ------------------------------------------ @@ -301,7 +298,9 @@ installed, here's an example of using Mako from within a Note that if you use third-party templating languages without cooperating BFG bindings, the auto-template-reload strategy explained -in :ref:`reload_templates_section` will not be available. +in :ref:`reload_templates_section` will not be available, nor will the +template resource overriding capability explained in +:ref:`overriding_resources_section` be available. .. _available_template_system_bindings: diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index cfc484cf0..8e21150c1 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -3,12 +3,13 @@ Traversal ========= -When :term:`traversal` is used, the :mod:`repoze.bfg` *Router* parses -the URL associated with the request and splits the URL into path -segments. Based on these path segments, :mod:`repoze.bfg` traverses a -*model graph* in order to find a :term:`context`. It then attempts to -find a :term:`view` based on the *type* of the context (specified by -its Python class type or any :term:`interface` attached to it). If +When :term:`traversal` is used within a :mod:`repoze.bfg` application, +the :mod:`repoze.bfg` *Router* parses the URL associated with the +request. It splits the URL into individual path segments. Based on +these path segments, :mod:`repoze.bfg` traverses a *model graph* in +order to find a :term:`context`. It then attempts to find a +:term:`view` based on the *type* of the context (specified by its +Python class type or any :term:`interface` attached to it). If :mod:`repoze.bfg` finds a :term:`view` for the context, it calls it and returns a response to the user. @@ -81,8 +82,8 @@ application, the system uses this algorithm to determine which Python code to execute: #. The request for the page is presented to the :mod:`repoze.bfg` - "router" in terms of a standard :term:`WSGI` request, which is - represented by a WSGI environment and a ``start_response`` + :term:`router` in terms of a standard :term:`WSGI` request, which + is represented by a WSGI environment and a ``start_response`` callable. #. The router creates a :term:`WebOb` request object based on the @@ -145,15 +146,16 @@ code to execute: request, an :term:`authorization policy` is consulted to see if the "current user" (al determined by the the authentication policy) can perform the action. If he can, processing continues. - If he cannot, an ``HTTPUnauthorized`` error is raised. + If he cannot, the ``forbidden`` view is called (see + :ref:`changing_the_forbidden_view`). #. 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 and returned. + back upstream. If a view is not found, the ``notfound`` view is + called (see :ref:`changing_the_notfound_view`). In either case, the result is returned upstream via the :term:`WSGI` protocol. @@ -167,10 +169,10 @@ It's useful to be able to debug ``NotFound`` errors when they occur unexpectedly due to an application registry misconfiguration. To debug these errors, use the ``BFG_DEBUG_NOTFOUND`` environment variable or the ``debug_notfound`` configuration file setting. -Details of why a view was not found will be printed to stderr, and the -browser representation of the error will include the same information. -See :ref:`environment_chapter` for more information about how and -where to set these values. +Details of why a view was not found will be printed to ``stderr``, and +the browser representation of the error will include the same +information. See :ref:`environment_chapter` for more information +about how and where to set these values. A Traversal Example ------------------- @@ -189,27 +191,29 @@ traversing the follwing graph:: Here's what happens: -- bfg traverses the root, and attempts to find foo, which it finds. +- :mod:`repoze.bfg` traverses the root, and attempts to find foo, + which it finds. -- bfg traverses foo, and attempts to find bar, which it finds. +- :mod:`repoze.bfg` traverses foo, and attempts to find bar, which it + finds. -- bfg traverses bar, and attempts to find baz, which it does not - find ('bar' raises a ``KeyError`` when asked for baz). +- :mod:`repoze.bfg` traverses bar, and attempts to find baz, which it + does not find ('bar' raises a ``KeyError`` when asked for baz). The fact that it does not find "baz" at this point does not signify an error condition. It signifies that: -- the "context" is bar (the context is the last item found during - traversal). +- the :term:`context` is bar (the context is the last item found + during traversal). -- the "view name" is ``baz`` +- the :term:`view name` is ``baz`` -- the "subpath" is ``('biz', 'buz.txt')`` +- the :term:`subpath` is ``('biz', 'buz.txt')`` -Because it's the "context", bfg examimes "bar" to find out what "type" -it is. Let's say it finds that the context is an ``IBar`` type -(because "bar" happens to have an attribute attached to it that -indicates it's an ``IBar``). +Because it's the "context", :mod:`repoze.bfg` examimes "bar" to find +out what "type" it is. Let's say it finds that the context is an +``IBar`` type (because "bar" happens to have an attribute attached to +it that indicates it's an ``IBar``). Using the "view name" ("baz") and the type, it asks the :term:`application registry` (configured separately, via @@ -218,8 +222,8 @@ Using the "view name" ("baz") and the type, it asks the - Please find me a :term:`view` with the name "baz" that can be used for the type ``IBar``. -Let's say it finds no matching view type. It then returns a -``NotFound``. The request ends. Everyone is sad. +Let's say it finds no matching view type. It then returns the result +of the ``notfound`` view. The request ends. Everyone is sad. But! For this graph:: @@ -235,28 +239,32 @@ But! For this graph:: The user asks for ``http://example.com/foo/bar/baz/biz/buz.txt`` -- bfg traverses foo, and attempts to find bar, which it finds. +- :mod:`repoze.bfg` traverses foo, and attempts to find bar, which it + finds. -- bfg traverses bar, and attempts to find baz, which it finds. +- :mod:`repoze.bfg` traverses bar, and attempts to find baz, which it + finds. -- bfg traverses baz, and attempts to find biz, which it finds. +- :mod:`repoze.bfg` traverses baz, and attempts to find biz, which it + finds. -- bfg traverses biz, and attemtps to find "buz.txt" which it does - not find. +- :mod:`repoze.bfg` traverses biz, and attemtps to find "buz.txt" + which it does not find. The fact that it does not find "buz.txt" at this point does not signify an error condition. It signifies that: -- the "context" is biz (the context is the last item found during traversal). +- the :term:`context` is biz (the context is the last item found + during traversal). -- the "view name" is "buz.txt" +- the :term:`view name` is "buz.txt" -- the "subpath" is an empty sequence ( ``()`` ). +- the :term:`subpath` is an empty sequence ( ``()`` ). -Because it's the "context", bfg examimes "biz" to find out what "type" -it is. Let's say it finds that the context an ``IBiz`` type (because -"biz" happens to have an attribute attached to it that happens -indicates it's an ``IBiz``). +Because it's the "context", :mod:`repoze.bfg` examimes "biz" to find +out what "type" it is. Let's say it finds that the context an ``IBiz`` +type (because "biz" happens to have an attribute attached to it that +happens indicates it's an ``IBiz``). Using the "view name" ("buz.txt") and the type, it asks the :term:`application registry` this question: @@ -272,9 +280,9 @@ It is passed the "biz" object as the "context" and the current There are two special cases: -- During traversal you will often end up with a "view name" that is - the empty string. This indicates that :mod:`repoze.bfg` should look - up the *default view*. The default view is a view that is +- During traversal you will often end up with a :term:`view name` that + is the empty string. This indicates that :mod:`repoze.bfg` should + look up the *default view*. The default view is a view that is registered with no name or a view which is registered with a name that equals the empty string. @@ -326,10 +334,13 @@ used to traverse to the virtual root object. See Unicode and Traversal --------------------- -The traversal machinery by default attempts to decode each path -element in ``PATH_INFO`` from its natural byte string (``str`` type) -representation into Unicode using the UTF-8 encoding before passing it -to the ``__getitem__`` of a model object. If any path segment in -``PATH_INFO`` is not decodeable using the UTF-8 decoding, a TypeError -is raised. +The traversal machinery by default attempts to first URL-unquote and +then Unicode-decode each path element in ``PATH_INFO`` from its +natural byte string (``str`` type) representation. URL unquoting is +performed using the Python stdlib ``urllib.unquote`` function. +Conversion from a URL-decoded string into Unicode is attempted using +the UTF-8 encoding. If any URL-unquoted path segment in ``PATH_INFO`` +is not decodeable using the UTF-8 decoding, a TypeError is raised. A +segment will be fully URL-unquoted and UTF8-decoded before it is +passed it to the ``__getitem__`` of any model object during traversal. diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index ccfbdff58..90ddd6672 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -195,8 +195,14 @@ Will generate the following matchdict:: {'traverse':(u'La Pe\xf1a', u'a', u'b', u'c')} +``<route>`` Statement Examples +------------------------------ + +Let's check out some examples of how ``<route>`` statements might be +commonly declared. + Example 1 ---------- +~~~~~~~~~ The simplest route delcaration: @@ -231,7 +237,7 @@ specified in the ``route`` declaration. It is a mapping object, a lot like a dictionary. Example 2 ---------- +~~~~~~~~~ Below is an example of some more complicated route statements you might add to your ``configure.zcml``: @@ -273,7 +279,7 @@ view available at the dotted Python pathname ``mypackage.views.idea_view``. Example 3 ---------- +~~~~~~~~~ The context object passed to a view found as the result of URL dispatch will by default be an instance of the object returned by the @@ -322,7 +328,7 @@ during ``make_app`. If the "fallback" root factory is None, a not used then. Example 4 ---------- +~~~~~~~~~ An example of configuring a ``view`` declaration in ``configure.zcml`` that maps a context found via URL dispatch to a view function is as @@ -392,6 +398,17 @@ declaration: view=".views.root_view" /> +Or provide the literal string ``/`` as the path: + +.. code-block:: xml + :linenos: + + <route + path="/" + name="root" + view=".views.root_view" + /> + Generating Route URLs --------------------- diff --git a/docs/narr/urlmapping.rst b/docs/narr/urlmapping.rst index 269061e40..1c9cde888 100644 --- a/docs/narr/urlmapping.rst +++ b/docs/narr/urlmapping.rst @@ -4,12 +4,13 @@ Mapping URLs to Code ==================== Many popular web frameworks today use :term:`URL dispatch` to -associate a particular URL with a bit of code (known somewhat -ambiguously as a "controller" or :term:`view` depending upon the -particular vocabulary religion to which you subscribe). These systems -allow the developer to create "urlconfs" or "routes" to -controller/view Python code using pattern matching against URL -components. Examples: `Django's URL dispatcher +associate a particular URL with a bit of code. In these systems, the +bit of code associated with a URL is known somewhat ambiguously as a +"controller" or :term:`view` depending upon the particular vocabulary +religion to which you subscribe. Such systems allow the developer to +create "urlconfs" or "routes" to controller/view Python code using +pattern matching against URL components. Examples: `Django's URL +dispatcher <http://www.djangoproject.com/documentation/url_dispatch/>`_ and the :term:`Routes` URL mapping system. @@ -62,12 +63,13 @@ URL-dispatch based systems, and some assertions just aren't possible. For example, URL-dispatch based systems don't deal very well with URLs that represent arbitrary-depth hierarchies. -Graph :term:`traversal` works well if you need to divine meaning out -of these types of "ambiguous" URLs and URLs that represent -arbitrary-depth hierarchies. Each URL segment represents a single -traversal through an edge of the graph. So a URL like -``http://example.com/a/b/c`` can be thought of as a graph traversal on -the ``example.com`` site through the edges ``a``, ``b``, and ``c``. +Graph :term:`traversal` works well if you need to divine meaning from +of these types of "ambiguous" URLs and from URLs that represent +arbitrary-depth hierarchies. When traversal is used, each URL segment +represents a single traversal step through an edge of a graph. So a +URL like ``http://example.com/a/b/c`` can be thought of as a graph +traversal on the ``example.com`` site through the edges ``a``, ``b``, +and ``c``. If you're willing to treat your application models as a graph that can be traversed, it also becomes easy to provide "row-level security" (in diff --git a/docs/narr/views.rst b/docs/narr/views.rst index d68f5cd3d..4435bbceb 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -4,9 +4,10 @@ Views ===== A :term:`view` is a callable which is invoked when a request enters -your application. :mod:`repoze.bfg's` primary job is to find and call -a view when a :term:`request` reaches it. The view's return value -must implement the :term:`WebOb` ``Response`` object interface. +your application. The primary job of any :mod:`repoze.bfg` +application is is to find and call a :term:`view` when a +:term:`request` reaches it. The value returned by a :term:`view` must +implement the :term:`WebOb` ``Response`` object interface. .. _function_as_view: @@ -267,7 +268,8 @@ route_name referred to by ``route_name`` usually has a ``*traverse`` token in the value of its ``path`` attribute, representing a part of the path that will be used by traversal against the result of the route's - :term:`root factory`. + :term:`root factory`. See :ref:`hybrid_chapter` for more + information on using this advanced feature. .. _mapping_views_to_urls_using_a_decorator_section: @@ -295,12 +297,12 @@ decorator to do this work. .. warning:: using this feature tends to slows down application startup slightly, as more work is performed at application startup - to scan for view declarations. Also, if you use decorators, it - means that other people will not be able to override your view - declarations externally using ZCML: this is a common requirement if - you're developing an exensible application (e.g. a framework). See - :ref:`extending_chapter` for more information about building - extensible applications. + to scan for view declarations. Additionally, if you use + decorators, it means that other people will not be able to override + your view declarations externally using ZCML: this is a common + requirement if you're developing an exensible application (e.g. a + framework). See :ref:`extending_chapter` for more information + about building extensible applications. The ``bfg_view`` Decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -591,8 +593,9 @@ specifying a permission in a ``view`` declaration: When an authentication policy is enabled, this view will be protected with the ``add`` permission. The view will *not be called* if the user does not possess the ``add`` permission relative to the current -:term:`context` and an authorization policy is enabled. Instead an -HTTP ``Unauthorized`` status will be returned to the client. +:term:`context` and an authorization policy is enabled. Instead the +``forbidden`` view result will be returned to the client (see +:ref:`changing_the_forbidden_view`). .. note:: @@ -621,8 +624,8 @@ slightly different response. return HTTPFound(location='http://example.com') All exception types from the :mod:`webob.exc` module implement the -``IResponse`` interface; any can be returned as the response from a -view. See :term:`WebOb` for the documentation for this module; it +Webob ``Response`` interface; any can be returned as the response from +a view. See :term:`WebOb` for the documentation for this module; it includes other response types for Unauthorized, etc. .. _static_resources_section: @@ -686,12 +689,6 @@ these will be resolved by the static view as you would expect. ``/static/foo.js``. See :ref:`traversal_chapter` for information about "goggles" (``@@``). -.. note:: Under the hood, the ``repoze.bfg.view.static`` class employs - the ``urlparser.StaticURLParser`` WSGI application to serve static - files. See `the Paste documentation for urlparser - <http://pythonpaste.org/modules/urlparser.html>`_ for more - information about ``urlparser.StaticURLParser``. - Using Views to Handle Form Submissions (Unicode and Character Set Issues) ------------------------------------------------------------------------- |
