Great. Given that, I've created the beginnings of a more formal specification:
WSGI Deployment Specification ----------------------------- I use the term "WSGI component" in here as shorthand to indicate all types of WSGI implementations (application, middleware). The primary deployment concern is to create a way to specify the configuration of an instance of a WSGI component within a declarative configuration file. A secondary deployment concern is to create a way to "wire up" components together into a specific deployable "pipeline". Pipeline Descriptors -------------------- Pipeline descriptors are file representations of a particular WSGI "pipeline". They include enough information to configure, instantiate, and wire together WSGI apps and middleware components into one pipeline for use by a WSGI server. Installation of the software which composes those components is handled separately. In order to define a pipeline, we use a ".ini"-format configuration file conventionally named '<something>.wsgi'. This file may optionally be marked as executable and associated with a simple UNIX interpreter via a leading hash-bang line to allow servers which employ stdin and stdout streams (ala CGI) to run the pipeline directly without any intermediation. For example, a deployment descriptor named 'myapplication.wsgi' might be composed of the following text:: #!/usr/bin/runwsgi [mypackage.mymodule.factory1] quux = arbitraryvalue eekx = arbitraryvalue [mypackage.mymodule.factory2] foo = arbitraryvalue bar = arbitraryvalue Section names are Python-dotted-path names (or setuptools "entry point names" described in a later section) which represent factories. Key-value pairs within a given section are used as keyword arguments to the factory that can be used as configuration for the component being instantiated. All sections in the deployment descriptor describe 'middleware' except for the last section, which must describe an application. Factories which construct middleware must return something which is a WSGI "callable" by implementing the following API:: def factory(next_app, [**kw]): """ next_app is the next application in the WSGI pipeline, **kw is optional, and accepts the key-value pairs that are used in the section as a dictionary, used for configuration """ Factories which construct middleware must return something which is a WSGI "callable" by implementing the following API:: def factory([**kw]): """" **kw is optional, and accepts the key-value pairs that are used in the section as a dictionary, used for configuration """ A deployment descriptor can also be parsed from within Python. An importable configurator which resides in 'wsgiref' exposes a function that accepts a single argument, "configure":: >>> from wsgiref.runwsgi import parse_deployment >>> appchain = parse_deployment('myapplication.wsgi') 'appchain' will be an object representing the fully configured "pipeline". 'parse_deployment' is guaranteed to return something that implements the WSGI "callable" API described in PEP 333. Entry Points <description of setuptools entry points goes here> On Mon, 2005-07-25 at 10:39 -0400, Phillip J. Eby wrote: > At 03:02 AM 7/25/2005 -0400, Chris McDonough wrote: > >Actually, let me give this a shot. > > > >We package up an egg called helloworld.egg. It happens to contain > >something that can be used as a WSGI component. Let's say it's a WSGI > >application that always returns 'Hello World'. And let's say it also > >contains middleware that lowercases anything that passes through before > >it's returned. > > > >The implementations of these components could be as follows: > > > >class HelloWorld: > > def __init__(self, app, **kw): > > pass # nothing to configure > > > > def __call__(self, environ, start_response): > > start_response('200 OK', []) > > return ['Hello World'] > > I'm thinking that an application like this wouldn't take an 'app' > constuctor parameter, and if it takes no configuration parameters it > doesn't need **kw, but good so far. > > > >class Lowercaser: > > def __init__(self, app, **kw): > > self.app = app > > # nothing else to configure > > > > def __call__(self, environ, start_response): > > for chunk in self.app(environ, start_response): > > yield chunk.lower() > > Again, no need for **kw if it doesn't take any configuration, but okay. > > > >An import map would ship inside of the egg-info dir: > > > >[wsgi.app_factories] > >helloworld = helloworld:HelloWorld > >lowercaser = helloworld:Lowercaser > > I'm thinking it would be more like: > > [wsgi.middleware] > lowercaser = helloworld:Lowercaser > > [wsgi.apps] > helloworld = helloworld:HelloWorld > > and you'd specify it in the setup script as something like this: > > setup( > #... > entry_points = { > 'wsgi.apps': ['helloworld = helloworld:HelloWorld'] > 'wsgi.middleware': ['lowercaser = helloworld:Lowercaser'] > } > ) > > (And the CVS version of setuptools already supports this.) > > > > >So we install the egg and this does nothing except allow it to be used > >from within Python. > > > >But when we create a "deployment descriptor" like so in a text editor: > > > >[helloworld from helloworld] > > > >[lowercaser from helloworld] > > Opposite order, though; the lowercaser comes first because it's the > middleware; the application would always come last, because they're listed > in the order in which they receive data, just like a pipes-and-filters > command line. > > > >... and run some "starter" script that parses that as a pipeline, > > ... possibly using a #! line if you're using CGI or FastCGI with Apache or > some other non-Python webserver. > > > >creates the two instances, wires them together, and we get a running > >pipeline? > > > >Am I on track? > > Definitely. > _______________________________________________ Web-SIG mailing list Web-SIG@python.org Web SIG: http://www.python.org/sigs/web-sig Unsubscribe: http://mail.python.org/mailman/options/web-sig/archive%40mail-archive.com