diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/copyright.rst | 13 | ||||
| -rw-r--r-- | docs/glossary.rst | 3 | ||||
| -rw-r--r-- | docs/index.rst | 2 | ||||
| -rw-r--r-- | docs/latexindex.rst | 2 | ||||
| -rw-r--r-- | docs/narr/firstapp.rst | 2 | ||||
| -rw-r--r-- | docs/narr/muchadoabouttraversal.rst | 312 | ||||
| -rw-r--r-- | docs/narr/resourcelocation.rst | 103 | ||||
| -rw-r--r-- | docs/narr/resources.rst | 36 | ||||
| -rw-r--r-- | docs/narr/router.rst | 2 | ||||
| -rw-r--r-- | docs/narr/security.rst | 3 | ||||
| -rw-r--r-- | docs/narr/traversal.rst | 184 | ||||
| -rw-r--r-- | docs/narr/urldispatch.rst | 41 | ||||
| -rw-r--r-- | docs/narr/views.rst | 10 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/src/views/tutorial/__init__.py | 2 | ||||
| -rw-r--r-- | docs/zcml/handler.rst | 2 |
15 files changed, 469 insertions, 248 deletions
diff --git a/docs/copyright.rst b/docs/copyright.rst index fa564a785..f5f12ad03 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -48,9 +48,15 @@ with respect to the use of the information contained herein. Attributions ------------ +Editor: + Casey Duncan + Contributors: - Ben Bangert, Blaise Laflamme, Carlos de la Guardia, Paul Everitt, - Marius Gedminas + + Ben Bangert, Blaise Laflamme, Rob Miller, Mike Orr, Carlos de la Guardia, + Paul Everitt, Tres Seaver, Marius Gedminas, Chris Rossi, Joachim Krebs, + Xavier Spriet, Reed O'Brien, William Chambers, Charlie Choiniere, Jamaludin + Ahmad. .. Cover Designer: .. Nat Hardwick of `Electrosoup <http://www.electrosoup.co.uk>`_. @@ -59,6 +65,9 @@ Used with permission: The :ref:`webob_chapter` chapter is adapted, with permission, from documentation originally written by Ian Bicking. + The :ref:`much_ado_about_traversal_chapter` chapter is adapted, + with permission, from an article written by Rob Miller. + .. Print Production .. ---------------- diff --git a/docs/glossary.rst b/docs/glossary.rst index 4d0c53d60..ce2d77d8d 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -834,7 +834,7 @@ Glossary :meth:`pyramid.config.Configurator.add_route` and :meth:`pyramid.config.Configurator.add_view` to make it more convenient to register a collection of views as a single class when - using :term:`url dispatch`. See also :ref:`handlers_chapter`. + using :term:`url dispatch`. See also :ref:`views_chapter`. Deployment settings Deployment settings are settings passed to the :term:`Configurator` as a @@ -852,7 +852,6 @@ Glossary http://pypi.python.org/pypi/WebError . view mapper - A view mapper is a class which implements the :class:`pyramid.interfaces.IViewMapperFactory` interface, which performs view argument and return value mapping. This is a plug point for diff --git a/docs/index.rst b/docs/index.rst index d35eb2325..2f3589499 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,8 +38,8 @@ Narrative documentation in chapter form explaining how to use narr/firstapp narr/project narr/startup - narr/resourcelocation narr/urldispatch + narr/muchadoabouttraversal narr/traversal narr/views narr/renderers diff --git a/docs/latexindex.rst b/docs/latexindex.rst index 058835937..9635e6e8a 100644 --- a/docs/latexindex.rst +++ b/docs/latexindex.rst @@ -31,8 +31,8 @@ Narrative Documentation narr/configuration narr/firstapp narr/project - narr/resourcelocation narr/urldispatch + narr/muchadoabouttraversal narr/traversal narr/views narr/renderers diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst index cb1e54b19..1a81134f5 100644 --- a/docs/narr/firstapp.rst +++ b/docs/narr/firstapp.rst @@ -10,7 +10,7 @@ more detail how it works. .. note:: If you're a "theory-first" kind of person, you might choose to read - :ref:`resourcelocation_chapter` and :ref:`views_chapter` before diving into + :ref:`urldispatch_chapter` and :ref:`views_chapter` before diving into the code that follows, but it's not necessary if -- like many programmers -- you're willing to "go with the flow". diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst new file mode 100644 index 000000000..bc1b48462 --- /dev/null +++ b/docs/narr/muchadoabouttraversal.rst @@ -0,0 +1,312 @@ +.. _much_ado_about_traversal_chapter: + +======================== +Much Ado About Traversal +======================== + +.. note:: This chapter was adapted, with permission, from a blog post by `Rob + Miller <http://blog.nonsequitarian.org/>`_, originally published at + `http://blog.nonsequitarian.org/2010/much-ado-about-traversal/ + <http://blog.nonsequitarian.org/2010/much-ado-about-traversal/>`_. + +Traversal is an alternative to :term:`URL dispatch` which allows +:app:`Pyramid` applications to map URLs to code. + +.. note:: + + Ex-Zope users whom are already familiar with traversal and view lookup + conceptually may want to skip directly to the :ref:`traversal_chapter` + chapter, which discusses technical details. This chapter is mostly aimed + at people who have previous :term:`Pylons` experience or experience in + another framework which does not provide traversal, and need an + introduction to the "why" of traversal. + +Some folks who have been using Pylons and its Routes-based URL matching for a +long time are being exposed for the first time, via :app:`Pyramid`, to new +ideas such as ":term:`traversal`" and ":term:`view lookup`" as a way to route +incoming HTTP requests to callable code. Some of the same folks believe that +traversal is hard to understand. Others question its usefulness; URL +matching has worked for them so far, why should they even consider dealing +with another approach, one which doesn't fit their brain and which doesn't +provide any immediately obvious value? + +You can be assured that if you don't want to understand traversal, you don't +have to. You can happily build :app:`Pyramid` applications with only +:term:`URL dispatch`. However, there are some straightforward, real-world +use cases that are much more easily served by a traversal-based approach than +by a pattern-matching mechanism. Even if you haven't yet hit one of these +use cases yourself, understanding these new ideas is worth the effort for any +web developer so you know when you might want to use them. :term:`Traversal` +is actually a straightforward metaphor easily comprehended by anyone who's +ever used a run-of-the-mill file system with folders and files. + +URL Dispatch +------------ + +Let's step back and consider the problem we're trying to solve, which is +simple. An HTTP request for a particular path has been routed to our web +application. The requested path will possibly invoke a specific :term:`view +callable` function defined somewhere in our app. We're trying to determine +*which* callable function, if any, should be invoked for a given requested +URL. + +Many systems, including Pyramid, offer a simple solution. They offer the +concept of "URL matching". URL matching approaches this problem by parsing +the URL path and comparing the results to a set of registered "patterns", +defined by a set of regular expressions, or some other URL path templating +syntax. Each pattern is mapped to a callable function somewhere; if the +request path matches a specific pattern, the associated function is called. +If the request path matches more than one pattern, some conflict resolution +scheme is used, usually a simple order precedence so that the first match +will take priority over any subsequent matches. If a request path doesn't +match any of the defined patterns, :app:`Pyramid` a "404 Not Found" response +is returned. + +In Pyramid, we offer an implementation of URL mapping which we call +:term:`URL dispatch`. Using :app:`Pyramid` syntax, we might have a match +pattern such as ``/{userid}/photos/{photoid}``, mapped to a ``photo_view()`` +function defined somewhere in our code. Then a request for a path such as +``/joeschmoe/photos/photo1`` would be a match, and the ``photo_view()`` +function would be invoked to handle the request. Similarly, +``/{userid}/blog/{year}/{month}/{postid}`` might map to a +``blog_post_view()`` function, so ``/joeschmoe/blog/2010/12/urlmatching`` +would trigger the function, which presumably would know how to find and +render the ``urlmatching`` blog post. + +Historical Refresher +-------------------- + +Now that we've refreshed our understanding of :term:`URL dispatch`, we'll dig +in to the idea of traversal. Before we do, though, let's take a trip down +memory lane. If you've been doing web work for a while, you may remember a +time when we didn't have fancy web frameworks like :term:`Pylons` and +:app:`Pyramid`. Instead, we had general purpose HTTP servers that primarily +served files off of a file system. The "root" of a given site mapped to a +particular folder somewhere on the file system. Each segment of the request +URL path represented a subdirectory. The final path segment would be either +a directory or a file, and once the server found the right file it would +package it up in an HTTP response and send it back to the client. So serving +up a request for ``/joeschmoe/photos/photo1`` literally meant that there was +a ``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which +in turn contained a ``photo1`` file. If at any point along the way we find +that there is not a folder or file matching the requested path, we return a +404 response. + +As the web grew more dynamic, however, a little bit of extra complexity was +added. Technologies such as CGI and HTTP server modules were developed. +Files were still looked up on the file system, but if the file ended with +(for example) ``.cgi`` or ``.php``, or if it lived in a special folder, +instead of simply sending the file to the client the server would read the +file, execute it using an interpreter of some sort, and then send the output +from this process to the client as the final result. The server +configuration specified which files would trigger some dynamic code, with the +default case being to just serve the static file. + +Traversal (aka Resource Location) +--------------------------------- + +.. index:: + single: traversal overview + +Believe it or not, if you understand how serving files from a file system +works,you understand traversal. And if you understand that a server might do +something different based on what type of file a given request specifies, +then you understand view lookup. + +The major difference between file system lookup and traversal is that a file +system lookup steps through nested directories and files in a file system +tree, while traversal steps through nested dictionary-type objects in an +:term:`resource tree`. Let's take a detailed look at one of our example +paths, so we can see what I mean: + +The path ``/joeschmoe/photos/photo1``, has four segments: ``/``, +``joeschmoe``, ``photos`` and ``photo1``. With file system lookup we might +have a root folder (``/``) containing a nested folder (``joeschmoe``), which +contains another nested folder (``photos``), which finally contains a JPG +file ("photo1"). With traversal, we instead have a dictionary-like root +object. Asking for the ``joeschmoe`` key gives us another dictionary-like +object. Asking this in turn for the ``photos`` key gives us yet another +mapping object, which finally (hopefully) contains the resource that we're +looking for within its values, referenced by the ``photo1`` key. + +In pure Python terms, then, the traversal or "resource location" +portion of satisfying the ``/joeschmoe/photos/photo1`` request +will look something like this pseudocode:: + + get_root()['joeschmoe']['photos']['photo1'] + +``get_root()`` is some function that returns a root traversal +:term:`resource`. If all of the specified keys exist, then the returned +object will be the resource that is being requested, analogous to the JPG +file that was retrieved in the file system example. If a :exc:`KeyError` is +generated anywhere along the way, :app:`Pyramid` will return 404. (This +isn't precisely true, as you'll see when we learn about view lookup below, +but the basic idea holds.) + +What Is a "Resource"? +--------------------- + +"Files on a file system I understand", you might say. "But what are these +nested dictionary things? Where do these objects, these 'resources', live? +What *are* they?" + +Since :app:`Pyramid` is not a highly opinionated framework, it makes no +restriction on how a :term:`resource` is implemented; a developer can +implement them as he wishes. One common pattern used is to persist all of +the resources, including the root, in a database as a graph. The root object +is a dictionarylike object. Dictionarylike objects in Python supply a +``__getitem__`` method which is called when key lookup is done. Under the +hood, when ``adict`` is a dictionarylike object, Python translates +``adict['a']`` to ``adict.__getitem__('a')``. Try doing this in a Python +interpreter prompt if you don't believe us: + +.. code-block:: text + :linenos: + + Python 2.4.6 (#2, Apr 29 2010, 00:31:48) + [GCC 4.4.3] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> adict = {} + >>> adict['a'] = 1 + >>> adict['a'] + 1 + >>> adict.__getitem__('a') + 1 + + +The dictionarylike root object stores the ids of all of its subresources as +keys, and provides a ``__getitem__`` implementation that fetches them. So +``get_root()`` fetches the unique root object, while +``get_root()['joeschmoe']`` returns a different object, also stored in the +database, which in turn has its own subresources and ``__getitem__`` +implementation, etc. These resources might be persisted in a relational +database, one of the many "NoSQL" solutions that are becoming popular these +days, or anywhere else, it doesn't matter. As long as the returned objects +provide the dictionary-like API (i.e. as long as they have an appropriately +implemented ``__getitem__`` method) then traversal will work. + +In fact, you don't need a "database" at all. You could trivially implement a +set of objects with ``__getitem__`` methods that search for files in specific +directories, and thus precisely recreate the older mechanism of having the +URL path mapped directly to a folder structure on the file system. Or you +could use plain dictionaries too. Traversal is in fact a superset of file +system lookup. + +.. note:: See the chapter entitled :ref:`resources_chapter` for a more + technical overview of resources. + +View Lookup +----------- + +At this point we're nearly there. We've covered traversal, which is the +process by which a specific resource is retrieved according to a specific URL +path. But what is "view lookup"? + +The need for view lookup is simple: there is more than one possible action +that you might want to take after finding a :term:`resource`. With our photo +example, for instance, you might want to view the photo in a page, but you +might also want to provide a way for the user to edit the photo and any +associated metadata. We'll call the former the ``view`` view, and the latter +will be the ``edit`` view (Original, I know.) :app:`Pyramid` has a +centralized view registry where named views can be associated with specific +resource types. So in our example, we'll assume that we've registered +``view`` and ``edit`` views for photo objects, and that we've specified the +``view`` view as the default, so that ``/joeschmoe/photos/photo1/view`` and +``/joeschmoe/photos/photo1`` are equivalent. The edit view would sensibly be +provided by a request for ``/joeschmoe/photos/photo1/edit``. + +Hopefully it's clear that the first portion of the edit view's URL path is +going to resolve to the same resource as the non-edit version, specifically +the resource returned by ``get_root()['joeschmoe']['photos']['photo1']``. +But traveral ends there; the ``photo1`` resource doesn't have an ``edit`` +key. In fact, it might not even be a dictionary-like object, in which case +``photo1['edit']`` would be meaningless. When the :app:`Pyramid` resource +location has been resolved to a *leaf* resource, but the entire request path +has not yet been expended, the *very next* path segment is treated as a +:term:`view name`. The registry is then checked to see if a view of the +given name has been specified for a resource of the given type. If so, the +view callable is invoked, with the resource passed in as the related +``context`` object (also available as ``request.context``). If a view +callable could not be found, :app:`Pyramid` will return a "404 Not Found" +response. + +You might conceptualize a request for ``/joeschmoe/photos/photo1/edit`` as +ultimately converted into the following piece of Pythonic pseudocode:: + + context = get_root()['joeschmoe']['photos']['photo1'] + view_callable = get_view(context, 'edit') + request.context = context + view_callable(request) + +The ``get_root`` and ``get_view`` functions don't really exist. Internally, +:app:`Pyramid` does something more complicated. But the example above is a +reasonable approximation of the view lookup algorithm in pseudocode. + +Use Cases +--------- + +Why should we care about traversal? URL matching is easier to explain, and +it's good enough, right? + +In some cases, yes, but certainly not in all cases. So far we've had very +structured URLs, where our paths have had a specific, small number of pieces, +like this:: + + /{userid}/{typename}/{objectid}[/{view_name}] + +In all of the examples thus far, we've hard coded the typename value, +assuming that we'd know at development time what names were going to be used +("photos", "blog", etc.). But what if we don't know what these names will +be? Or, worse yet, what if we don't know *anything* about the structure of +the URLs inside a user's folder? We could be writing a CMS where we want the +end user to be able to arbitrarily add content and other folders inside his +folder. He might decide to nest folders dozens of layers deep. How will you +construct matching patterns that could account for every possible combination +of paths that might develop? + +It's possible, but it will make for some somewhat ugly URLs. And the +matching patterns are going to become complex quickly as you try to handle +all of the edge cases. + +With traversal, however, it's straightforward. If you want 20 layers of +nesting, it's no problem. :app:`Pyramid` will happily call ``__getitem__`` +as many times as it needs to, until it runs out of path segments or until a +resource raises a :exc:`KeyError`. Each resource only needs to know how to +fetch its immediate children, the traversal algorithm takes care of the rest. + +One of the key advantages of traversal is that the structure of the resource +tree can live in the database, and not in the code. It's simple to let users +modify the tree at runtime to set up their own personalized directory +structures. + +Another use case in which traversal shines is when there is a need to support +a context-dependent security policy. One example might be a document +management infrastructure for a large corporation, where members of different +departments have varying access levels to the various other departments' +files. Reasonably, even specific files might need to be made available to +specific individuals. Traversal does well here if your resources actually +represent the data objects related to your documents, because the idea of a +resource authorization is baked right into the code resolution and calling +process. Resource objects can store ACLs, which can be inherited and/or +overridden by the subresources. + +If each resource can thus generate a context-based ACL, then whenever view +code is attempting to perform a sensitive action, it can check against that +ACL to see whether the current user should be allowed to perform the action. +In this way you achieve so called "instance based" or "row level" security +which is considerably harder to model using a traditional tabular approach. +:app:`Pyramid` actively supports such a scheme, and in fact if you register +your views with guard permissions and use an authorization policy, +:app:`Pyramid` can check against a resource's ACL when deciding whether or +not the view itself is available to the current user. + +In summary, there are entire classes of problems that are more easily served +by traversal and view lookup than by :term:`URL dispatch`. If your problems +don't require it, great: stick with :term:`URL dispatch`. But if you're +using :app:`Pyramid` and you ever find that you *do* need to support one of +these use cases, you'll be glad you have traversal in your toolkit. + +.. note:: + It is even possible to mix and match :term:`traversal` with + :term:`URL dispatch` in the same :app:`Pyramid` application. See the + :ref:`hybrid_chapter` chapter for details. diff --git a/docs/narr/resourcelocation.rst b/docs/narr/resourcelocation.rst deleted file mode 100644 index 8ddc890ed..000000000 --- a/docs/narr/resourcelocation.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. index:: - single: resource location - -.. _resourcelocation_chapter: - -Resource Location and View Lookup ---------------------------------- - -:app:`Pyramid` uses two separate but cooperating subsystems to find and -invoke :term:`view callable` code written by the application developer: -:term:`resource location` and :term:`view lookup`. - -- First, a :app:`Pyramid` :term:`resource location` subsystem is given a - :term:`request`; it is responsible for finding a :term:`resource` object - based on information present in the request. When a resource is found via - resource location, it becomes known as the :term:`context`. - -- Next, using the context resource found by :term:`resource location` and the - :term:`request`, :term:`view lookup` is then responsible for finding and - invoking a :term:`view callable`. A view callable is a specific bit of - code written and registered by the application developer which receives the - :term:`request` and which returns a :term:`response`. - -These two subsystems are used by :app:`Pyramid` serially: first, a -:term:`resource location` subsystem does its job. Then the result of -resource location is passed to the :term:`view lookup` subsystem. The view -lookup system finds a :term:`view callable` written by an application -developer, and invokes it. A view callable returns a :term:`response`. The -response is returned to the requesting user. - -There are two separate :term:`resource location` subsystems in -:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. They can be used -separately or they can be combined. Three chapters which follow describe -:term:`resource location`: :ref:`traversal_chapter`, -:ref:`urldispatch_chapter` and :ref:`hybrid_chapter`. - -There is only one :term:`view lookup` subsystem present in :app:`Pyramid`. -Where appropriate, we will describe how view lookup interacts with context -finding. One chapter which follows describes :term:`view lookup`: -:ref:`views_chapter`. - -Should I Use Traversal or URL Dispatch for Resource Location? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When you use :app:`Pyramid`, you have a choice about how you'd like to -resolve URLs to code: you can use either :term:`traversal` or :term:`URL -dispatch`. The choice to use traversal vs. URL dispatch is largely -"religious". Since :app:`Pyramid` provides support for both approaches, you -can use either exclusively or combine them as you see fit. - -:term:`URL dispatch` is very straightforward. When you limit your -application to using URL dispatch, you know every URL that your application -might generate or respond to, all the URL matching elements are listed in a -single place, and you needn't think about :term:`resource location` or -:term:`view lookup` at all. - -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 single member in some system. -You just match everything "below" ``members`` to a particular :term:`view -callable`, e.g. ``/members/{memberid}``. - -However, URL dispatch is not very convenient if you'd like your URLs to -represent an arbitrary-depth hierarchy. For example, if you need to infer -the difference between sets of URLs such as these, where the ``document`` in -the first URL represents a PDF document, and ``/stuff/page`` in the second -represents an OpenOffice document in a "stuff" folder. - -.. code-block:: text - - http://example.com/members/Chris/document - http://example.com/members/Chris/stuff/page - -It takes more pattern matching assertions to be able to make hierarchies work -in URL-dispatch based systems, and some assertions just aren't possible. -URL-dispatch based systems just don't deal very well with URLs that represent -arbitrary-depth hierarchies. - -:term:`URL dispatch` tends to collapse the two steps of :term:`resource -location` and :term:`view lookup` into a single step. Thus, a URL can map -*directly* to a view callable. This makes URL dispatch easier to understand -than traversal, because traversal makes you understand how :term:`resource -location` works. But explicitly locating a resource provides extra -flexibility. For example, it makes it possible to protect your application -with declarative context-sensitive instance-level :term:`authorization`. - -Unlike URL dispatch, :term:`traversal` works well for URLs that represent -arbitrary-depth hierarchies. Since the path segments that compose a URL are -addressed separately, it becomes very easy to form URLs that represent -arbitrary depth hierarchies in a system that uses traversal. When you're -willing to treat your application resources as a tree that can be traversed, -it also becomes easy to provide "instance-level security": you just attach an -:term:`ACL` security declaration to each resource in the tree. This is not -nearly as easy to do when using URL dispatch. - -Traversal probably just doesn't make any sense when you possess completely -"square" data stored in a relational database because it requires the -construction and maintenance of a resource tree and requires that the -developer think about mapping URLs to code in terms of traversing that tree. - -We'll examine both :term:`URL dispatch` and :term:`traversal` in the next two -chapters. - diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst index 8cf2cead2..cf13f8c8d 100644 --- a/docs/narr/resources.rst +++ b/docs/narr/resources.rst @@ -1,21 +1,23 @@ +.. _resources_chapter: + Resources ========= -A :term:`resource` is an object that represents a "place" in a tree related -to your application. Every :app:`Pyramid` application has at least one -resource object: the :term:`root` resource (even if you don't define one -manually, a default root resource is created for you). The root resource is -the root of a :term:`resource tree`. A resource tree is a set of nested -dictionary-like objects which you can use to represent your website's -structure. +A :term:`resource` is an object that represents a "place" in a tree +related to your application. Every :app:`Pyramid` application has at +least one resource object: the :term:`root` resource. Even if you don't +define a root resource manually, a default one is created for you. The +root resource is the root of a :term:`resource tree`. A resource tree +is a set of nested dictionary-like objects which you can use to +represent your website's structure. In an application which uses :term:`traversal` to map URLs to code, the -resource tree structure is used heavily to map a URL to a :term:`view -callable`. :app:`Pyramid` will walk "up" the resource tree by traversing -through the nested dictionary structure of the tree when :term:`traversal` is -used in order to find a :term:`context` resource. Once a context resource is -found, the context resource and data in the request will be used to find a -:term:`view callable`. +resource tree structure is used heavily to map each URL to a :term:`view +callable`. When :term:`traversal` is used, :app:`Pyramid` will walk +through the resource tree by traversing through its nested dictionary +structure in order to find a :term:`context` resource. Once a context +resource is found, the context resource and data in the request will be +used to find a :term:`view callable`. In an application which uses :term:`URL dispatch`, the resource tree is only used indirectly, and is often "invisible" to the developer. In URL dispatch @@ -26,7 +28,7 @@ much less important in applications that use URL dispatch than applications that use traversal. In "Zope-like" :app:`Pyramid` applications, resource objects also often store -data persistently and offer methods related to mutating that persistent data. +data persistently, and offer methods related to mutating that persistent data. In these kinds of applications, resources not only represent the site structure of your website, but they become the :term:`domain model` of the application. @@ -72,8 +74,8 @@ tree: the container's ``__getitem__`` should return the sub-resource. - Leaf resources, which do not contain other resources, must not implement a - ``__getitem__``, or if they do, their ``__getitem__`` method must raise a - :exc:`KeyError`. + ``__getitem__``, or if they do, their ``__getitem__`` method must always + raise a :exc:`KeyError`. See :ref:`traversal_chapter` for more information about how traversal works against resource instances. @@ -239,7 +241,7 @@ A slash is appended to all resource URLs when :func:`~pyramid.url.resource_url` is used to generate them in this simple manner, because resources are "places" in the hierarchy, and URLs are meant to be clicked on to be visited. Relative URLs that you include on HTML pages -rendered as the result of the default view of a resource are typically more +rendered as the result of the default view of a resource are more apt to be relative to these resources than relative to their parent. You can also pass extra elements to :func:`~pyramid.url.resource_url`: diff --git a/docs/narr/router.rst b/docs/narr/router.rst index d3d5bd370..f9e98373c 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -133,6 +133,6 @@ processing? This is a very high-level overview that leaves out various details. For more detail about subsystems invoked by the :app:`Pyramid` router such as traversal, URL dispatch, views, and event processing, see -:ref:`resourcelocation_chapter`, :ref:`views_chapter`, and +:ref:`urldispatch_chapter`, :ref:`views_chapter`, and :ref:`events_chapter`. diff --git a/docs/narr/security.rst b/docs/narr/security.rst index c5262faa2..62a4727bc 100644 --- a/docs/narr/security.rst +++ b/docs/narr/security.rst @@ -18,8 +18,7 @@ works at a high level: :term:`resource location`. A context is located differently depending on whether the application uses :term:`traversal` or :term:`URL dispatch`, but a context is ultimately found in either case. See - :ref:`resourcelocation_chapter` for more information about resource - location. + the :ref:`urldispatch_chapter` chapter for more information. - A :term:`view callable` is located by :term:`view lookup` using the context as well as other attributes of the request. diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 2d7878265..0b0bb1d3e 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -3,33 +3,22 @@ Traversal ========= -:term:`Traversal` provides an alternative to using :term:`URL dispatch` to -map a URL to a :term:`view callable`. It is the act of locating a -:term:`context` resource by walking over a :term:`resource tree`, starting -from a :term:`root` resource, using a :term:`request` object as a source of -path information. Once a context resource is found, a view callable is -looked up and invoked. - -Using :term:`Traversal` to map a URL to code is optional. It is often less -easy to understand than URL dispatch, so if you're a rank beginner, it -probably makes sense to use URL dispatch to map URLs to code instead of -traversal. In that case, you can skip this chapter. - -.. index:: - single: traversal overview - -A High-Level Overview of Traversal ----------------------------------- - A :term:`traversal` uses the URL (Universal Resource Locator) to find a -:term:`resource`. This is done by mapping each segment of the path portion -of the URL into a set of nested dictionary-like objects called the -:term:`resource tree`. You might think of this as looking up files and -directories in a file system. Traversal walks down the path until it finds a -published "directory" or "file". The resource we find as the result of a -traversal becomes the :term:`context`. A separate :term:`view lookup` -subsystem is used to then find some view code willing "publish" the context -resource. +:term:`resource` located in a :term:`resource tree`, which is a set of +nested dictionary-like objects. Traversal is done by using each segment +of the path portion of the URL to navigate through the :term:`resource +tree`. You might think of this as looking up files and directories in a +file system. Traversal walks down the path until it finds a published +resource, analogous to a file system "directory" or "file". The +resource found as the result of a traversal becomes the +:term:`context` of the :term:`request`. Then, the :term:`view lookup` +subsystem is used to find some view code willing "publish" this +resource by generating a :term:`response`. + +Using :term:`Traversal` to map a URL to code is optional. It is often +less easy to understand than :term:`URL dispatch`, so if you're a rank +beginner, it probably makes sense to use URL dispatch to map URLs to +code instead of traversal. In that case, you can skip this chapter. .. index:: single: traversal details @@ -37,62 +26,65 @@ resource. Traversal Details ----------------- -:term:`Traversal` is dependent on information in a :term:`request` object. -Every :term:`request` object contains URL path information in the -``PATH_INFO`` portion of the :term:`WSGI` environment. The ``PATH_INFO`` -portion of the WSGI environment is the portion of a request's URL following -the hostname and port number, but before any query string elements or +:term:`Traversal` is dependent on information in a :term:`request` +object. Every :term:`request` object contains URL path information in +the ``PATH_INFO`` portion of the :term:`WSGI` environment. The +``PATH_INFO`` string is the portion of a request's URL following the +hostname and port number, but before any query string elements or fragment element. For example the ``PATH_INFO`` portion of the URL ``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``. -Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of path -segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is converted to -the sequence ``['a', 'b', 'c']``. +Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of +path segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is +converted to the sequence ``['a', 'b', 'c']``. -After the path info is converted, a lookup is performed against the resource -tree for each path segment. Each lookup uses the ``__getitem__`` method of a -resource in the tree. +This path sequence is then used to descend through the :term:`resource +tree`, looking up a resource for each path segment. Each lookup uses the +``__getitem__`` method of a resource in the tree. For example, if the path info sequence is ``['a', 'b', 'c']``: -- :term:`Traversal` pops the first element (``a``) from the path segment - sequence and attempts to call the root resource's ``__getitem__`` method - using that value (``a``) as an argument; we'll presume it succeeds. +- :term:`Traversal` starts by acquiring the :term:`root` resource of the + application by calling the :term:`root factory`. The :term:`root factory` + can be configured to return whatever object is appropriate as the + traversal root of your application. + +- Next, the first element (``a``) is popped from the path segment + sequence and is used as a key to lookup the corresponding resource + in the root. This invokes the root resource's ``__getitem__`` method + using that value (``a``) as an argument. -- When the root resource's ``__getitem__`` succeeds it will return another - resource, which we'll call "A". The :term:`context` temporarily becomes - the "A" resource. +- If the root resource "contains" a resource with key ``a``, its + ``__getitem__`` method will return it. The :term:`context` temporarily + becomes the "A" resource. - The next segment (``b``) is popped from the path sequence, and the "A" resource's ``__getitem__`` is called with that value (``b``) as an argument; we'll presume it succeeds. -- When the "A" resource's ``__getitem__`` succeeds it will return another - resource, which we'll call "B". The :term:`context` temporarily becomes - the "B" resource. - -This process continues until the path segment sequence is exhausted or a path -element cannot be resolved to a resource. In either case, a :term:`context` -resource is chosen. - -Traversal "stops" when it either reaches a leaf level resource in your -resource tree or when the path segments implied by the URL "run out". The -resource that traversal "stops on" becomes the :term:`context`. If at any -point during traversal any resource in the tree doesn't have a -``__getitem__`` method, or if the ``__getitem__`` method of a resource raises -a :exc:`KeyError`, traversal ends immediately, and that resource becomes the -:term:`context`. - -The results of a :term:`traversal` also include a :term:`view name`. The -:term:`view name` is the *first* URL path segment in the set of ``PATH_INFO`` -segments "left over" in the path segment list popped by the traversal process -*after* traversal finds a context resource. - -The combination of the context resource and the :term:`view name` found via -traversal is used later in the same request by a separate :app:`Pyramid` -subsystem -- the :term:`view lookup` subsystem -- to find a :term:`view -callable` later within the same request. How :app:`Pyramid` performs view -lookup is explained within the :ref:`views_chapter` chapter. +- The "A" resource's ``__getitem__`` returns another resource, which + we'll call "B". The :term:`context` temporarily becomes the "B" + resource. + +Traversal continues until the path segment sequence is exhausted or a +path element cannot be resolved to a resource. In either case, the +:term:`context` resource is the last object that the traversal +successfully resolved. If any resource found during traversal lacks a +``__getitem__`` method, or if its ``__getitem__`` method raises a +:exc:`KeyError`, traversal ends immediately, and that resource becomes +the :term:`context`. + +The results of a :term:`traversal` also include a :term:`view name`. If +traversal ends before the path segment sequence is exhausted, the +:term:`view name` is the *next* remaining path segment element. If the +:term:`traversal` expends all of the path segments, then the :term:`view +name` is the empty string (`''`). + +The combination of the context resource and the :term:`view name` found +via traversal is used later in the same request by the :term:`view +lookup` subsystem to find a :term:`view callable`. How :app:`Pyramid` +performs view lookup is explained within the :ref:`views_chapter` +chapter. .. index:: single: object tree @@ -104,19 +96,20 @@ lookup is explained within the :ref:`views_chapter` chapter. The Resource Tree ----------------- -When your application uses :term:`traversal` to resolve URLs to code, the -application must supply a :term:`resource tree` to :app:`Pyramid`. The -resource tree is a set of nested dictionary-like objects. The root of the -tree is represented by a :term:`root` resource. The tree is effectively a -nested set of dictionary-like objects. +The resource tree is a set of nested dictionary-like resource objects +that begins with a :term:`root` resource. In order to use +:term:`traversal` to resolve URLs to code, your application must supply +a :term:`resource tree` to :app:`Pyramid`. -In order to supply a root resource for an application, at system startup -time, the :app:`Pyramid` :term:`Router` is configured with a callback known -as a :term:`root factory`. The root factory is supplied by the application -developer as the ``root_factory`` argument to the application's -:term:`Configurator`. +In order to supply a root resource for an application the :app:`Pyramid` +:term:`Router` is configured with a callback known as a :term:`root +factory`. The root factory is supplied by the application, at startup +time, as the ``root_factory`` argument to the :term:`Configurator`. -Here's an example of a simple root factory: +The root factory is a Python callable that accepts a :term:`request` +object, and returns the root object of the :term:`resource tree`. A +function, or class is typically used as an application's root factory. +Here's an example of a simple root factory class: .. code-block:: python :linenos: @@ -133,24 +126,23 @@ passing it to an instance of a :term:`Configurator` named ``config``: config = Configurator(root_factory=Root) -Using the ``root_factory`` argument to a :class:`pyramid.config.Configurator` -constructor tells your :app:`Pyramid` application to call this root factory -to generate a root resource whenever a request enters the application. This -root factory is also known as the global root factory. A root factory can -alternately be passed to the ``Configurator`` as a :term:`dotted Python name` -which refers to a root factory defined in a different module. - -A root factory is passed a :term:`request` object and it is expected to -return an object which represents the root of the resource tree. All -:term:`traversal` will begin at this root resource. Usually a root factory -for a traversal-based application will be more complicated than the above -``Root`` class; in particular it may be associated with a database connection -or another persistence mechanism. +The ``root_factory`` argument to the +:class:`pyramid.config.Configurator` constructor registers this root +factory to be called to generate a root resource whenever a request +enters the application. The root factory registered this way is also +known as the global root factory. A root factory can alternately be +passed to the ``Configurator`` as a :term:`dotted Python name` which can +refer to a root factory defined in a different module. If no :term:`root factory` is passed to the :app:`Pyramid` -:term:`Configurator` constructor, or the ``root_factory`` is specified as the -value ``None``, a *default* root factory is used. The default root factory -always returns a resource that has no child resources. +:term:`Configurator` constructor, or if the ``root_factory`` value +specified is ``None``, a *default* root factory is used. The default +root factory always returns a resource that has no child resources; it +is effectively empty. + +Usually a root factory for a traversal-based application will be more +complicated than the above ``Root`` class; in particular it may be +associated with a database connection or another persistence mechanism. .. sidebar:: Emulating the Default Root Factory diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 0d28a0e96..c0b132a04 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -6,16 +6,28 @@ URL Dispatch ============ -:term:`URL dispatch` provides a simple way to map URLs :term:`view` code -using a simple pattern matching language. An ordered set of patterns is -checked one-by-one. If one of the patterns matches the path information -associated with a request, a particular :term:`view callable` is invoked. If -no route matches, :app:`Pyramid` falls back to trying to use -:term:`traversal` to map the current request to a :term:`view callable`. - -The presence of calls to the :meth:`pyramid.config.Configurator.add_route` -method within your application is a sign that you're using :term:`URL -dispatch`. +:term:`URL dispatch` provides a simple way to map URLs to :term:`view` +code using a simple pattern matching language. An ordered set of +patterns is checked one-by-one. If one of the patterns matches the path +information associated with a request, a particular :term:`view +callable` is invoked. + +:term:`URL dispatch` is one of two ways to perform :term:`resource +location` in :app:`Pyramid`; the other way is using :term:`traversal`. +If no route is matched using :term:`URL dispatch`, :app:`Pyramid` falls +back to :term:`traversal` to handle the :term:`request`. + +It is the responsibility of the :term:`resource location` subsystem +(i.e., :term:`URL dispatch` or :term:`traversal`) to find the resource +object that is the :term:`context` of the :term:`request`. Once the +:term:`context` is determined, :term:`view lookup` is then responsible +for finding and invoking a :term:`view callable`. A view callable is a +specific bit of code, defined in your application, that receives the +:term:`request` and returns a :term:`response` object. + +Where appropriate, we will describe how view lookup interacts with +:term:`resource location`. The :ref:`views_chapter` chapter describes +the details of :term:`view lookup`. High-Level Operational Overview ------------------------------- @@ -24,10 +36,9 @@ If route configuration is present in an application, the :app:`Pyramid` :term:`Router` checks every incoming request against an ordered set of URL matching patterns present in a *route map*. -If any route pattern matches the information in the :term:`request` provided -to :app:`Pyramid`, :app:`Pyramid` will shortcut :term:`traversal`, and will -invoke :term:`view lookup` using a :term:`context` resource generated by the -route match. +If any route pattern matches the information in the :term:`request`, +:app:`Pyramid` will invoke :term:`view lookup` using a :term:`context` +resource generated by the route match. However, if no route pattern matches the information in the :term:`request` provided to :app:`Pyramid`, it will fail over to using :term:`traversal` to @@ -72,7 +83,7 @@ example: .. versionchanged:: 1.0a4 Prior to 1.0a4, routes allow for a marker starting with a ``:``, for - example ``/prefix/:one/:two``. Starting in 1.0a4, this style is deprecated + example ``/prefix/:one/:two``. This style is now deprecated in favor or ``{}`` usage which allows for additional functionality. .. index:: diff --git a/docs/narr/views.rst b/docs/narr/views.rst index ad28e48d4..81f3e644f 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -17,11 +17,11 @@ request made to your application. that implements a view *callable*, and the process of view *lookup*. -The chapter :ref:`resourcelocation_chapter` describes how, using information -from the :term:`request`, a :term:`context` resource is computed. But the -context resource itself isn't very useful without an associated :term:`view -callable`. A view callable returns a response to a user, often using the -context resource to do so. +The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` describes how, +using information from the :term:`request`, a :term:`context` resource is +computed. But the context resource itself isn't very useful without an +associated :term:`view callable`. A view callable returns a response to a +user, often using the context resource to do so. The job of actually locating and invoking the "best" :term:`view callable` is the job of the :term:`view lookup` subsystem. The view lookup subsystem diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py index 334fde814..1a8d24499 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py @@ -10,7 +10,7 @@ def main(global_config, **settings): initialize_sql(engine) config = Configurator(settings=settings) config.add_static_view('static', 'tutorial:static') - config.add_route('home', '/', view='tutorial.views.view_wiki') + config.add_route('view_wiki', '/', view='tutorial.views.view_wiki') config.add_route('view_page', '/{pagename}', view='tutorial.views.view_page', view_renderer='tutorial:templates/view.pt') diff --git a/docs/zcml/handler.rst b/docs/zcml/handler.rst index 01d442ab6..64aac7e78 100644 --- a/docs/zcml/handler.rst +++ b/docs/zcml/handler.rst @@ -155,4 +155,4 @@ You can also add a :term:`route configuration` via: See Also ~~~~~~~~ -See also :ref:`handlers_chapter`. +See also :ref:`views_chapter`. |
