Inconsistency in CGI Documentation????

Sam Penrose sam at ddmweb.com
Tue Aug 21 17:15:40 EDT 2001


[Maan, digging in to the cgi.FieldStorage API, discovers how crufty it
is]

0) You provide the keep_blank_values argument like this:
Test_Form=cgi.FieldStorage(keep_blank_values=1). 

IMO this should have been the default, and I always use it this way.
As has been noted, however, this will not solve all of your problems.

1) If you are going to do significant work with cgi on Python, you will
want to wrap or subclass the cgi.FieldStorage object into something a
little easier to work with. Notably, if cgi.FieldStorage had a get
method, you could just use that when you weren't sure if a key would be
present. Consider this script:

#!/usr/bin/env python
import cgi
class FieldStorageWrapper(cgi.FieldStorage):
    def get(self, key, default=''):
        if self.has_key(key):
            return self[key]
        else:
            return default
        
form = FieldStorageWrapper()
print 'Content-type: text/html\n'
print form.get('foo', 'no foo here')

Call this as a cgi without a 'foo' argument and you will see 'no foo
here'. However, if you call it with 'foo=bar', you'll get:
MiniFieldStorage('foo', 'bar') 
instead of the 'bar' you were looking for, so what you need is your
subclass to read: 

    def get(self, key, default=''):
        if self.has_key(key):
            return self[key].value
        else:
            return default

...but if you have an incoming form with more than one value for a key
here, you'll get an Attribute Error, because self[key] will be not a
MiniFieldStorage object whose contents are in a value attribute but
rather a list of FieldStorage objects whose contents are in *their*
.value attributes rather than something logical like a list of strings.
What you really want to is to get rid of the whole .value thing. This
requires (?) wrapping FieldStorage. Chuck Esterbrook did so for Webware
in a class called HTTPRequest:
<http://webware.sourceforge.net/Webware/WebKit/Docs/Source/Files/HTTPRequest.py.html>
I used that as the basis of my own, much simpler (and cruder) wrapper
class which I am happy to share if anyone wants it. BTW, Webware is a
wonderful project. If you do much Python web programming, you should
check it out for good ideas at a minimum.

2) If you think that all of this is an indictment of the current Python
library, you're right. The BDFL does not seem to agree, however. I spent
considerable time thinking about writing a replacement for the
FieldStorage class, but foundered when I realized how little I knew
about why it used recursive object-birthing to parse MIME headers:

    FieldStorageClass = None
    def read_multi(self, environ, keep_blank_values, strict_parsing):
        """Internal: read a part that is itself multipart."""
        self.list = []
        klass = self.FieldStorageClass or self.__class__
        part = klass(self.fp, {}, self.innerboundary,
                     environ, keep_blank_values, strict_parsing)
        # Throw first part away
        while not part.done:
            headers = rfc822.Message(self.fp)
            part = klass(self.fp, headers, self.innerboundary,
                         environ, keep_blank_values, strict_parsing)
            self.list.append(part)
        self.skip_lines()

If someone can help me get past that, I might take another whack at it.
In particular, I'm not sure whether the recursion is important for
avoiding N^2 worst-case performance, or whether it's just the nifty
kind of thing you do if you are as smart as Guido. Maybe the timbot can
show us how to do it with generators...




More information about the Python-list mailing list