fix(Request.get_param_as_list): Handle missing list items

This patch modifies get_param_as_list to handle missing list items by
inserting None as a placeholder. If the query parameter's value is just
commas, then they are collapsed into a single None (as if the query
param hadn't been specified).

Fixes #154
This commit is contained in:
kgriffs
2013-09-06 14:35:11 -05:00
parent 2e80b6f7c5
commit ba912e367a
3 changed files with 57 additions and 18 deletions

View File

@@ -549,7 +549,9 @@ class Request(object):
name: Parameter name, case-sensitive (e.g., 'limit')
transform: An optional transform function that takes as input
each element in the list as a string and outputs a transformed
element for inclusion in the list that will be returned.
element for inclusion in the list that will be returned. For
example, passing the int function will transform list items
into numbers.
required: Set to True to raise HTTPBadRequest instead of returning
gracefully when the parameter is not found or is not an
integer (default False)
@@ -558,21 +560,43 @@ class Request(object):
Returns:
The value of the param if it is found. Otherwise, returns None
unless required is True.
unless required is True. for partial lists, None will be returned
as a placeholder. For example:
things=1,,3
would be returned as:
['1', None, '3']
while this:
things=,,,
would just be retured as:
[None, None, None, None]
Raises
HTTPBadRequest: The param was not found in the request, but was
required.
"""
# PERF: Use if..in since it is a good all-around performer; we don't
# know how likely params are to be specified by clients.
if name in self._params:
items = self._params[name].split(',')
if transform is not None:
# PERF(kgriffs): Use if-else rather than a DRY approach
# that sets transform to a passthrough function; avoids
# function calling overhead.
if transform is None:
items = [i if i != '' else None
for i in items]
else:
try:
items = [transform(x) for x in items]
items = [transform(i) if i != '' else None
for i in items]
except ValueError:
desc = ('The value of the "' + name + '" query parameter '
'is not formatted correctly.')

View File

@@ -181,7 +181,9 @@ class TestQueryParams(testing.TestBase):
self.assertEquals(store['echo'], True)
def test_list_type(self):
query_string = 'colors=red,green,blue&limit=1'
query_string = ('colors=red,green,blue&limit=1'
'&list-ish1=f,,x&list-ish2=,0&list-ish3=a,,,b'
'&empty1=&empty2=,&empty3=,,')
self.simulate_request('/', query_string=query_string)
req = self.resource.req
@@ -191,12 +193,27 @@ class TestQueryParams(testing.TestBase):
self.assertEquals(req.get_param_as_list('limit'), ['1'])
self.assertIs(req.get_param_as_list('marker'), None)
self.assertEquals(req.get_param_as_list('empty1'), None)
self.assertEquals(req.get_param_as_list('empty2'), [None, None])
self.assertEquals(req.get_param_as_list('empty3'), [None, None, None])
self.assertEquals(req.get_param_as_list('list-ish1'),
['f', None, 'x'])
# Ensure that '0' doesn't get translated to None
self.assertEquals(req.get_param_as_list('list-ish2'),
[None, '0'])
# Ensure that '0' doesn't get translated to None
self.assertEquals(req.get_param_as_list('list-ish3'),
['a', None, None, 'b'])
store = {}
self.assertEquals(req.get_param_as_list('limit', store=store), ['1'])
self.assertEquals(store['limit'], ['1'])
def test_list_transformer(self):
query_string = 'coord=1.4,13,15.1&limit=100'
query_string = 'coord=1.4,13,15.1&limit=100&things=4,,1'
self.simulate_request('/', query_string=query_string)
req = self.resource.req
@@ -206,15 +223,13 @@ class TestQueryParams(testing.TestBase):
actual = req.get_param_as_list('coord', transform=float)
self.assertEquals(actual, expected)
expected = ['4', None, '1']
actual = req.get_param_as_list('things', transform=str)
self.assertEquals(actual, expected)
expected = [4, None, 1]
actual = req.get_param_as_list('things', transform=int)
self.assertEquals(actual, expected)
self.assertRaises(falcon.HTTPBadRequest,
req.get_param_as_list, 'coord', transform=int)
def test_bogus_input(self):
query_string = 'colors=red,green,&limit=1&pickle'
self.simulate_request('/', query_string=query_string)
req = self.resource.req
self.assertEquals(req.get_param_as_list('colors'),
['red', 'green', ''])
self.assertEquals(req.get_param('limit'), '1')
self.assertIs(req.get_param('pickle'), None)

View File

@@ -24,5 +24,5 @@ commands = py3kwarn falcon
deps = flake8
commands = flake8 \
--max-complexity=12 \
--exclude=.venv,.tox,dist,doc,./falcon/bench/nuts \
--exclude=./build,.venv,.tox,dist,doc,./falcon/bench/nuts \
--ignore=F403