[Checkins] SVN: zope.httpform/trunk/src/zope/httpform/ Increased test coverage.
Shane Hathaway
shane at hathawaymix.org
Thu Feb 5 19:22:34 EST 2009
Log message for revision 96166:
Increased test coverage.
Changed:
U zope.httpform/trunk/src/zope/httpform/README.txt
U zope.httpform/trunk/src/zope/httpform/parser.py
-=-
Modified: zope.httpform/trunk/src/zope/httpform/README.txt
===================================================================
--- zope.httpform/trunk/src/zope/httpform/README.txt 2009-02-05 23:15:15 UTC (rev 96165)
+++ zope.httpform/trunk/src/zope/httpform/README.txt 2009-02-06 00:22:34 UTC (rev 96166)
@@ -38,12 +38,12 @@
What happens if variables get repeated?
- >>> env['QUERY_STRING'] = 'x:int=1&x:float=2'
+ >>> env['QUERY_STRING'] = 'x=0&x=a&x=b&x:int=1&x:float=2'
>>> pprint.pprint(FormParser(env).parse())
- {u'x': [1, 2.0]}
+ {u'x': [u'0', u'a', u'b', 1, 2.0]}
-That's reasonable, but it's even better to use another suffix so that
-certain variables are returned as a list even when they occur only once.
+That's reasonable, but it's even better to use the `:list` suffix so that
+field values are a list even when they occur only once.
>>> env['QUERY_STRING'] = 'x:int:list=1'
>>> pprint.pprint(FormParser(env).parse())
@@ -80,6 +80,12 @@
>>> pprint.pprint(FormParser(env).parse())
{u'x': (2, 1)}
+A value can become a list:
+
+ >>> env['QUERY_STRING'] = 'x:int=0&x:int:list=1'
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'x': [0, 1]}
+
Default Values
--------------
@@ -102,14 +108,24 @@
>>> pprint.pprint(FormParser(env).parse())
{u'country': u'US'}
-A default value can take the place of a list.
+A default value takes the place of an empty value.
- >>> env['QUERY_STRING'] = 'x:default=null'
+ >>> env['QUERY_STRING'] = 'x:int:default=0&x:int='
>>> pprint.pprint(FormParser(env).parse())
- {u'x': u'null'}
- >>> env['QUERY_STRING'] = 'x:int:list=1&x:default=null'
+ {u'x': 0}
+
+A default list value will be added to the list unless it has already
+been added.
+
+ >>> env['QUERY_STRING'] = 'x:list:default=always'
>>> pprint.pprint(FormParser(env).parse())
- {u'x': [1]}
+ {u'x': [u'always']}
+ >>> env['QUERY_STRING'] = 'x:list:default=always&x:list=always'
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'x': [u'always']}
+ >>> env['QUERY_STRING'] = 'x:list:default=always&x:list=never'
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'x': [u'never', u'always']}
Required Values
---------------
@@ -136,7 +152,7 @@
Use `:tokens` to split the input on whitespace.
- >>> env['QUERY_STRING'] = 'x:tokens=a+b++c%0Dd'
+ >>> env['QUERY_STRING'] = 'x:tokens=a+b++c%0Ad'
>>> pprint.pprint(FormParser(env).parse())
{u'x': [u'a', u'b', u'c', u'd']}
@@ -173,6 +189,13 @@
>>> x['a']
1
+You can use str(record), although repr(record) is more informative.
+
+ >>> str(x)
+ '{a: 1, b: 2}'
+ >>> repr(x)
+ "{'a': 1, 'b': 2}"
+
Some attribute names would clash with mapping method names and are thus
disallowed.
@@ -203,6 +226,60 @@
>>> pprint.pprint(FormParser(env).parse())
{u'points': [{'x': 1.0, 'y': 2.0}, {'x': 11.0, 'y': -2.0}]}
+A record can contain a tuple.
+
+ >>> q = 'segment.p0:tuple:record=0'
+ >>> q += '&segment.p0:tuple:record=0'
+ >>> q += '&segment.p1:tuple:record=10'
+ >>> q += '&segment.p1:tuple:record=11'
+ >>> env['QUERY_STRING'] = q
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'segment': {'p0': (u'0', u'0'), 'p1': (u'10', u'11')}}
+
+You can put a list or tuple inside a record list, but you need to use
+a non-list record attribute to indiciate the start of each record.
+Here we're going to use the record attribute with an empty name to
+mark new records.
+
+ >>> q = 'points.color:records:default:int=0'
+ >>> q += '&points:records='
+ >>> q += '&points.axes:tuple:int:records=0'
+ >>> q += '&points.axes:tuple:int:records=0'
+ >>> q += '&points.axes:tuple:int:records=0'
+ >>> q += '&points.color:int:records='
+ >>> q += '&points:records='
+ >>> q += '&points.axes:tuple:int:records=1'
+ >>> q += '&points.axes:tuple:int:records=2'
+ >>> q += '&points.axes:tuple:int:records=3'
+ >>> env['QUERY_STRING'] = q
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'points': [{'': u'', 'axes': (0, 0, 0), 'color': 0},
+ {'': u'', 'axes': (1, 2, 3), 'color': 0}]}
+
+Records can have a default value for each field.
+
+ >>> q = 'friends.birthdate:default:records=unspecified'
+ >>> q += '&friends.name:records=Alice'
+ >>> q += '&friends.name:records=Bob'
+ >>> q += '&friends.name:records=Charlie'
+ >>> q += '&friends.birthdate:records=1/1/1'
+ >>> env['QUERY_STRING'] = q
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'friends': [{'birthdate': u'unspecified', 'name': u'Alice'},
+ {'birthdate': u'unspecified', 'name': u'Bob'},
+ {'birthdate': u'1/1/1', 'name': u'Charlie'}]}
+
+There can be a default record.
+
+ >>> q = 'prefs.name:record:default=unnamed'
+ >>> q += '&prefs.address:record:default=unknown'
+ >>> q += '&prefs.age:int:record:default=100'
+ >>> q += '&prefs.address:record=123+Grant+Ave'
+ >>> q += '&prefs.age:int:record='
+ >>> env['QUERY_STRING'] = q
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'prefs': {'address': u'123 Grant Ave', 'age': 100, 'name': u'unnamed'}}
+
Actions
-------
@@ -219,7 +296,7 @@
>>> parser.action is None
True
-Here's an action:
+Here is an action:
>>> env['QUERY_STRING'] = 'y:int=1&:action=getX'
>>> parser = FormParser(env)
@@ -265,6 +342,55 @@
>>> parser.action
u'prev'
+Invalid Input
+-------------
+
+Invalid suffixes are counted as part of the field name. Valid
+but unrecognized suffixes get ignored.
+
+ >>> env['QUERY_STRING'] = 'x:0:int=1&y:complex=2'
+ >>> pprint.pprint(FormParser(env).parse())
+ {u'x:0': 1, u'y': u'2'}
+
+The int, long, and float types require a valid value.
+
+ >>> env['QUERY_STRING'] = 'x:int='
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: Empty entry when integer expected
+
+ >>> env['QUERY_STRING'] = 'x:int=z'
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: An integer was expected in the value 'z'
+
+ >>> env['QUERY_STRING'] = 'x:long='
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: Empty entry when integer expected
+
+ >>> env['QUERY_STRING'] = 'x:long=z'
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: A long integer was expected in the value 'z'
+
+ >>> env['QUERY_STRING'] = 'x:float='
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: Empty entry when float expected
+
+ >>> env['QUERY_STRING'] = 'x:float=z'
+ >>> pprint.pprint(FormParser(env).parse())
+ Traceback (most recent call last):
+ ...
+ ValueError: A float was expected in the value 'z'
+
+
URL Encoded POST
----------------
@@ -284,6 +410,15 @@
>>> pprint.pprint(FormParser(env).parse())
{}
+No form parsing is done for content types that don't look like forms.
+
+ >>> input_fp = StringIO("x:int=1&y:int=2")
+ >>> env = {'REQUEST_METHOD': 'POST',
+ ... 'CONTENT_TYPE': 'text/xml',
+ ... 'wsgi.input': input_fp}
+ >>> pprint.pprint(FormParser(env).parse())
+ {}
+
File Upload
-----------
@@ -353,3 +488,26 @@
>>> pprint.pprint(form)
{u'pics': 'I am file1.txt.'}
+Send a big file. (More than 1000 bytes triggers storage to a tempfile.)
+
+ >>> content_type = 'multipart/form-data; boundary=AaB03x'
+ >>> input_body="""\
+ ... --AaB03x
+ ... content-disposition: form-data; name="pics"; filename="file1.txt"
+ ... Content-Type: application/octet-stream
+ ...
+ ... """
+ >>> input_body += 30 * '0123456789012345678901234567890123456789'
+ >>> input_body += "\n--AaB03x--\n"
+ >>> env = {'REQUEST_METHOD': 'POST',
+ ... 'CONTENT_TYPE': content_type,
+ ... 'wsgi.input': StringIO(input_body)}
+ >>> form = FormParser(env).parse()
+ >>> pprint.pprint(form)
+ {u'pics': <zope.httpform.parser.FileUpload object at ...>}
+ >>> data = form['pics'].read()
+ >>> len(data)
+ 1200
+ >>> data[:12]
+ '012345678901'
+
Modified: zope.httpform/trunk/src/zope/httpform/parser.py
===================================================================
--- zope.httpform/trunk/src/zope/httpform/parser.py 2009-02-05 23:15:15 UTC (rev 96165)
+++ zope.httpform/trunk/src/zope/httpform/parser.py 2009-02-06 00:22:34 UTC (rev 96166)
@@ -294,11 +294,6 @@
else:
k, attr = self._split_key(key)
- # remove any type_names in the attr
- i = attr.find(":")
- if i >= 0:
- attr = attr[:i]
-
if k in form:
item = form[k]
if isinstance(item, Record):
More information about the Checkins
mailing list