[Web-SIG] PasteDeploy 0.1

Phillip J. Eby pje at telecommunity.com
Tue Aug 23 02:26:35 CEST 2005

At 12:44 PM 8/22/2005 -0500, Ian Bicking wrote:
>Hmm... it's also just occurred to me that filters should be easier to
>define.  In almost all cases I find I want to curry the configuration so
>it can be applied at the same time the wrapped application is passed in.
>   I might add another protocol for that.

I think the format is improving, as it was now clear enough for me to 
figure out what I'd like to change.  ;-)

I stole this example off your blog, and then rewrote it using a slightly 
more advanced version of my last syntax proposal:

     # Put one login system in front of the entire site
     [login wrapper from Paste]
     database = "mysql://localhost/userdb"
     table    = "users"

     # Then this passes different path prefixes to different apps
     [urlmap from Paste]
     "/"     = static()
     "/cms"  = auth(filebrowser_app())
     "/blog" = blog()

     # variables used later
     [config = vars]
     admin_email = "me at example.com"
     document_root = "/home/me/htdocs"

     # a very simple app...
     [static = static from Paste]
     document_root = config.document_root

     # the login filter should give us a username; this just restricts
     # who can access
     [auth = auth wrapper from Paste]
     require_role = "admin"
     admin_email = config.admin_email

     # this application is distributed in an egg
     [filebrowser_app = filebrowser from FileBrowser]
     document_root = config.document_root
     admin_email = config.admin_email

     # In this case the app isn't distributed as an Egg with
     # entry_points, so we manually create a glue function blog_app
     # and just invoke it here
     [blog = myglue.apps:blog_app]
     admin_email = config.admin_email

Most of the above should be pretty obvious, but a few points anyway:

* This format is generic; it has nothing to do with WSGI in particular and 
can be used to assemble any component tree.  It also supports implementing 
the "wsgi services" concept.

* Argument names can be either an identifier or a quoted string

* You can use factories from a default group (e.g. 'vars' above might 
effectively be short for 'vars from WSGIUtils')

* named sections ("[name = ...]") have to come after the unnamed sections, 
and they are turned into "curried" factory objects that are available in 
the eval() namespace used for all expressions.  When called in an 
expression, they can accept keyword arguments to override the defaults in 
the named section.  They have properties with the same names as the values 
defined in that section.

* The first part of a section (after the "name=", if any) is an import spec 
for a factory, or if it's followed by "from" or "wrapper from", then it's 
the name of an entry point that advertises a factory.

* "wrapper" means that the factory will be called with two positional 
arguments; non-wrappers are called with one argument.  Named wrappers can 
be passed a positional argument if used in an another factory argument 
expression - this will be the object they should wrap.

* The last unnamed section is the effective "result" of parsing the file, 
although it will be wrapped by any contiguous preceding "wrapper" sections

The parser for this format would of course be considerably more complex 
than the Paste-Deploy parser (especially since evaluation would be done 
lazily), but I think the syntax is both cleaner and more powerful.  The 
factory signatures are:

     def non_wrapper_factory(parent_component, **kw):

     def wrapper_factory(child_component, parent_component, **kw):

With the parent/child parameters always being supplied positionally.  The 
idea is that parent_component will be used to create a chain of service 
contexts, and child_component is an application to be wrapped by middleware.

I've thought this through enough that I know how I could implement all of 
the features shown, but it may be a week or two at least before I could try 
hacking together an implementation.  Also, the services side of it isn't 
really fleshed out yet, and it may also be that we need to provide some 
simple "builtin" functions in the eval() namespace to do things like lookup 
services or load other deployment files, etc.

More information about the Web-SIG mailing list