I made a mistake by adding the current generation of "URL-dispatch" behavior to
Currently, repoze.bfg allows you to use Routes to invoke a bfg view with a
manufactured context based on a route match. To do so, you configure a
"repoze.bfg.urldispatch.RoutesMapper" as the bfg "get_root" callable (aka
IRootFactory, lately, at least), and pass it in to bfg's "make_app" at
application construction time. Before you pass it in, you are expected to call
the RoutesMapper's "connect" method with the same arguments you might pass to a
"real" Routes mapper object (see
The BFG RoutesMapper also treats one argument to "connect" specially: a
"context_factory". This argument, if it exists, allows you to tell BFG what
kind of class to create for the manufactured context. If it doesn't exist, BFG
creates a generic RoutesContext object. In either case, the object is decorated
with a single interface: IRoutesContext. Whether it's a custom context
manufactured by a "context_factory" or a default RoutesContext object, the
object obtains only that single interface. The attributes of an instance of the
class are the keys and values in the routes match_dict. You are expected to
make BFG view declarations *against IRoutesContext* with names that match the
"controller" name in the routes match_dict.
Some of this is wrong. Instead of working this way, URL dispatch should replace
traversal to find the context, the view_name, and the subpath based on elements
in a route path, and it should *allow the user to specify the context interface
types* instead of expecting a user to register views against IRoutesContext.
Here's how such a scheme might work: in the case that a context is found by a
route, the context will be manufactured instead of being returned as a result of
traversal through the root graph. Next-gen urldispatch will just find a context
and possibly inform BFG about the "view name" and the "subpath" based on
elements present the Route path (just like the normal ModelGraphTraverser does).
Each route should allow a "context_factory" to be specified as well as a
sequence of "context_interfaces". When a route is matched, a context will be
created using the context factory; its attributes will be all the attributes in
the routes match_dict. It will also be decorated (via alsoProvides) with the
interfaces mentioned as "context_interfaces". Users will make "normal" BFG view
declarations against such interfaces. This will allow you to mix and match
traversal and graph traversal using the same interfaces.
Additionally, instead of requiring a RoutesMapper as an IRootFactory, a next-gen
BFG that allows a context to be found as a result of a Routes route match will
just allow ZCML "route" declarations to be placed in an application's
"configure.zcml". If any of these declarations exist, URL dispatch will be
given "first crack" at resolving a URL; in applications that *only* use URL
dispatch, the get_root callable passed to make_app at app startup can be a
For convenience, if a Routes match_dict contains a ":view_name" key, it will be
passed back to BFG as the BFG view name. Likewise, if it contains a "*subpath"
wildcard match, this will be passed back to BFG as the subpath. These will be
attached by BFG to the request as "subpath" and "view_name". They'll also be
available on the manufactured context, too; this is only a way to make contexts
found through traversal or url dispatch more similar.
Here's an example of some ZCML that would create a Routes route:
For PATH_INFO '/blog/1/edit' The urldispatch "traverser" will pass back a
BlogEntry with the interfaces IBlogEntry and IContent attached to it (another
marker interface IRoutesContext will also be attached, but it's only for
framework consumption). The "view_name" will be passed back as "edit". The
subpath will be empty.
Here's another example:
Here we'll get the same context and view_name for PATH_INFO '/blog/1/edit', but
we'll have a non-empty subpath.
Of course, users will be able to specify a "view_name" and "subpath" argument as
defaults in the route declaration as well, e.g.:
The "repoze.bfg.model_url" API will be changed to inspect if the context is an
IRoutesContext; if so, the Routes url_for API will be used to construct a URL
for Routes-generated contexts. I'm not sure how this will work out.
If I find time to do this, I won't unceremoniously rip out the existing
urldispatch stuff; it will just get deprecated.
In any case, comments welcome.
Repoze-dev mailing list