summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-06-11 03:15:15 +0000
committerChris McDonough <chrism@agendaless.com>2009-06-11 03:15:15 +0000
commitdfc2b65c1b6d2f938f68b7868a14d8f9a4faab9e (patch)
treef3241401b7175a401e00286b11e3efe3c21f5093 /docs
parentf8b0065b6ede54424d7a7b49f9f113e87634b5ab (diff)
downloadpyramid-dfc2b65c1b6d2f938f68b7868a14d8f9a4faab9e.tar.gz
pyramid-dfc2b65c1b6d2f938f68b7868a14d8f9a4faab9e.tar.bz2
pyramid-dfc2b65c1b6d2f938f68b7868a14d8f9a4faab9e.zip
Merge unifyroutesandtraversal branch into trunk
Diffstat (limited to 'docs')
-rw-r--r--docs/narr/hooks.rst73
-rw-r--r--docs/narr/project.rst4
-rw-r--r--docs/narr/traversal.rst21
-rw-r--r--docs/narr/urldispatch.rst90
-rw-r--r--docs/narr/urlmapping.rst7
-rw-r--r--docs/tutorials/bfgwiki2/authorization.rst80
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml3
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/models.py8
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py3
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/utilities.py10
10 files changed, 99 insertions, 200 deletions
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 533024352..53d6c8c77 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -7,51 +7,6 @@ ZCML "hooks" can be used to influence the behavior of the
:mod:`repoze.bfg` framework in various ways. This is an advanced
topic; not many people will want or need to do any of these things.
-Changing the request factory
-----------------------------
-
-You may change the class used as the "request factory" from within the
-:mod:`repoze.bfg` ``Router`` class (the ``Router`` class turns the
-WSGI environment into a "request" object which is used ubiquitously
-throughout :mod:`repoze.bfg`). The default "request factory" is the
-class ``webob.Request``. You may change it by placing the following
-ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <utility provides="repoze.bfg.interfaces.IRequestFactory"
- component="helloworld.factories.request_factory"/>
-
-Replace ``helloworld.factories.request_factory`` with the Python
-dotted name to the request factory you want to use. Here's some
-sample code that implements a minimal request factory:
-
-.. code-block:: python
-
- from webob import Request
- from repoze.bfg.interfaces import IRequest
-
- class MyRequest(Request):
- implements(IRequest)
-
- def request_factory():
- return MyRequest
-
-.. warning:: If you register an ``IRequestFactory`` utility in this
- way, you *must* be sure that the factory returns an object that
- implements *at least* the ``repoze.bfg.interfaces.IRequest``
- interface. Otherwise all application view lookups will fail (they
- will all return a 404 response code). Likewise, if you want to be
- able to use method-related interfaces such as ``IGETRequest``,
- ``IPOSTRequest``, etc. in your view declarations, the callable
- returned by the factory must also do the same introspection of the
- environ that the default request factory does and decorate the
- returned object to implement one of these interfaces based on the
- ``HTTP_METHOD`` present in the environ. Note that the above
- example does not do this, so lookups for method-related interfaces
- will fail.
-
Changing the response factory
-----------------------------
@@ -164,31 +119,3 @@ code that implements a minimal forbidden view:
an alterate forbidden view. For example, it would make sense to
return a response with a ``403 Forbidden`` status code.
-.. _changing_routes_context_factory:
-
-Changing the Default Routes Context Factory
--------------------------------------------
-
-The default Routes "context factory" (the object used to create
-context objects when you use ``<route..>`` statements in your ZCML) is
-``repoze.bfg.urldispatch.DefaultRoutesContext``. You may change the
-class used as the Routes "context factory" by placing the following
-ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <utility provides="repoze.bfg.interfaces.IRoutesContextFactory"
- component="helloworld.factories.routes_context_factory"/>
-
-Replace ``helloworld.factories.routes_context_factory`` with the
-Python dotted name to the context factory you want to use. Here's
-some sample code that implements a minimal context factory:
-
-.. code-block:: python
- :linenos:
-
- class RoutesContextFactory(object):
- def __init__(self, **kw):
- self.__dict__.update(kw)
-
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 7fb3604de..3de146e8e 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -92,10 +92,10 @@ application's Python code and templates.
<http://www.sqlalchemy.org/>`_ also exist. Use ``paster create -t
bfg_zodb`` to create a project that depends on ZODB. Use ``paster
create -t bfg_routesalchemy`` to create a project that depends on
- SQLAlchemy and Routes (uses :term:`URL dispatch` instead of
+ SQLAlchemy and Routes (uses only :term:`URL dispatch` and no
:term:`traversal`). Use ``paster create -t bfg_alchemy`` to create
a project that depends on SQLAlchemy but *not* Routes (uses
- :term:`traversal` instead of :term:`URL dispatch`).
+ only :term:`traversal` and no :term:`URL dispatch`).
Installing your Newly Created Project for Development
-----------------------------------------------------
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index 7177432de..4c032952b 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -29,15 +29,18 @@ root object is usually a *mapping* object (such as a Python
dictionary).
.. note:: If a :term:`root factory` is passed to the :mod:`repoze.bfg`
- "make_app" function as the value ``None``, no traversal is
- performed. Instead, it's assumed that all URLs will be mapped to
- code via :term:`URL dispatch`. No root factory, no traversal. It
- is also possible to mix-and-match traversal with URL dispatch.
- When both a root factory (and therefore traversal) *and* "routes"
- declarations (and therefore url dispatch) are used, the url
- dispatch routes are checked first, and if none match,
- :mod:`repoze.bfg` will fall back to using traversal to attempt to
- map the request to a view.
+ "make_app" function as the value ``None``, a default root factory
+ is used. This is most useful when you're using :term:`URL
+ dispatch` and you don't care very much about traversing any
+ particular graph to resolve URLs to code. It is also possible to
+ use traversal and URL dispatch together. When both a root factory
+ (and therefore traversal) *and* "routes" declarations (and
+ therefore url dispatch) are used, the url dispatch routes are
+ checked first, and if none match, :mod:`repoze.bfg` will fall back
+ to using traversal to attempt to map the request to a view. If the
+ name ``*traverse`` is in a route's ``path`` pattern, when it is
+ matched, it is also possible to do traversal *after* a route has
+ been matched. See :ref:`urldispatch_chapter` for more information.
Items contained within the object graph are analogous to the concept
of :term:`model` objects used by many other frameworks (and
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index c7d1e2a38..91063fc26 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -16,8 +16,8 @@ which allows you to declaratively map URLs to code.
neither concept (controller nor action) exists within
:mod:`repoze.bfg`. Instead, when you map a URL pattern to
code in bfg, you will map the URL patterm to a :term:`view`.
- Once the context and view name are found, the view will be
- called with a :term:`context` and a :term:`request`.
+ Once the context and view are found, the view will be called
+ with a :term:`context` and a :term:`request`.
It often makes a lot of sense to use :term:`URL dispatch` instead of
:term:`traversal` in an application that has no natural hierarchy.
@@ -54,17 +54,15 @@ acts as a root factory, it is willing to check the requested URL
against a *routes map* to find a :term:`context` and a :term:`view`
before traversal has a chance to find it first. If a route matches, a
:term:`context` is generated and :mod:`repoze.bfg` will call the
-:term:`view` specified with the context and the request.
-
-If no route matches, :mod:`repoze.bfg` will fail over to calling the
-root factory callable passed to the application in it's ``make_app``
-function (usually a traversal function). By configuring your ZCML
-``route`` statements appropriately, you can mix and match URL dispatch
-and traversal in this way.
+:term:`view` specified with the context and the request. If no route
+matches, :mod:`repoze.bfg` will fail over to calling the :term:`root
+factory` callable passed to the application in it's ``make_app``
+function (usually a traversal function).
A root factory is not required for purely URL-dispatch-based apps: if
-the root factory callable is ``None``, :mod:`repoze.bfg` will return a
-NotFound error to the user's browser when no routes match.
+the root factory callable is passed as ``None`` to the ``make_app``
+function, :mod:`repoze.bfg` will return a NotFound error to the user's
+browser when no routes match.
.. note:: See :ref:`modelspy_project_section` for an example of a
simple root factory callable that will use traversal.
@@ -105,9 +103,8 @@ factory
The Python dotted-path name to a function that will generate a
:mod:`repoze.bfg` context object when this route matches.
- e.g. ``mypackage.models.MyFactoryClass``. By default, a
- ``repoze.bfg.urldispatch.DefaultRoutesContext`` object will be
- constructed if a factory is not provided.
+ e.g. ``mypackage.models.MyFactoryClass``. If this argument is not
+ specified, a default root factory will be used.
encoding
@@ -267,12 +264,12 @@ Example 3
---------
The context object passed to a view found as the result of URL
-dispatch will by default be an instance of the
-``repoze.bfg.urldispatch.DefaultRoutesContext`` object. You can
-override this behavior by passing in a ``factory`` argument to the
-ZCML directive for a particular route. The ``factory`` should be a
-callable that accepts arbitrary keyword arguments and returns an
-instance of a class that will be the context used by the view.
+dispatch will by default be an instance of the object returned by the
+default :term:`root factory`. You can override this behavior by
+passing in a ``factory`` argument to the ZCML directive for a
+particular route. The ``factory`` should be a callable that accepts a
+WSGI environment and returns an instance of a class that will be the
+context used by the view.
An example of using a route with a factory:
@@ -288,13 +285,13 @@ An example of using a route with a factory:
The above route will manufacture an ``Idea`` model as a context,
assuming that ``mypackage.models.Idea`` resolves to a class that
-accepts arbitrary key/value pair arguments.
+accepts a WSGI environment in its ``__init__``.
.. note:: Values prefixed with a period (``.``) for the ``factory``
- and ``provides`` attributes of a ``route`` (such as
- ``.models.Idea`` and ``.views.idea_view``) above) mean "relative to
- the Python package directory in which this :term:`ZCML` file is
- stored". So if the above ``route`` declaration was made inside a
+ and ``view`` attributes of a ``route`` (such as ``.models.Idea``
+ and ``.views.idea_view``) above) mean "relative to the Python
+ package directory in which this :term:`ZCML` file is stored". So
+ if the above ``route`` declaration was made inside a
``configure.zcml`` file that lived in the ``hello`` package, you
could replace the relative ``.models.Idea`` with the absolute
``hello.models.Idea`` Either the relative or absolute form is
@@ -302,14 +299,10 @@ accepts arbitrary key/value pair arguments.
form, in case your package's name changes. It's also shorter to
type.
-All context objects manufactured via URL dispatch will be decorated by
-default with the ``repoze.bfg.interfaces.IRoutesContext``
-:term:`interface`.
-
If no route matches in the above configuration, :mod:`repoze.bfg` will
-call the "fallback" ``get_root`` callable provided to it during
-``make_app`. If the "fallback" ``get_root`` is None, a ``NotFound``
-error will be raised when no route matches.
+call the "fallback" :term:`root factory` callable provided to it
+during ``make_app`. If the "fallback" root factory is None, a
+``NotFound`` error will be raised when no route matches.
.. note:: See :ref:`using_model_interfaces` for more information about
how views are found when interfaces are attached to a
@@ -338,7 +331,10 @@ The ``.models`` module referred to above might look like so:
.. code-block:: python
:linenos:
- class Article(dict):
+ class Article(object):
+ def __init__(self, environ):
+ self.__dict__.update(environ['repoze.bfg.matchdict'])
+
def is_root(self):
return self['article'] == 'root'
@@ -393,8 +389,8 @@ request when a database connection is involved. When
of the traversal :term:`root factory`. Often the root factory will
insert an object into the WSGI environment that performs some cleanup
when its ``__del__`` method is called. When URL dispatch is used,
-however, no root factory is required, so sometimes that option is not
-open to you.
+however, no special root factory is required, so sometimes that option
+is not open to you.
Instead of putting this cleanup logic in the root factory, however,
you can cause a subscriber to be fired when a new request is detected;
@@ -439,32 +435,28 @@ Lists, see :ref:`security_chapter` for more information about the
:mod:`repoze.bfg` authorization subsystem). A common thing to want to
do is to attach an ``__acl__`` to the context object dynamically for
declarative security purposes. You can use the ``factory`` argument
-that points at a context factory which attaches a custom ``__acl__``
-to an object at its creation time.
+that points at a factory which attaches a custom ``__acl__`` to an
+object at its creation time.
Such a ``factory`` might look like so:
.. code-block:: python
:linenos:
- class Article(dict):
- pass
-
- def article_factory(**kw):
- model = Article(**kw)
- article = kw.get('article', None)
- if article == '1':
- model.__acl__ = [ (Allow, 'editor', 'view') ]
- return model
+ class Article(object):
+ def __init__(self, environ):
+ matchdict = environ['bfg.routes.matchdict']
+ article = matchdict.get('article', None)
+ if article == '1':
+ self.__acl__ = [ (Allow, 'editor', 'view') ]
If the route ``archives/:article`` is matched, and the article number
is ``1``, :mod:`repoze.bfg` will generate an ``Article``
:term:`context` with an ACL on it that allows the ``editor`` principal
the ``view`` permission. Obviously you can do more generic things
that inspect the routes match dict to see if the ``article`` argument
-matches a particular string; our sample ``article_factory`` function
-is not very ambitious. Its job could have just as well been done in
-the ``Article`` class' constructor, too.
+matches a particular string; our sample ``Article`` factory class is
+not very ambitious.
.. note:: See :ref:`security_chapter` for more information about
:mod:`repoze.bfg` security and ACLs.
diff --git a/docs/narr/urlmapping.rst b/docs/narr/urlmapping.rst
index 3c74d04d9..21f6235f8 100644
--- a/docs/narr/urlmapping.rst
+++ b/docs/narr/urlmapping.rst
@@ -90,10 +90,3 @@ URL-based dispatch.
:mod:`repoze.bfg` provides support for both approaches. You can use
either as you see fit.
-.. note::
-
- Most existng :mod:`repoze.bfg` applications use :term:`traversal` to
- map URLs to code. This is mostly due to the :term:`Zope` heritage
- of :mod:`repoze.bfg` and because it aids applications that require
- highly granular declarative security assertions.
-
diff --git a/docs/tutorials/bfgwiki2/authorization.rst b/docs/tutorials/bfgwiki2/authorization.rst
index 53d4cfb63..402e42f8d 100644
--- a/docs/tutorials/bfgwiki2/authorization.rst
+++ b/docs/tutorials/bfgwiki2/authorization.rst
@@ -11,54 +11,39 @@ allowing anyone with access to the server to view pages.
*authentication*. We'll make use of both features to provide security
to our application.
-Adding A Context Factory
-------------------------
+Adding A Root Factory
+---------------------
-We're going to start to use a custom *context factory* within our
-``configure.zcml`` file in order to be able to attach security
-declarations to our :term:`context` object. When we do this, we can
-begin to make use of the declarative security features of
-:mod:`repoze.bfg`.
+We're going to start to use a custom *root factory* within our
+``run.py`` file in order to be able to attach security declarations to
+our :term:`context` object. When we do this, we can begin to make use
+of the declarative security features of :mod:`repoze.bfg`.
-Let's modify our ``configure.zcml``, following the instructions in the
-BFG documentation section named
-:ref:`changing_routes_context_factory`. We'll point it at a function
-in a new module we create named ``utilities.py``.
+Let's modify our ``run.py``, passing in a :term:`root factory` as the
+first argument to ``repoze.bfg.router.make_app``. We'll point it at a
+new class we create inside our ``models.py`` file. Add the following
+statements to your ``models.py`` file:
-Add the following section to your application's
-``configure.zcml`` file:
-
-.. code-block:: xml
- :linenos:
-
- <utility provides="repoze.bfg.interfaces.IRoutesContextFactory"
- component=".utilities.RoutesContextFactory"/>
-
-As a result, our ``configure.zcml`` file will now look like so:
-
-.. literalinclude:: src/authorization/tutorial/configure.zcml
- :linenos:
- :language: xml
-
-Once ``configure.zcml`` has been modified, create a file named
-``utilities.py`` and give it the following contents:
-
-.. literalinclude:: src/authorization/tutorial/utilities.py
- :linenos:
- :language: python
+.. code-block:: python
-The result of our changing of the default routes context factory in
-``configure.zcml`` and our addition of a new ``RoutesContextFactory``
-class to ``utilities.py`` allows us to use declarative security
-features of :mod:`repoze.bfg`. The ``RoutesContextFactory`` class we
-added will be used to construct each of the ``context`` objects passed
-to our views. All of our ``context`` objects will possess an
-``__acl__`` attribute that allows "Everyone" (a special principal) to
-view all request, while allowing only a user named ``editor`` to edit
-and add pages. The ``__acl__`` attribute attached to a context is
-interpreted specially by :mod:`repoze.bfg` as an access control list
-during view execution. See :ref:`assigning_acls` for more information
-about what an :term:`ACL` represents.
+ from repoze.bfg.security import Allow
+ from repoze.bfg.security import Everyone
+
+ class RootFactory(object):
+ __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'editor', 'edit') ]
+ def __init__(self, environ):
+ self.__dict__.update(environ['bfg.routes.matchdict'])
+
+Defining a root factory allows us to use declarative security features
+of :mod:`repoze.bfg`. The ``RootFactory`` class we added will be used
+to construct each of the ``context`` objects passed to our views. All
+of our ``context`` objects will possess an ``__acl__`` attribute that
+allows "Everyone" (a special principal) to view all request, while
+allowing only a user named ``editor`` to edit and add pages. The
+``__acl__`` attribute attached to a context is interpreted specially
+by :mod:`repoze.bfg` as an access control list during view execution.
+See :ref:`assigning_acls` for more information about what an
+:term:`ACL` represents.
.. note: Although we don't use the functionality here, the ``factory``
used to create route contexts may differ per-route instead of
@@ -87,8 +72,11 @@ accepts a userid. If the userid exists in the system, the callback
should return a sequence of group identifiers (or an empty sequence if
the user isn't a member of any groups). If the userid *does not*
exist in the system, the callback should return ``None``. We'll use
-"dummy" data to represent user and groups sources. When we're done,
-your application's ``run.py`` will look like this.
+"dummy" data to represent user and groups sources.
+
+We'll also use the opportunity to pass our ``RootFactory`` in as the
+first argument to ``make_app``. When we're done, your application's
+``run.py`` will look like this.
.. literalinclude:: src/authorization/tutorial/run.py
:linenos:
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml b/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
index 8fd6140ab..ff0125f83 100644
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
@@ -49,9 +49,6 @@
permission="edit"
/>
- <utility provides="repoze.bfg.interfaces.IRoutesContextFactory"
- component=".utilities.RoutesContextFactory"/>
-
<utility provides="repoze.bfg.interfaces.IForbiddenView"
component=".login.login"/>
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/models.py b/docs/tutorials/bfgwiki2/src/authorization/tutorial/models.py
index 3e63c3734..283ddea74 100644
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/models.py
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/models.py
@@ -14,6 +14,9 @@ from sqlalchemy.ext.declarative import declarative_base
from zope.sqlalchemy import ZopeTransactionExtension
+from repoze.bfg.security import Allow
+from repoze.bfg.security import Everyone
+
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
@@ -28,6 +31,11 @@ class Page(Base):
self.name = name
self.data = data
+class RootFactory(object):
+ __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'editor', 'edit') ]
+ def __init__(self, environ):
+ self.__dict__.update(environ['bfg.routes.matchdict'])
+
def initialize_sql(db, echo=False):
engine = create_engine(db, echo=echo)
DBSession.configure(bind=engine)
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py b/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
index 0f2068bba..698ba96b9 100644
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
@@ -4,6 +4,7 @@ from repoze.bfg.authentication import AuthTktAuthenticationPolicy
import tutorial
from tutorial.models import DBSession
from tutorial.models import initialize_sql
+from tutorial.models import RootFactory
class Cleanup:
def __init__(self, cleaner):
@@ -27,7 +28,7 @@ def app(global_config, **kw):
authpolicy = AuthTktAuthenticationPolicy('seekr!t', callback=groupfinder)
- return make_app(None, tutorial, authentication_policy=authpolicy,
+ return make_app(RootFactory, tutorial, authentication_policy=authpolicy,
options=kw)
USERS = {'editor':'editor',
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/utilities.py b/docs/tutorials/bfgwiki2/src/authorization/tutorial/utilities.py
deleted file mode 100644
index cc1e0d515..000000000
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/utilities.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from repoze.bfg.security import Allow
-from repoze.bfg.security import Everyone
-
-class RoutesContextFactory(object):
- __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'editor', 'edit') ]
- def __init__(self, **kw):
- self.__dict__.update(kw)
-
-
-