PEP: 222 Title: Web Library Enhancements Version: $Revision$ Author: akuchlin@mems-exchange.org (Andrew Kuchling) Status: Active Type: Standards Track Python-Version: 2.1 Created: 18-Aug-2000 Post-History: Abstract This PEP proposes a set of enhancements to the CGI development facilities in the Python standard library. Enhancements might be new features, new modules for tasks such as cookie support, or removal of obsolete code. The intent is to incorporate the proposals emerging from this document into Python 2.1, due to be released in the first half of 2001. Proposed Changes This section lists changes that have been suggested, but about which no firm decision has yet been made. In the final version of this PEP, this section should be empty, as all the changes should be classified as accepted or rejected. fcgi.py : A new module adding support for the FastCGI protocol Better debugging support for CGIs from the Unix command line. Using Perl's CGI.pm [1], if you run a script from the command line, you can enter name=value pairs on standard input. cgimodel [2] provides this already. Should the existing cgi.py be deprecated and everything moved into a 'web' or 'cgi' package? That would allow removing some backward-compatibility cruft. cgi.py: keep_blank_values should be on by default. The 'if form.has_key()/if form[key].value' nested syntax is unnecessarily convoluted. cgi.py: We should not be told to create our own subclass just so we can handle file uploads. As a practical matter, I have yet to find the time to do this right, so I end up reading cgi.py's temp file into, at best, another file. Some of our legacy code actually reads it into a second temp file, then into a final destination! And even if we did, that would mean creating yet another object with its __init__ call and associated overhead. cgi.py: Delete the references to self.lines for file uploads cgi.py: Ideally, the pseudo-dictionary syntax would go away. It seems to me that the main reason it is there is to accomodate form['field'].file syntax. How about the following: form['field'] = '' #no values for key form['field'] = 'string' #one value in submission for key form['field'] = ['string', 'string', ....] #multiple values form['field'] = {'fileName':'remote/path', 'binaryValue':'@UIHJBV29489erht...'} #one file form['field'] = [{'fileName':'remote/path', 'binaryValue':'@UIHJBV29489erht...'}, {'fileName':'another/path', 'binaryValue':'7r7w7@@@@'}] #multiple files cgi.py: I'd prefer "input" or "submission" for the suggested FieldStorage() name. The html page into which the data represented by FieldStorage() is input is commonly known as a "form", which means that when someone refers to "the form" you aren't always sure what they are talking about. cgi.py: Allow a combination of query data and POST data. Currently, if there is POST data, then any query data encoded in the URL is ignored. It would be more convenient if the data from those two sources were merged into one dictionary. (XXX but is this standard at all?) cgi.py: Currently, query data with no `=' are ignored. Even if keep_blank_values is set, queries like `...?value=&...' are returned with blank values but queries like `...?value&...' are completely lost. It would be great if such data were made available through the FieldStorage interface, either as entries with None as values, or in a separate list. Utility function: build a query string from a list of 2-tuples Higher-level frameworks: add something like Webware or Zope's HTTPReqest/HTTPResponse objects. An HTML templating module. (But which one? There's no clear, or even vague, indication of which templating module to enshrine.) Dictionary-related utility classes: NoKeyErrors (returns an empty string, never a KeyError), PartialStringSubstitution (returns the original key string, never a KeyError) New Modules This section lists details about entire new packages or modules that should be added to the Python standard library. Major Changes to Existing Modules This section lists details of major changes to existing modules, whether in implementation or in interface. The changes in this section therefore carry greater degrees of risk, either in introducing bugs or a backward incompatibility. Minor Changes to Existing Modules This section lists details of minor changes to existing modules. These changes should have relatively small implementations, and have little risk of introducing incompatibilities with previous versions. Rejected Changes The changes listed in this section were proposed for Python 2.1, but were rejected as unsuitable. For each rejected change, a rationale is given describing why the change was deemed inappropriate. * None yet Proposed Interface XXX open issues: naming convention (studlycaps or underline-separated?); no interface for file uploads yet; need to look at all the various packages to see if there's anything else missing; need to look at the cgi.parse*() functions and see if they can be simplified, too. Parsing functions: carry over most of the parse* functions from cgi.py # The Response class borrows most of its methods from Zope's # HTTPResponse class. class Response: """ Attributes: status: HTTP status code to return headers: dictionary of response headers body: string containing the body of the HTTP response """ def __init__(self, status=200, headers={}, body=""): pass def setStatus(self, status, reason=None): "Set the numeric HTTP response code" pass def setHeader(self, name, value): "Set an HTTP header" pass def setBody(self, body): "Set the body of the response" pass def setCookie(self, name, value, path = XXX, # What to use as defaults? comment = XXX, domain = XXX, max-age = XXX, expires = XXX, secure = XXX ): "Set a cookie" pass def expireCookie(self, name): "Remove a cookie from the user" pass def redirect(self, url): "Redirect the browser to another URL" pass def __str__(self): "Convert entire response to a string" pass def dump(self): "Return a string representation useful for debugging" pass # XXX methods for specific classes of error:serverError, badRequest, etc.? class Request: """ Attributes: .headers : dictionary containing HTTP headers .cookies : dictionary of cookies .form : data from the form .env : environment dictionary """ def __init__(self, environ=os.environ, stdin=sys.stdin, keep_blank_values=0, strict_parsing=0): """Initialize the request object, using the provided environment and standard input.""" pass # Should people just use the dictionaries directly? def getHeader(self, name, default=None): pass def getCookie(self, name, default=None): pass def getField(self, name, default=None): pass def getURL(self, n=0, query_string=0): """Return the URL of the current request, chopping off 'n' path components from the right. Eg. if the URL is "http://foo.com/bar/baz/qux", n=2 would return "http://foo.com/bar". Does not include the query string (if any) """ def getBaseURL(self, n=0): """Return the base URL of the current request, adding 'n' path components to the end to recreate more of the whole URL. Eg. if the request URL is "http://foo.com/q/bar/baz/qux", n=0 would return "http://foo.com/", and n=2 "http://foo.com/q/bar". Returned URL does not include the query string, if any. """ def dump(self): "String representation suitable for debugging output" pass # Possibilities? def getBrowser(self): "Returns Mozilla/IE/Lynx/Opera/whatever" def isSecure(self): "Return true if this is an SSLified request" def wrapper(func, logfile=None): """ Calls the function 'func', passing it the arguments (request, response, logfile). Exceptions are trapped and sent to the file 'logfile'. """ pass Copyright This document has been placed in the public domain. References and Footnotes [1] CGI.pm: [2] http://www.embl-heidelberg.de/~chenna/pythonpages/ Local Variables: mode: indented-text indent-tabs-mode: nil End: