I have written a function to handle post data received from a web page. The Emphasis is on making getting post data easy: using the function allows the coder to specify the required data, type, and default value all in one line.
I'm using django and it provides a nice dict of post data. this will be passed to the function.
All the post data values is str. I want the str values converted to required types, and for default values to be used if the keys were not in the post data.
The required types include int, uuid, long, and str.
here is what I have:
def handler(post_data, transforms):
""" Generator function that takes dict of post_data and treats in way specified by transforms
Arguments:
post_data - post data to be transformed to type required - dict
transforms - tuple of tuples of how to treat the post data. - tuple
'schema' of transforms:
(
(key in post_data to get,
type to convert the vale to e.g, int or uuid,
boolean of if value is required or not,
default value to return if no key not exist ), ...
)
example of transforms:
( ('key1', uuid, True), ('from', str, False, 'UK'), 'user', 'address' )
annotated example : (
('key1', uuid, True), # convert val at 'key1' to uuid. required.
('from', str, False, 'UK'), # 'convert' val at 'from' to str. not required. Default value = 'UK'
'user', # get value at 'user'
'address', # get value at 'address'
)
"""
def defaults(key, to_type=str, required=True, default_value=None):
"""gives default values to any values not specified in the transform"""
return key, to_type, required, default_value
for transform in transforms:
#if transform is a string then encapsulate
transform = transform if isinstance(transform, tuple) else [transform]
#unpack but provide default values for absent keys
key, to_type, required, fallback = defaults(*transform)
try:
#try to convert the value to the format required by transform
raw = request.POST.get(key)
yield fallback if not raw else to_type(raw)
except (ValueError, KeyError):
#if key not exists or value cannot be converted
if required:
return #bailout
yield fallback
example usage:
post_data = {'name':'richard', 'age':'23', 'from':'UK', 'key1': '330c48a4-3664-11e2-982e-fda51ac77194'}
[in ] name, age = handler(post_data, transforms=('name', 'age'))
[in ] print name, age
[out] 'richard', '23'#notice 23 as string
[in ] name, age = handler(post_data, transforms=('name', ('age', int)))
[in ] print name, age
[out] 'richard', 23 #notice 23 as int
[in ] key1, brother = handler(post_data, transforms=(('key1', uuid), ('brother', str, False)))
[in ] print key1, brother
[out] UUID('330c48a4-3664-11e2-982e-fda51ac77194') #notice string has been converted to uuid and absense of brother value
[in ] key1, brother = handler(post_data, transforms=(('key1', uuid), ('brother', str, False, 'Abe')))
[in ] print key1, brother
[out] UUID('330c48a4-3664-11e2-982e-fda51ac77194'), 'Abe' #notice default value for brother used
I'm looking to make the code even more consise.
1 Answer 1
I think the code is great.
Some comments:
- Transform is a tuple of 4 elements (key, type, is_default, default_value). I think is too many, it is hard to remember which means what.
- Since it is a tuple - if you want to provide a "default_value" - you need to provide everything else. But in real life the most common scenario for me is to use
request.GET.get('param1', 'default_value')
- I'm not sure about the version of python, but in python 2.* it would not cover unicodes
isinstance(transform, str)
- function name
def handler(post_data, transforms)
should be a verb probably.
-
\$\begingroup\$ thanks. I will do the following: 1: combine "is_default" and "default_value" 2: I will do raw = request.POST.get(key) yield fallback if not raw else to_type(raw) 3: I will use not isinstance(transform, list) 4: I will rename accordingly \$\endgroup\$Code Review Doctor– Code Review Doctor2013年01月17日 09:43:34 +00:00Commented Jan 17, 2013 at 9:43
-
\$\begingroup\$
not isinstance(transform, list)
will not work, because you are using tuples. If you want to check for unicode + str , you can useisinstance(transform, basestring)
. if you want to check for collections you need to use collections module it has base classes for collections. \$\endgroup\$RomanI– RomanI2013年01月17日 19:02:49 +00:00Commented Jan 17, 2013 at 19:02