diff options
| author | Chris McDonough <chrism@agendaless.com> | 2008-07-28 05:31:47 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2008-07-28 05:31:47 +0000 |
| commit | 178623bbd8e9aab75b6206ef69f67b62edb3d12e (patch) | |
| tree | 2442c1d41bdb13a41e4ab841fddcc091d5804ca2 | |
| parent | 96e65d8e6d47a1b806c4d281e6890f77f86407c3 (diff) | |
| download | pyramid-178623bbd8e9aab75b6206ef69f67b62edb3d12e.tar.gz pyramid-178623bbd8e9aab75b6206ef69f67b62edb3d12e.tar.bz2 pyramid-178623bbd8e9aab75b6206ef69f67b62edb3d12e.zip | |
Tweaks.
| -rw-r--r-- | docs/glossary.rst | 162 | ||||
| -rw-r--r-- | docs/narr/introduction.rst | 10 | ||||
| -rw-r--r-- | docs/narr/models.rst | 29 | ||||
| -rw-r--r-- | docs/narr/project.rst | 200 | ||||
| -rw-r--r-- | docs/narr/security.rst | 32 | ||||
| -rw-r--r-- | docs/narr/traversal.rst | 181 | ||||
| -rw-r--r-- | docs/tutorials/lxmlgraph/background.rst | 69 | ||||
| -rw-r--r-- | docs/tutorials/lxmlgraph/index.rst | 12 | ||||
| -rw-r--r-- | docs/tutorials/lxmlgraph/step01.rst | 7 | ||||
| -rw-r--r-- | docs/tutorials/lxmlgraph/step02.rst | 39 | ||||
| -rw-r--r-- | docs/tutorials/lxmlgraph/step03.rst | 17 |
11 files changed, 419 insertions, 339 deletions
diff --git a/docs/glossary.rst b/docs/glossary.rst index b42d2cc7e..a3c377f49 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -16,7 +16,21 @@ Glossary Setuptools `Setuptools <http://peak.telecommunity.com/DevCenter/setuptools>`_ builds on Python's ``distutils`` to provide easier building, - distribution, and installation of packages. + distribution, and installation of libraries and applications. + Package + A directory on disk which contains an ``__init__.py`` file, making + it recognizable to Python as a location which can be ``import`` -ed. + Project + (Setuptools/distutils terminology). A directory on disk which + contains a ``setup.py`` file and one or more Python packages. The + ``setup.py`` file contains code that allows the package(s) to be + installed, distributed, and tested. + Distribution + (Setuptools/distutils terminology). A file representing an + installable library or application. Distributions are usually + files that have the suffix of ``.egg``, ``.tar.gz``, or ``.zip``. + Distributions are the target of Setuptools commands such as + ``easy_install``. View A "view" is a callable which returns a response object. It should accept two values: context and request. @@ -33,80 +47,102 @@ Glossary An object representing data in the system. A model is part of the object graph traversed by the system. Models are traversed to determine a context. + Traversal + The act of descending "down" a graph of model objects from a root + 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. + URL dispatch + An alternative to graph traversal as a mechanism for locating a + :term:`context` for a :term:`view`. When you use :term:`Routes` + in your :mod:`repoze.bfg` application, you are using URL dispatch. + See the :ref:`urldispatch_module` for more information. Context - A model in the system that is found during traversal; it becomes - the subject of a view. + A :term:`model` in the system that is "found" during + :term:`traversal` or :term:`URL dispatch`; it becomes the subject + of a :term:`view`. See the :ref:`traversal_chapter` chapter for + more information. Application registry A registry which maps model types to views, as well as performing - other application-specific component registrations. + other application-specific component registrations. Every + :mod:`repoze.bfg` application has one (and only one) application + registry, which is represented on disk by its ``configure.zcml`` + file. Template - A file that is capable of representing some text when rendered. + A file with replaceable parts that is capable of representing some + text, XML, or HTML when rendered. Interface - An attribute of a model object that determines its type. + An attribute of an object that determines its type. Location The path to an object in a model graph. Security policy An object that provides a mechanism to check authorization using authentication data and a permission associated with a model. It essentially returns "true" if the combination of the authorization - information in the model (e.g. an ACL) and the authentication data - in the request (e.g. the REMOTE_USER) allow the action implied by - the permission associated with the view (e.g. "add"). + information in the model (e.g. an :term:`ACL`) and the + authentication data in the request (e.g. the ``REMOTE_USER`` + environment variable) allow the action implied by the permission + associated with the view (e.g. ``add`` or ``read``). Principal A user id or group id. Permission A string or unicode object that represents an action being taken against a context. A permission is associated with a view name and a model type by the developer. Models are decorated with - security declarations (e.g. ACLs), which reference these tokens - also. Permissions are used by the active to security policy to - match the view permission against the model's statements about - which permissions are granted to which principal in a context in - order to to answer the question "is this user allowed to do this". - Examples of permissions: "read", or "view_blog_entries". + security declarations (e.g. an :term:`ACL`), which reference these + tokens also. Permissions are used by the active to security + policy to match the view permission against the model's statements + about which permissions are granted to which principal in a + context in order to to answer the question "is this user allowed + to do this". Examples of permissions: ``read``, or + ``view_blog_entries``. ACE An *access control entry*. An access control entry is one element - in an *ACL*. An access control entry is a three-tuple that + in an :term:`ACL`. An access control entry is a three-tuple that describes three things: an *action* (one of either ``Allow`` or - ``Deny``), a *principal* (a string describing a user or group), and - a *permission*. For example the ACE, ``(Allow, 'bob', 'read')`` is - a member of an ACL that indicates that the principal ``bob`` is - allowed the permission ``read`` against the context the ACL is - attached to. + ``Deny``), a :term:`principal` (a string describing a user or + group), and a :term:`permission`. For example the ACE, ``(Allow, + 'bob', 'read')`` is a member of an ACL that indicates that the + principal ``bob`` is allowed the permission ``read`` against the + context the ACL is attached to. ACL - An *access control list*. An ACL is a sequence of *ACE* s. An ACL - is attached to a model instance. An example of an ACL is ``[ - (Allow, 'bob', 'read'), (Deny, 'fred', 'write')]``. If an ACL is - attached to a model instance, and that model instance is findable - via the context, it will be consulted by the security policy to - determine wither a particular request can be fulfilled given the - *authentication* information in the request. + An *access control list*. An ACL is a sequence of :term:`ACE` + tuples. An ACL is attached to a model instance. An example of an + ACL is ``[ (Allow, 'bob', 'read'), (Deny, 'fred', 'write')]``. If + an ACL is attached to a model instance, and that model instance is + findable via the context, it will be consulted any active security + policy to determine wither a particular request can be fulfilled + given the :term:`authentication` information in the request. Authentication - The act of determining that the credentials a user presents during a - particular request are "good". ``repoze.bfg`` does not perfom - authentication: it leaves it up to an upstream component such as - ``repoze.who``. ``repoze.bfg`` uses the authentication data - supplied by the upstream component as one input during - authorization. + The act of determining that the credentials a user presents during + a particular request are "good". :mod:`repoze.bfg` does not + perfom authentication: it leaves it up to an upstream component + such as :term:`repoze.who`. :mod:`repoze.bfg` uses the + :term:`authentication` data supplied by the upstream component as + one input during :term:`authorization`. Authorization - The act of determining whether a user can perform a specific action. - In bfg terms, this means determining whether, for a given context, - the *principals* associated with the request have the requisite - *permission* to allow the request to continue. + The act of determining whether a user can perform a specific + action. In bfg terms, this means determining whether, for a given + context, any :term:`principal` (or principals) associated with the + request have the requisite :term:`permission` to allow the request + to continue. Principal - A *principal* is a string or unicode object representing a user or a - user's membership in a group. It is provided by the - *authentication* machinery upstream, typically. For example, if a - user had the user id "bob", and Bob was part of two groups named - "group foo" and "group bar", the request might have information - attached to it that would indictate that Bob was represented by - three principals: "bob", "group foo" and "group bar". + A *principal* is a string or unicode object representing a user or + a user's membership in a group. It is provided by the + :term:`authentication` machinery "upstream", typically (such as + :term:`repoze.who`). For example, if a user had the user id + "bob", and Bob was part of two groups named "group foo" and "group + bar", the request might have information attached to it that would + indictate that Bob was represented by three principals: "bob", + "group foo" and "group bar". Security Policy A security policy in bfg terms is a bit of code which accepts a - request, the *ACL* associated with a context, and the *permission* - associated with a particular view, and determines whether or not the - principals associated with the request can perform the action - associated with the permission based on the ACL. + request, the :term:`ACL` associated with a context, and the + :term:`permission` associated with a particular view, and + subsequently determines whether or not the principals associated + with the request can perform the action associated with the + permission based on the ACL found on the :term:`context` (or any + of its parents). WSGI `Web Server Gateway Interface <http://wsgi.org/>`_. This is a Python standard for connecting web applications to web servers, @@ -120,9 +156,17 @@ Glossary Paste `Paste <http://pythonpaste.org>`_ is a WSGI development and deployment system developed by Ian Bicking. + PasteDeploy + `PasteDeploy <http://pythonpaste.org>`_ is a library used by + :mod:`repoze.bfg` which makes it possible to configure + :term:`WSGI` components together declaratively within an ``.ini`` + file. It was developed by Ian Bicking as part of :term:`Paste`. LXML `lxml <http://codespeak.net/lxml/>`_ is a XML processing library for Python by Martijn Faassen and others. + XSLT + `XSL Transformations <http://www.w3.org/TR/xslt>`_. A language + for transforming XML documents into other XML documents. z3c.pt `z3c.pt <http://pypi.python.org/pypi/z3c.pt>`_ is an implementation of the `Zope Page Template @@ -137,3 +181,23 @@ Glossary graph traversal when deciding which *view* should be called. See :ref:`urldispatch_module` for more information about (optional) Routes integration in bfg. + ZCML + `Zope Configuration Markup Language + <http://www.muthukadan.net/docs/zca.html#zcml>`_, the XML dialect + used by Zope and :mod:`repoze.bfg` to describe associating a view + with a model type. ZCML is capable of performing many different + registrations and declarations, but its primary purpose in + :mod:`repoze.bfg` is to perform view mappings via the ``bfg:view`` + declaration. The ``configure.zcml`` file in a :mod:`repoze.bfg` + application represents the application's :term:`application + registry`. + repoze.who + `Authentication middleware + <http://svn.repoze.org/repoze.who/trunk/README.txt>`_ for + :term:`WSGI` applications. It can be used by :mod:`repoze.bfg` to + provide authentication information. + ReStructuredText + 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. + diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 61b03b3dc..bf2f07e19 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -16,11 +16,15 @@ Similarities with Other Frameworks :mod:`repoze.bfg` was inspired by Zope, Django, and Pylons. -:mod:`repoze.bfg`'s traversal is inspired by Zope. :mod:`repoze.bfg` +:mod:`repoze.bfg` traversal is inspired by Zope. :mod:`repoze.bfg` uses the Zope Component Architecture ("CA") internally, as do Zope 2, Zope 3, and Grok. Developers don't interact with the CA very much during typical development, however; it's mostly used by the framework -developer rather than the application developer. +developer rather than the application developer. :mod:`repoze.bfg` +developers use :term:`ZCML` (an XML dialect) to perform various +configuration tasks; in particular, as in Zope3, one more more +:term:`view` functions is associated with a :term:`model` type via +ZCML. Like Pylons, :mod:`repoze.bfg` is mostly policy-free. It makes no assertions about which database you should use, and its built-in @@ -62,7 +66,7 @@ happens to be true for :mod:`repoze.bfg`:: framework - that is, "model", "template", and "view." That breakdown makes much more sense. -:mod:`repoze.bfg` 's skeleton code generator generates a directory +The skeleton code generator of :mod:`repoze.bfg` generates a directory layout very simliar to the directory layout suggested by the `Django Book <http://www.djangobook.com/>`_ . Additionally, as suggested above, the concepts of :term:`view`, :term:`model` and diff --git a/docs/narr/models.rst b/docs/narr/models.rst index cff04ea18..1e5685ed6 100644 --- a/docs/narr/models.rst +++ b/docs/narr/models.rst @@ -1,9 +1,9 @@ Models ====== -*Models* are typically simple Python classes defined in a module. - Model *instances* make up the graph that :mod:`repoze.bfg` is willing - to traverse. +A :term:`model` is typically a simple Python class defined in a +module. Model *instances* make up the graph that :mod:`repoze.bfg` is +willing to traverse. Defining a Model ---------------- @@ -26,11 +26,11 @@ An example of a model describing a blog entry:: self.created = datetime.datetime.now() A model consists of two things: the object which defines the model -(above as the class ``IBlogEntry``), and an *interface* attached to -the model object. An interface simply tags the model object with a -"type" that can be referred to within view configuration. A model -object can implement zero or more interfaces. The interface must be -an instance of a class that inherits from +(above as the class ``IBlogEntry``), and an :term:`interface` attached +to the model object. An interface simply tags the model object with a +"type" that can be referred to within the :term:`application +registry`. A model object can implement zero or more interfaces. The +interface must be an instance of a class that inherits from ``zope.interface.Interface``. You specify that a model *implements* an interface by using the @@ -67,13 +67,14 @@ Location-Aware Model Instances by via ``__getitem__``. If you choose not to manage the ``__name__`` and ``__parent__`` - attributes of your models "by hand", :mod:`repoze.bfg`` is willing - to help you do this. If your "root" node claims it implements the + attributes of your models "by hand", :mod:`repoze.bfg`` is willing to + help you do this. If your "root" node claims it implements the interface ``zope.location.interfaces.ILocation``, you don't need to - manage these attributes by hand. During traversal, if the root node - says it implements ``ILocation``, bfg will wrap each child in a - LocationProxy which will dynamically assign a ``__name__`` and a - ``__parent__`` to it, recursively. + manage these attributes by hand. During :term:`traversal`, if the + root node says it implements the ``ILocation`` :term:`interface`, + :mod:`repoze.bfg` will wrap each child in a ``LocationProxy`` which + will dynamically assign a ``__name__`` and a ``__parent__`` to it, + recursively. If you choose to make use of the location-based dynamic assignment of ``__parent__`` and ``__name__``, the root node must have a diff --git a/docs/narr/project.rst b/docs/narr/project.rst index f67e28e1e..53ba15b74 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -10,8 +10,8 @@ creation of a new project by answering a series of questions. Creating the Project -------------------- -To start a :mod:`repoze.bfg` project, use the ``paster create`` -facility:: +To start a :mod:`repoze.bfg` :term:`project`, use the ``paster +create`` facility:: $ paster create -t bfg @@ -49,27 +49,26 @@ project we name ``myproject``:: Running /Users/chrism/projects/repoze-devel/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` *project* -directory from which a Python setuptools *distribution* can be +``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 ``PasteDeploy`` ``.ini`` file +deployment or development. A sample :term:`PasteDeploy` ``.ini`` file named ``myproject.ini`` will also be created in the project directory. -You can use this to run your application. +You will use the ``paster serve`` command against this ``ini`` file to +run your application. -The main ``myproject`` contains an additional subdirectory (also named -``myproject``) representing a Python pakckage which holds very simple -bfg sample code. This is where you'll edit your application's Python -code and templates. +The main ``myproject`` directory contains an additional subdirectory +(also named ``myproject``) representing a Python :term:`package` which +holds very simple :mod:`repoze.bfg` sample code. This is where you'll +edit your application's Python code and templates. Installing your Newly Created Project for Development ----------------------------------------------------- -Using your favorite Python interpreter (using a `virtualenv -<http://pypi.python.org/pypi/virtualenv>`_ is suggested in order to -isolate your application from your system Python's packages), invoke -the following command when inside the project directory against the -generated ``setup.py``:: +Using your favorite Python interpreter (or, better, the interpreter +from a :term:`virtualenv`), invoke the following command when inside +the project directory against the generated ``setup.py``:: $ python setup.py develop @@ -79,8 +78,9 @@ Elided output from a run of this command is shown below:: ... Finished processing dependencies for myproject==0.1 -This will install your application 's package into the interpreter so -it can be found and run as a WSGI application inside a WSGI server. +This will install your application 's :term:`package` into the +interpreter so it can be found and run as a :term:`WSGI` application +inside a WSGI server. Running The Tests For Your Application -------------------------------------- @@ -139,20 +139,21 @@ port 5432. Viewing the Application ----------------------- -Visit http://localhost:5432/ in your browser. You will see:: +Visit *http://localhost:5432/* in your browser. You will see:: Welcome to myproject -That's the page shown by default when you visit a generated -application. +That's the page shown by default when you visit an unmodified ``paster +create``-generated application. The Project Structure --------------------- -Our generated :mod:`repoze.bfg` application is a setuptools *project* -(named ``myproject``), which contains a Python package (which is -*also* named ``myproject``; the paster template generates a project -which contains a package that shares its name). +Our generated :mod:`repoze.bfg` application is a setuptools +:term:`project` (named ``myproject``), which contains a Python +:term:`package` (which is *also* named ``myproject``; the paster +template generates a project which contains a package that shares its +name). The ``myproject`` project has the following directory structure:: @@ -172,64 +173,71 @@ The ``myproject`` project has the following directory structure:: |-- myproject.ini `-- setup.py -The ``myproject`` *Project* ---------------------------- +The ``myproject`` :term:`Project` +--------------------------------- -The ``myproject`` project is the distribution and deployment wrapper -for your application. It contains both the ``myproject`` *package* -representing your application as well as files used to describe, run, -and test your application. +The ``myproject`` :term:`project` is the distribution and deployment +wrapper for your application. It contains both the ``myproject`` +:term:`package` representing your application as well as files used to +describe, run, and test your application. -#. ``CHANGES.txt`` describes the changes you've made to the application. +#. ``CHANGES.txt`` describes the changes you've made to the + application. It is conventionally written in + :term:`ReStructuredText` format. -#. ``README.txt`` describes the application in general. +#. ``README.txt`` describes the application in general. It is + conventionally written in :term:`RestructuredText` format. #. ``ez_setup.py`` is a file that is used by ``setup.py`` to install - setuptools if the executing user does not have it installed. + :term:`setuptools` if the executing user does not have it + installed. -#. ``myproject.ini`` is a PasteDeploy configuration file that can be - used to execute your application. +#. ``myproject.ini`` is a :term:`PasteDeploy` configuration file that + can be used to execute your application. #. ``setup.py`` is the file you'll use to test and distribute your - application. It is a standard distutils/setuptools ``setup.py`` file. + application. It is a standard :term:`setuptools` ``setup.py`` + file. -It also contains the ``myproject`` *package*, described below. +It also contains the ``myproject`` :term:`package`, described below. -The ``myproject`` *Package* ---------------------------- +The ``myproject`` :term:`Package` +--------------------------------- -The ``myproject`` package lives inside the ``myproject`` project. It -contains: +The ``myproject`` :term:`package` lives inside the ``myproject`` +:term:`project`. It contains: #. An ``__init__.py`` file which signifies that this is a Python - package. It is conventionally empty, save for a single comment at - the top. + :term:`package`. It is conventionally empty, save for a single + comment at the top. -#. A ``configure.zcml`` file which maps view names to model types. - This is also known as the "application registry", although it - also often contains non-view-related declarations. +#. A ``configure.zcml`` is a :term:`ZCML` file which maps view names + to model types. This is also known as the :term:`application + registry`. -#. A ``models.py`` module, which contains model code. +#. A ``models.py`` module, which contains :term:`model` code. #. A ``run.py`` module, which contains code that helps users run the application. -#. A ``templates`` directory, which is full of zc3.pt and/or XSL - templates. +#. A ``templates`` directory, which is full of :term:`z3c.pt` and/or + :term:`XSLT` templates. -#. A ``tests.py`` module, which contains test code. +#. A ``tests.py`` module, which contains unit test code for the + application. -#. A ``views.py`` module, which contains view code. +#. A ``views.py`` module, which contains view code for the + application. -These are purely conventions established by the Paster template: +These are purely conventions established by the ``paster`` template: :mod:`repoze.bfg` doesn't insist that you name things in any particular way. ``configure.zcml`` ~~~~~~~~~~~~~~~~~~ -The ``configure.zcml`` (representing the application registry) looks -like so: +The ``configure.zcml`` represents the :term:`application +registry`. It looks like so: .. literalinclude:: myproject/myproject/configure.zcml :linenos: @@ -244,7 +252,17 @@ like so: #. Lines 8-11 register a single view. It is ``for`` model objects that support the IMyModel interface. The ``view`` attribute points - at a Python function that does all the work for this view. + at a Python function that does all the work for this view. Note + that the values of both the ``for`` attribute and the ``view`` + attribute begin with a single period. Names that begin with a + period are "shortcuts" which point at files relative to the + :term:`package` in which the ``configure.zcml`` file lives. In + this case, since the ``configure.zcml`` file lives within the + ``myproject`` project, the shorcut ``.models.IMyModel`` could also + be spelled ``myproject.models.IMyModel`` (forming a full Python + dotted-path name to the ``IMyModel`` class). Likewise the shortcut + ``.views.my_view`` could be replaced with + ``myproject.views.my_view``. ``views.py`` ~~~~~~~~~~~~ @@ -257,31 +275,36 @@ in the model, and the HTML given back to the browser. :linenos: #. Lines 3-5 provide the ``my_view`` that was registered as the view. - ``configure.zcml`` said that the default URL for IMyModel content - should run this ``my_view`` function. + ``configure.zcml`` said that the default URL for ``IMyModel`` + content should run this ``my_view`` function. - The function is handed two pieces of information: the ``context`` - and the ``request``. The ``context`` is the data at the current - hop in the URL. (That data comes from the model.) The request is - an instance of a WebOb request. + The function is handed two pieces of information: the + :term:`context` and the term:`request`. The *context* is the term + :term:`model` found via :term:`traversal` (or via :term:`URL + dispatch`). The *request* is an instance of the :term:`WebOb` + ``Request`` class representing the browser's request to our server. -#. The model renders a template and returns the result as the - response. +#. The view renders a :term:`template` and returns the result as the + :term:`response`. .. note:: - This example uses ``render_template_to_response`` which allows the - view author to think only in terms of templates. If you want more - control over the response, use ``render_template`` and create your - own ``WebOb`` Response object to return. + This example uses ``render_template_to_response`` which is a + shortcut function. If you want more control over the response, use + the ``render_template`` function, also present in + :ref:`template_module`. You may then create your own :term:`WebOb` + Response object, using the result of ``render_template`` as the + response's body. ``models.py`` ~~~~~~~~~~~~~ -In our sample app, the ``models.py`` module provides the model data. -We create an interface ``IMyModel`` that gives us the "type" for our -data. We then write a class ``MyModel`` that provides the behavior -for instances of the ``IMyModel`` type. +The ``models.py`` module provides the :term:`model` data for our +application. We write a class named ``MyModel`` that provides the +behavior. We then create an interface ``IMyModel`` that is a +:term:`interface` which serves as the "type" for our data, and we +associate it without our ``MyModel`` class by claiming that the class +``implements`` the interface. .. literalinclude:: myproject/myproject/models.py :linenos: @@ -303,29 +326,39 @@ make any assumption about which sort of datastore you'll want to use, so the sample application uses an instance of ``MyModel`` to represent the root. +What will likely frighten new developers in the model file is the use +of :term:`interface` classes. In their simplest form (which is the +only form that :mod:`repoze.bfg` requires you to understand), +interfaces are simply "marker" attributes indicating the *type* of a +model object. These can be attached to classes (via the +``implements`` function with one or more interfaces as arguments at +class scope). In more advanced usage, they can be attached directly +to instances. We do not demonstrate that here. + ``run.py`` ~~~~~~~~~~ We need a small Python module that configures our application and -advertises itself to our Paste ``.ini`` file. For convenience, we -also make it possible to run this module directory without the Paste -configuration file: +advertises itself to our :term:`PasteDeploy` ``.ini`` file. For +convenience, we also make it possible to run this module directory +without the PasteDeploy configuration file: .. literalinclude:: myproject/myproject/run.py :linenos: #. Lines 1 - 7 define a function that returns a :mod:`repoze.bfg` - Router application. This is meant to be called by the PasteDeploy - framework as a result of running ``paster serve``. + 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 9 - 12 allow this file to serve 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 5432. +#. Lines 9 - 12 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 5432. ``templates/mytemplate.pt`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The single template in the project looks like so: +The single :term:`template` in the project looks like so: .. literalinclude:: myproject/myproject/templates/mytemplate.pt :linenos: @@ -333,7 +366,8 @@ The single template in the project looks like so: This is a :term:`z3c.pt` template. It displays the current project name when it is rendered. It is referenced by the ``my_view`` -function in the ``views.py`` module. +function in the ``views.py`` module. Templates are accessed and used +by view functions. ``tests.py`` ~~~~~~~~~~~~ @@ -345,5 +379,7 @@ The ``tests.py`` module includes unit tests for your application. This sample ``tests.py`` file has a single unit test defined within it. This is the code that is executed when you run ``setup.py test --q``. You may add more tests here as you build your application. +-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 7adeda3b9..36c0b618a 100644 --- a/docs/narr/security.rst +++ b/docs/narr/security.rst @@ -1,10 +1,10 @@ Security ======== -``repoze.bfg`` provides an optional declarative security system that -prevents views that are protected by a :term:`permission` from being -rendered when the user represented by the request does not have the -appropriate level of access in a context. +:mod:`repoze.bfg` provides an optional declarative security system +that prevents views that are protected by a :term:`permission` from +being rendered when the user represented by the request does not have +the appropriate level of access in a context. Security is enabled by adding configuration to your ``configure.zcml`` which specifies a :term:`security policy`. @@ -12,8 +12,8 @@ which specifies a :term:`security policy`. Enabling a Security Policy -------------------------- -By default, ``repoze.bfg`` enables no security policy. All views are -accessible by completely anonymous users. +By default, :mod:`repoze.bfg` enables no security policy. All views +are accessible by completely anonymous users. However, if you add the following bit of code to your application's ``configure.zcml``, you will enable a security policy:: @@ -36,10 +36,11 @@ WSGI server. Protecting Views with Permissions --------------------------------- -You declaratively protected a particular view with a permisson via the -``configure.zcml`` application registry. For example, the following -declaration protects the view named ``add_entry.html`` when invoked -against an ``IBlog`` context with the ``add`` permission:: +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 an ``IBlog`` context with the +``add`` permission:: <bfg:view for=".models.IBlog" @@ -59,7 +60,7 @@ to the system. You can name permissions whatever you like. Assigning ACLs to your Model Objects ------------------------------------ -When ``repoze.bfg`` determines whether a user possesses a particular +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 @@ -86,9 +87,10 @@ class:: ] implements(IBlog, ILocation) -The above ACL indicates that the Everyone principal (a system-defined -principal) is allowed to view the blog, the ``group:editors`` -principal is allowed to add to and edit the blog. +The above ACL indicates that the ``Everyone`` principal (a special +system-defined principal indicating, literally, everyone) is allowed +to view the blog, the ``group:editors`` principal is allowed to add to +and edit the blog. A principal is usually a user id, however it also may be a group id if your authentication system provides group information and the security @@ -119,7 +121,7 @@ which points at their parent object. The root object's ``__parent__`` is ``None``. An object with a ``__parent__`` attribute and a ``__name__`` attribute is said to be *location-aware*. -If the root object in a ``repoze.bfg`` application declares that it +If the root object in a :mod:`repoze.bfg` application declares that it implements the ``ILocation`` interface, it is assumed that the objects in the rest of the model are location-aware. Even if they are not explictly, if the root object is marked as ``ILocation``, the bfg diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 64e92c570..673f94927 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -1,33 +1,30 @@ +.. _traversal_chapter: + Traversal ========= -In many popular web frameworks, a "URL dispatcher" is used to +In many popular web frameworks, :term:`URL dispatch` is used to associate a particular URL with a bit of code (known somewhat -ambiguously as a "controller" or "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 +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 <http://www.djangoproject.com/documentation/url_dispatch/>`_ and the -`Routes URL mapping system <http://routes.groovie.org/>`_ . - -It is possible, however, to map URLs to code differently, using -"object graph traversal". The venerable Zope and CherryPy web -frameworks offer graph-traversal-based URL dispatch. -:mod:`repoze.bfg` also provides graph-traversal-based dispatch of URLs -to code. Graph-traversal based dispatching is useful if you like the -URL to represent an arbitrary hierarchy of potentially heterogeneous -items. +:term:`Routes` URL mapping system. -.. note:: +:mod:`repoze.bfg` supports :term:`URL dispatch` via :term:`Routes`. +See the :ref:`urldispatch_module` for more information about using URL +dispatch. - :mod:`repoze.bfg` features graph traversal. However, via the - inclusion of :term:`Routes`, URL dispatch is also supported for the - parts of your URL space that better fit that model. See the - :ref:`urldispatch_module` for more information about using URL - dispatch. +By default, however, :mod:`repoze.bfg` does not use URL dispatch to +map URLs to code. Instead, it maps URLs to code slightly differently, +using object graph :term:`traversal`. The venerable Zope and CherryPy +web frameworks offer graph-traversal-based URL dispatch. +Graph-traversal based dispatching is useful if you like the URL to +represent an arbitrary hierarchy of potentially heterogeneous items. -Non-graph traversal based URL dispatch can easily handle URLs such as +:term:`URL dispatch` can easily handle URLs such as ``http://example.com/members/Chris``, where it's assumed that each item "below" ``members`` in the URL represents a member in the system. You just match everything "below" ``members`` to a particular view. @@ -39,18 +36,18 @@ sets of URLs such as:: ...wherein you'd like the ``document`` in the first URL to represent a PDF document, and ``/stuff/page`` in the second to represent an -OpenOffice document in a "stuff" folder. It takes more pattern +*OpenOffice* document in a "stuff" folder. It takes more pattern matching assertions to be able to make URLs like these work in 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 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 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``. Finally, if you're willing to treat your application models as a graph that can be traversed, it also becomes trivial to provide "row-level @@ -62,10 +59,10 @@ Graph traversal is materially more complex than URL-based dispatch, however, if only because it requires the construction and maintenance of a graph, and it requires the developer to think about mapping URLs to code in terms of traversing the graph. (How's *that* for -self-referential! ;-) That said, for developers comfortable with Zope -(and comfortable with hierarchical data stores like ZODB), mapping a -URL to a graph traversal is a natural way to think about creating a -web application. +self-referential! ;-) ) That said, for developers comfortable with +:term:`Zope` or comfortable with hierarchical data stores like *ZODB* +or a filesystem, mapping a URL to a graph traversal is a natural way +to think about creating a web application. In essence, the choice to use graph traversal vs. URL dispatch is largely religious in some sense. Graph traversal dispatch probably @@ -74,30 +71,32 @@ stored in a relational database. However, when you have a hierarchical data store, it can provide advantages over using URL-based dispatch. -Thus :mod:`repoze.bfg` provides support for both approaches, even -though the focus is on object graph traversal. +:mod:`repoze.bfg` provides support for both approaches. Graph +traversal is described in detail below. The Model Graph --------------- -Users interact with your :mod:`repoze.bfg`-based application via a +Users interact with your :mod:`repoze.bfg` -based application via a "router", which is itself a WSGI application. At system startup time, the router is configured with a root object from which all traversal -will begin. The root object is a mapping object, such as a Python -dictionary. In fact, all items contained in the graph are either leaf -nodes (these have no ``__getitem__``) or container nodes (these do -have a ``__getitem__``). +will begin. The root object is usually a mapping object, such as a +Python dictionary. Usually the root is a *container* node, and thus +contains other items. In fact, all items contained in the graph are +either *leaf* nodes (these have no ``__getitem__``) or *container* +nodes (these do have a ``__getitem__``). Items contained within the graph are analogous to the concept of -``model`` objects used by many other frameworks (and :mod:`repoze.bfg` -refers to them as models, as well). They are typically instances of -classes. Each containerish instance is willing to return a child or -raise a KeyError based on a name passed to its ``__getitem__``. No -leaf-level instance is required to have a ``__getitem__``. +:term:`model` objects used by many other frameworks (and +:mod:`repoze.bfg` refers to them as models, as well). They are +typically instances of Python classes. Each containerish instance is +willing to return a child or raise a ``KeyError`` based on a name +passed to its ``__getitem__``. No leaf-level instance is required to +have a ``__getitem__``. :mod:`repoze.bfg` traverses the model graph in order to find a -*context*. It then attempts to find a *view* based on the type of the -context. +:term:`context`. It then attempts to find a :term`view` based on the +type (specified by an :term:`interface`) of the context. How :mod:`repoze.bfg` Processes a Request Using Traversal --------------------------------------------------------- @@ -107,12 +106,12 @@ 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 - "router" in terms of a standard WSGI request, which is + "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 `WebOb <http://pythonpaste.org/webob/>`_ - request object based on the WSGI environment. + 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 @@ -121,59 +120,60 @@ code to execute: request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the traversal sequence ``['a', 'b', 'c']``. - 4. 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 + 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 ``@@`` + 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 - "context". If the path has been exhausted when traversal ends, - the "view name" is deemed to be the empty string (``''``). + :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 + *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']``. + 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 security policy is configured, the router performs a + 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 + 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` 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. + 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 WSGI protocol. +In either case, the result is returned upstream via the :term:`WSGI` +protocol. A Traversal Example ------------------- @@ -209,19 +209,20 @@ error condition. It signifies that: - the "subpath" is ``['biz', 'buz.txt']`` -Because it's the "context", bfg examimes "baz" to find out what "type" +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``). -Using the "view name" ("baz") and the type, it asks the "application -registry" (configured separately, via "configure.zcml") this question: +Using the "view name" ("baz") and the type, it asks the +:term:`application registry` (configured separately, via +``configure.zcml``) this question: - - Please find me a "view" (controller in some religions) with the - name "baz" that can be used for the type ``IBar``. + - Please find me a :term:`view` (aka *controller* in some religions) + 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 a +``NotFound``. The request ends. Everyone is sad. But! For this graph:: @@ -246,7 +247,7 @@ The user asks for ``http://example.com/foo/bar/baz/biz/buz.txt`` - bfg traverses biz, and attemtps to find "buz.txt" which it does not find. -The fact that it does not find "biz.txt" at this point does not +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). @@ -261,16 +262,16 @@ it is. Let's say it finds that the context an ``IBiz`` type (because indicates it's an ``IBiz``). Using the "view name" ("buz.txt") and the type, it asks the -"application registry" (configured separately, in "configure.zcml") -this question: +:term:`application registry` this question: - - Please find me a "view" (controller in some religions) with the - name "buz.txt" that can be used for type ``IBiz``. + - Please find me a :term:`view` (*controller* in some religions) + with the name "buz.txt" that can be used for type ``IBiz``. Let's say that question is answered "here you go, here'a a bit of code -that is willing to deal with that case", and returns a view. It is -passed the "biz" object as the "context" and the current WebOb request -as the "request". It returns a response. +that is willing to deal with that case", and returns a :term:`view`. +It is passed the "biz" object as the "context" and the current +:term:`WebOb` :term:`request` as the "request". It returns a +term:`response`. There are two special cases: diff --git a/docs/tutorials/lxmlgraph/background.rst b/docs/tutorials/lxmlgraph/background.rst index e4fdc5034..aec4cda26 100644 --- a/docs/tutorials/lxmlgraph/background.rst +++ b/docs/tutorials/lxmlgraph/background.rst @@ -1,31 +1,29 @@ Background ==================== -This demo application presumes that you have an interest in XML -technologies and might want to leverage them for a fast, but rich and -dynamic, website. In this demo application, we build up, bit-by-bit, -the functionality. Thus, you don't have to know squatola about XML to -follow along. - -In fact, the real purpose of this demo app is to teach its author how -to use the stack (repoze.bfg, Paster, eggs, etc.) - -In summary: - - - Represent a hierarchical site as hierarchical XML - - - Inject ``repoze.bfg`` semantics into elements using :term:`lxml` - - - Support flexible-but-fast rendering with XSLT +In this demo application, we build up, bit-by-bit, the functionality +for a website based on a single XML document. You don't have to know +much about XML to follow along. In fact, the real purpose of this +demo app is to teach its author how to use the stack +(:mod:`repoze.bfg`, ``paster``, eggs, etc.) .. warning:: If you dislike XML and related technologies such as XPath and XSLT, you'll thoroughly detest this sample application. Just to be - stupendously clear, ``repoze.bfg`` is in no way dependent on XML. - On the other hand, ``repoze.bfg`` happens to make XML publishing + stupendously clear, :mod:`repoze.bfg` is in no way dependent on XML. + On the other hand, :mod:`repoze.bfg` happens to make XML publishing kinda fun. +In summary: + + - Represent a hierarchical website as an XML document + + - Inject :mod:`repoze.bfg` semantics into elements using + :term:`lxml` + + - Support rendering with :term:`XSLT` + What It Does ------------------- @@ -44,7 +42,7 @@ drive. (Unless you're one of those folks that uses your Windows Desktop as a flat filing system.) How might I get that information into a website? -Using ``repoze.bfg``, of course. More specifically, with an XML file +Using :mod:`repoze.bfg`, of course. More specifically, with an XML file that models that hierarchy: .. literalinclude:: step00/simplemodel.xml @@ -53,8 +51,8 @@ that models that hierarchy: How It Works ------------------- -To coerce ``repoze.bfg`` into publishing this model, I just need to -sprinkle in some Python behavior. For example, ``repoze.bfg`` uses +To coerce :mod:`repoze.bfg` into publishing this model, I just need to +sprinkle in some Python behavior. For example, :mod:`repoze.bfg` uses ``__getitem__`` to traverse the model. I need my XML data to support this method. Moreover, I want some specific behavior: run an XPath express on the node to get the child with the ``@name`` attribute @@ -64,11 +62,9 @@ Fortunately :term:`lxml` makes this easy. I can inject my nodes with a class that I write, thus providing my own ``__getitem__`` behavior. That class can also assert that my XML nodes provide an interface. -The interface then lets me glue back into the standard ``repoze.bfg`` +The interface then lets me glue back into the standard :mod:`repoze.bfg` machinery, such as associating views and permissions into the model. -Neato torpedo. And stinking fast. - Next up, I need to provide views for the elements in the model. I could, for example, use ZPT and manipulate the XML data using Python expressions against the :term:`lxml` API. Or, I could use XSLT. @@ -85,28 +81,3 @@ step-by-step, starting with no XML. Each of those decisions will be analyzed an implemented. At the end, you'll see both the resulting demo application, plus the thought process that went along with it. -What It Might Do --------------------- - -This demo application has the potential to show some other interesting -investigations: - -#. **Authorization**. By hooking up support for an ``__acl__`` - property, I can store ACL information on a single node, on an - ancestor, on the ``<site>`` root, on the Python class, or any - combination thereof. Additionally, I can wire up the - ``__parent__`` attribute as a property that makes an :term:`lxml` - ``node.getparent()`` call. - -#. **Multiple views**. Instead of just having a single default view - on a node, I can allow other view names, all pointing at the same - view function and XSLT. I simple grab that name and pass it in as - a paramter to the XSLT, which will run a different rule for - rendering. Adding a view would no longer required editing ZCML and - adding a function. - -#. **Forms**. To edit data in the model, I need to render a form, - then handle post data on the way back in. For the former, it's - *really* easy in XSLT to make a very powerful, flexible, and - extensisible form rendering system. For the latter, I'll have to - learn more about POST handlers in ``repoze.bfg``. diff --git a/docs/tutorials/lxmlgraph/index.rst b/docs/tutorials/lxmlgraph/index.rst index a4d0016cc..cc79f7e73 100644 --- a/docs/tutorials/lxmlgraph/index.rst +++ b/docs/tutorials/lxmlgraph/index.rst @@ -1,10 +1,10 @@ -``lxmlgraph``: Publishing An XML Tree with ``repoze.bfg`` -========================================================== +``lxmlgraph``: Publishing An XML Tree with :mod:`repoze.bfg` +============================================================ -Hierarchical websites are easy to develop with ``repoze.bfg``. That -hierarchy doesn't need to be defined by any particular sort of graph -or databsase system. To demonstrate this, we present -``repoze.lxmlgraph``, a demo application for ``repoze.bfg`` that +Hierarchical websites are easy to develop with :mod:`repoze.bfg`. +That hierarchy doesn't need to be defined by any particular sort of +graph or databsase system. To demonstrate this, we present +``repoze.lxmlgraph``, a demo application for :mod:`repoze.bfg` that describes publishing an XML document as a hierarchical website. .. toctree:: diff --git a/docs/tutorials/lxmlgraph/step01.rst b/docs/tutorials/lxmlgraph/step01.rst index 6c6f93191..578f13608 100644 --- a/docs/tutorials/lxmlgraph/step01.rst +++ b/docs/tutorials/lxmlgraph/step01.rst @@ -3,10 +3,9 @@ Step 1: Getting Started ======================= To get started, using the ``paster`` command from a :term:`virtualenv` -you've created that has ``repoze.bfg`` installed, run ``paster create --t bfg`` as described in :ref:`project_narr` to create your lxmlgraph -project:: - +you've created that has :mod:`repoze.bfg` installed, run ``paster +create -t bfg`` as described in :ref:`project_narr` to create your +``lxmlgraph`` project:: $ paster create -t bfg Selected and implied templates: repoze.bfg#bfg repoze.bfg starter project diff --git a/docs/tutorials/lxmlgraph/step02.rst b/docs/tutorials/lxmlgraph/step02.rst index 94aca07e4..1dc1ebcd3 100644 --- a/docs/tutorials/lxmlgraph/step02.rst +++ b/docs/tutorials/lxmlgraph/step02.rst @@ -6,7 +6,7 @@ We now have a project named ``lxmlgraph``. It contains a *package* (also) named ``lxmlgraph``. In this step we will add an XML document to the *package* as our model -data. We will leverage the following ``repoze.bfg`` machinery: +data. We will leverage the following :mod:`repoze.bfg` machinery: - Model data with interfaces that define "types" @@ -14,11 +14,11 @@ data. We will leverage the following ``repoze.bfg`` machinery: Our application will need to do these things: - - Use :term:`lxml` Element classes to inject ``repoze.bfg`` behavior into - ``lxml`` nodes + - Use :term:`lxml` Element classes to inject :mod:`repoze.bfg` + behavior into ``lxml`` nodes - - That model class needs to implement the ``repoze.bfg`` publishing - contract + - That model class needs to implement the :mod:`repoze.bfg` + publishing contract All of the below filenames are relative to the ``lxmlgraph`` *package* rather than the *project*. @@ -40,18 +40,17 @@ your package: #. In lines 3-4, the ``<site>`` contains 2 top-level children: a and b. These are provided as an element name ``<document>``. This, - also, is meaningless as far as ``repoze.bfg`` is concerned. + also, is meaningless as far as :mod:`repoze.bfg` is concerned. However, this is where you compose the information model you are publishing. The only special constraint is that an XML node that wants to be -"found" by ``repoze.bfg`` in during traversal *must* have a ``name`` -attribute. (The use of ``@name`` corresponds to ``__name__`` in the -``repoze.bfg`` sense of ``repoze.bfg`` :term:`location` ). Each hop -in the URL tries to grab a child with an attribute matching the next -hop. Also, the value of the ``@name`` should be unique in its -containing node. - +"found" by :mod:`repoze.bfg` in during traversal *must* have a +``name`` attribute. (The use of ``@name`` corresponds to ``__name__`` +in the :mod:`repoze.bfg` sense of :term:`location` ). Each hop in the +URL tries to grab a child with an attribute matching the next hop. +Also, the value of the ``@name`` should be unique in its containing +node. Module ``models.py`` ------------------------------ @@ -64,7 +63,7 @@ class with the parser. Replace the contents of the autogenerated .. literalinclude:: step02/myapp/models.py :linenos: -#. Line 4 imports ``lxml``. +#. Line 4 imports :term:`lxml`. #. Line 9 creates the custom class we are going to use to extend etree.ElementBase. The `<lxml website @@ -75,20 +74,20 @@ class with the parser. Replace the contents of the autogenerated certain content type (interface.) In our case, instances will be XML nodes. -#. ``repoze.bfg`` has a "protocol" where model data should have an +#. :mod:`repoze.bfg` has a protocol where model data should have an ``__name__`` attribute. Lines 14-16 implement this by grabbing the ``@name`` attribute of the current node. -#. URL traversal in ``repoze.bfg`` works via the ``__getitem__`` +#. URL traversal in :mod:`repoze.bfg` works via the ``__getitem__`` protocol. Thus, we need a method that implements this. Lines 18-26 use XPath to look for a direct child that has an ``@name`` matching the item name that's being traversed to. If it finds it, return it. If not, or if more than one is found, raise an error. #. As before, ``get_root`` is the function that is expected to return - the top of the model. In lines 30+ we do the ``lxml`` magic to get the - custom Python class registered. We then load some XML and return - the top of the tree. + the top of the model. In lines 30+ we do the :term:`lxml` magic to + get the custom Python class registered. We then load some XML and + return the top of the tree. Module ``views.py`` ----------------------------- @@ -124,7 +123,9 @@ It will listen on port 5432. We can use these URLs to browse the model graph and see results:: http://localhost:5432/a (Hello to document from a @ /a) + http://localhost:5432/b (Hello to document from b @ /b) + http://localhost:5432/c (Not Found) In this case, each request grabs a node in the XML and uses it as the diff --git a/docs/tutorials/lxmlgraph/step03.rst b/docs/tutorials/lxmlgraph/step03.rst index 5e7911889..9edc77af3 100644 --- a/docs/tutorials/lxmlgraph/step03.rst +++ b/docs/tutorials/lxmlgraph/step03.rst @@ -60,8 +60,9 @@ Also add a function in ``views.py`` that looks like the following: This function is relatively simple: -#. Line 1 imports a ``repoze.bfg`` function that renders ZPT templates - to a response. ``repoze.bfg`` uses the ``z3c.pt`` ZPT engine. +#. Line 1 imports a :mod:`repoze.bfg` function that renders ZPT + templates to a response. :mod:`repoze.bfg` uses the ``z3c.pt`` ZPT + engine. #. Line 2, like our other view functions, gets passed a ``context`` (the current hop in the URL) and WebOb ``request`` object. @@ -160,11 +161,12 @@ to your ``views.py`` file: #. Line 10 implements the difference. We call ``render_transform_to_response`` instead of - ``render_template_to_response``. This tells ``repoze.bfg`` to make - an XSLT processor for this template, instead of a ZPT. The second - argument passes in ``context`` to the XSLT transform. ``context``` - is an instance of an Element node. Namely, a node from the XML - document that corresponds to the current hop in the URL. + ``render_template_to_response``. This tells :mod:`repoze.bfg` to + make an XSLT processor for this template, instead of a ZPT. The + second argument passes in ``context`` to the XSLT transform. + ``context``` is an instance of an Element node. Namely, a node + from the XML document that corresponds to the current hop in the + URL. ``xsltview.xsl`` @@ -190,7 +192,6 @@ directory and give it the following contents: #. Line 8 shows the element name of the current node. - Viewing the XSLT -------------------- |
