[Web-SIG] RE: Comments/stylistic ideas regarding WSGI

angryhicKclown at netscape.net angryhicKclown at netscape.net
Mon Aug 23 16:32:00 CEST 2004

>Date: Mon, 23 Aug 2004 01:52:35 -0400
>From: "Phillip J. Eby" <pje at telecommunity.com>
>Subject: Re: [Web-SIG] Comments/stylistic ideas regarding WSGI
>To: angryhicKclown at netscape.net, web-sig at python.org
>Message-ID: < at mail.telecommunity.com>
>Content-Type: text/plain; charset="us-ascii"; format=flowed
>At 12:44 AM 8/23/04 -0400, angryhicKclown at netscape.net wrote:
>>Now that I understand what WSGI is intended to be used for, I like it a 
>>lot. However, I do have a few suggestions.
>>Although it means more typing, I think the API is too cryptic as-is.
>So, now that you understand the API, you think it's too cryptic.  :)
>All kidding aside, I've made some attempts to make the spec more readable 
>with respect to the various callables, as you'll see in my next draft posting.
>>I think that applications should be callable, but should have a single 
>>parameter: gateway. The gateway parameter contains attributes and methods 
>>such as environ, start_response(), and write(). This way, it's clear to 
>>the end-user both in documentation (removing many instances of "callable" 
>>and confusion with __init__) and also is very much more natural to many 
>I agree that it's more natural, but I disagree that "naturalness" is an 
>important goal for the WSGI spec.  The reason is that most of WSGI's 
>initial audience will be implementing exactly *one* server/gateway and/or 
>application, in order to add support for it to their server or application 
>framework.  They will thus have "spec in hand" when implementing.  It's 
>more important that they be able to easily implement the spec.

I agree, however "a callable that is passed a callable which returns a callable" could be mind-bending for some people.

>The second audience for WSGI will be people creating "middleware" 
>components, and they will appreciate the bare-bones nature of WSGI even 
>more, because they will not need to implement a "gateway" class in order to 
>intercept inputs, outputs, or variables.  Many fairly sophisticated pieces 
>of middleware will be written as a single function (maybe with one or two 
>nested functions).
>Best of all, these functions will be *very* explicit as to what they are 
>modifying, because they will not contain code that's needed to emulate 
>functions they aren't replacing.  Using multi-functional objects like your 
>"gateway" proposal means that middleware components have to implement the 
>full gateway interface.
Not neccessarily. They could extend something like this:

class Gateway(object):
    def __init__(self, parent=None):
        self.parent = parent
    def __getattribute__(self, key):
            return object.__getattribute__(self, key)
        except AttributeError:
            if self.parent != None:
                return getattr(self.parent, key)
    def write(self, data):
        raise NotImplementedError
    # ... more standard API functions here

and instantiate it with the gateway they were passed from the caller.

>>Finally, I think the most important reason this change should be 
>>implemented is because it allows the interface to be easily upgraded 
>>without breaking compatibility with older versions.
>Actually, the current interface includes *numerous* routes for extension, 
>including additional 'wsgi.' keys, and keyword arguments to callables.

I don't see why this can't be solved with OOP.

>>  Perhaps (just an example), in the future, there will be a need for a 
>> flush() method, in addition to the write() method. In the current 
>> version, start_response() would return a tuple of write() and flush(), 
>> which would break current compatibility. The only other way I see of 
>> doing this using the current spec would be passing a default parameter of 
>> the version of the API used, which is ugly.
>It would be simple to add a 'wsgi.flush' key to the environ to supply this 
>functionality, were it needed.  (Of course, flush() isn't actually needed, 
>because WSGI requires write buffers to always be emptied ASAP.)

Fair enough, however I think we're trying to solve a problem (extensions) which has already been solved by inheritance.
>>In my opinion, my proposal looks a bit clearer.
>I agree with you, but as I said, it's not a primary goal.  WSGI will rarely 
>be used directly by an application developer; it's much more likely that 
>you will use some other Python Web API layered atop WSGI.  In other words, 
>the intended audience is developers of servers, frameworks, and 
>middleware.  And most framework and server authors will only code to the 
>spec once, probably with the spec in hand so they can check their 
>compliance.  I think it's better for them to have an absolutely unequivocal 
>spec, that's simple to implement and easy to verify the correctness 
>of.  For example, did you use a dictionary?  That's a trivial yes-or-no 
>thing to check, compared to, e.g., "did I implement a sufficiently 
>dictionary-like object?"

"Did I override the write() method?"

>>My other idea (which follows the previous proposal) is to scrap 
>>start_response() entirely, and instead set gateway.status and 
>>gateway.headers attributes. The simple app would now look like:
>>     def simple_app(gateway):
>>         gateway.status = '200 OK'
>>         gateway.headers = [('Content-type','text/plain')] # perhaps 
>> gateway.set_header('Content-type','text/plain')?
>>         gateway.write('Hello world!\n')
>To properly evaluate your proposal, it's inappropriate to use the 
>application-side code as a basis for comparison.  Compare the *server-side* 
>code, and the code needed to implement various forms of middleware.  You 
>will find that the relatively small gain on the application-side code is 
>*rapidly* counterbalanced by the expanding complexity of servers and 
>middleware.  For example, to implement a middleware component that applies 
>an XSLT stylesheet, you'll need to create a class that implements all the 
>WSGI methods, and delegates the ones it doesn't need to the previous 
>gateway object.  It will also need properties so it can observe the setting 
>of status and headers, and delegate those as well, while tracking what it 

Proposal withdrawn.

>By comparison, the functional architecture of WSGI allows a middleware 
>component to simply pass through to the next component whatever it doesn't 
>need to change.  For example, a middleware component for applying an XSLT 
>stylesheet would only need to define 'start_response' and 'write' 
>replacements, where the 'start_response' simply munged the headers for 
>content type and length, and the 'write' would pump data into the 
>stylesheet mechanism, and call the old write function with any output.
>These changes are clearly connected to the functionality: there is no 
>overhead being added just so the next component downstream gets a more 
>"object-oriented" interface.


>(I'm wondering if I should add any of this to the spec, but it already has 
>a paragraph in the Rationale section saying the API is intentionally 
>no-frills, and another one in the Q&A saying "Why is this interface so 
>low-level?".  I'm not sure how much more I can add without it seeming 
>overdefensive, although I'm sure I'll get ten times as many more "why don't 
>you use an object" protests once this hits c.l.py.  Oh well.)

I'd say you should write a short paragraph under "Questions and Answers" regarding it.

It's a great proposal thus far, I just think it's not as clean as it could be.

Switch to Netscape Internet Service.
As low as $9.95 a month -- Sign up today at http://isp.netscape.com/register

Netscape. Just the Net You Need.

New! Netscape Toolbar for Internet Explorer
Search from anywhere on the Web and block those annoying pop-ups.
Download now at http://channels.netscape.com/ns/search/install.jsp

More information about the Web-SIG mailing list