feat: Add ability to pass a dict 'store' to req.get_param

This patch adds an optional 'store' method argument to
req.get_param and friends. This makes it easy to construct
sparse dicts corresponding to query string params, e.g.,
for use as kwargs when calling app functions.

Closes issue #130
This commit is contained in:
kgriffs
2013-05-13 15:09:57 -04:00
parent 29b2027940
commit 16c669784a
2 changed files with 57 additions and 9 deletions

View File

@@ -367,13 +367,15 @@ class Request(object):
description = 'The "' + name + '" header is required.'
raise HTTPBadRequest('Missing header', description)
def get_param(self, name, required=False):
def get_param(self, name, required=False, store=None):
"""Return the value of a query string parameter as a string
Args:
name: Parameter name, case-sensitive (e.g., 'sort')
required: Set to True to raise HTTPBadRequest instead of returning
gracefully when the parameter is not found (default False)
store: A dict-like object in which to place the value of the
param, but only if the param is found.
Returns:
The value of the param as a string, or None if param is not found
@@ -388,6 +390,9 @@ class Request(object):
# 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:
if store is not None:
store[name] = self._params[name]
return self._params[name]
if not required:
@@ -396,7 +401,8 @@ class Request(object):
description = 'The "' + name + '" query parameter is required.'
raise HTTPBadRequest('Missing query parameter', description)
def get_param_as_int(self, name, required=False, min=None, max=None):
def get_param_as_int(self, name,
required=False, min=None, max=None, store=None):
"""Return the value of a query string parameter as an int
Args:
@@ -409,6 +415,8 @@ class Request(object):
max: Set to the maximum value allowed for this param. If the param
is found and its value is greater than max, an HTTPError is
raised.
store: A dict-like object in which to place the value of the
param, but only if the param is found (default None)
Returns:
The value of the param if it is found and can be converted to an
@@ -444,6 +452,9 @@ class Request(object):
'parameter may not exceed %d') % max
raise InvalidHeaderValueError(description)
if store is not None:
store[name] = val
return val
if not required:
@@ -452,7 +463,7 @@ class Request(object):
description = 'The "' + name + '" query parameter is required.'
raise HTTPBadRequest('Missing query parameter', description)
def get_param_as_bool(self, name, required=False):
def get_param_as_bool(self, name, required=False, store=None):
"""Return the value of a query string parameter as a boolean
Args:
@@ -460,6 +471,8 @@ class Request(object):
required: Set to True to raise HTTPBadRequest instead of returning
gracefully when the parameter is not found or is not one of
['true', 'false'] (default False)
store: A dict-like object in which to place the value of the
param, but only if the param is found (default None)
Returns:
The value of the param if it is found and can be converted to a
@@ -477,21 +490,27 @@ class Request(object):
if name in self._params:
val = self._params[name]
if val == 'true':
return True
val = True
elif val == 'false':
return False
val = False
else:
description = ('The value of the "' + name + '" query '
'parameter must be "true" or "false".')
raise InvalidParamValueError(description)
if store is not None:
store[name] = val
return val
if not required:
return None
description = 'The "' + name + '" query parameter is required.'
raise HTTPBadRequest('Missing query parameter', description)
def get_param_as_list(self, name, transform=None, required=False):
def get_param_as_list(self, name,
transform=None, required=False, store=None):
"""Return the value of a query string parameter as a list
Note that list items must be comma-separated.
@@ -504,6 +523,8 @@ class Request(object):
required: Set to True to raise HTTPBadRequest instead of returning
gracefully when the parameter is not found or is not an
integer (default False)
store: A dict-like object in which to place the value of the
param, but only if the param is found (default None)
Returns:
The value of the param if it is found. Otherwise, returns None
@@ -527,6 +548,9 @@ class Request(object):
'is not formatted correctly.')
raise InvalidParamValueError(desc)
if store is not None:
store[name] = items
return items
if not required:

View File

@@ -13,8 +13,10 @@ class TestQueryParams(testing.TestBase):
self.simulate_request('/', query_string=query_string)
req = self.resource.req
store = {}
self.assertIs(req.get_param('marker'), None)
self.assertIs(req.get_param('limit'), None)
self.assertIs(req.get_param('limit', store), None)
self.assertNotIn('limit', store)
self.assertIs(req.get_param_as_int('limit'), None)
self.assertIs(req.get_param_as_bool('limit'), None)
self.assertIs(req.get_param_as_list('limit'), None)
@@ -26,13 +28,22 @@ class TestQueryParams(testing.TestBase):
req = self.resource.req
self.assertIs(req.get_param('marker'), None)
store = {}
self.assertIs(req.get_param('marker', store=store), None)
self.assertNotIn('marker', store)
def test_simple(self):
query_string = 'marker=deadbeef&limit=25'
self.simulate_request('/', query_string=query_string)
req = self.resource.req
self.assertEquals(req.get_param('marker') or 'deadbeef', 'deadbeef')
self.assertEquals(req.get_param('limit') or '25', '25')
store = {}
self.assertEquals(req.get_param('marker', store=store) or 'nada',
'deadbeef')
self.assertEquals(req.get_param('limit', store=store) or '0', '25')
self.assertEquals(store['marker'], 'deadbeef')
self.assertEquals(store['limit'], '25')
def test_allowed_names(self):
query_string = ('p=0&p1=23&2p=foo&some-thing=that&blank=&some_thing=x&'
@@ -69,8 +80,13 @@ class TestQueryParams(testing.TestBase):
req = self.resource.req
self.assertRaises(falcon.HTTPBadRequest, req.get_param_as_int,
'marker')
self.assertEquals(req.get_param_as_int('limit'), 25)
store = {}
self.assertEquals(req.get_param_as_int('limit', store=store), 25)
self.assertEquals(store['limit'], 25)
self.assertEquals(
req.get_param_as_int('limit', min=1, max=50), 25)
@@ -153,6 +169,10 @@ class TestQueryParams(testing.TestBase):
self.assertEquals(req.get_param_as_bool('echo'), True)
self.assertEquals(req.get_param_as_bool('doit'), False)
store = {}
self.assertEquals(req.get_param_as_bool('echo', store=store), True)
self.assertEquals(store['echo'], True)
def test_list_type(self):
query_string = 'colors=red,green,blue&limit=1'
self.simulate_request('/', query_string=query_string)
@@ -164,6 +184,10 @@ class TestQueryParams(testing.TestBase):
self.assertEquals(req.get_param_as_list('limit'), ['1'])
self.assertIs(req.get_param_as_list('marker'), None)
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'
self.simulate_request('/', query_string=query_string)