Package couchdbkit :: Package schema :: Module properties
[hide private]
[frames] | no frames]

Source Code for Module couchdbkit.schema.properties

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of couchdbkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  """ properties used by Document object """ 
  7   
  8  from calendar import timegm 
  9  import decimal 
 10  import datetime 
 11  import re 
 12  import time 
 13   
 14  from couchdbkit.exceptions import * 
 15   
 16  __all__ = ['ALLOWED_PROPERTY_TYPES', 'Property', 'StringProperty', 
 17          'IntegerProperty', 'DecimalProperty', 'BooleanProperty', 
 18          'FloatProperty', 'DateTimeProperty', 'DateProperty', 
 19          'TimeProperty', 'DictProperty', 'ListProperty', 
 20          'StringListProperty', 'dict_to_json', 'list_to_json', 
 21          'value_to_json', 'MAP_TYPES_PROPERTIES', 'value_to_python', 
 22          'dict_to_python', 'list_to_python', 'convert_property', 
 23          'value_to_property', 'LazyDict', 'LazyList'] 
 24   
 25  ALLOWED_PROPERTY_TYPES = set([ 
 26      basestring, 
 27      str, 
 28      unicode, 
 29      bool, 
 30      int, 
 31      long, 
 32      float, 
 33      datetime.datetime, 
 34      datetime.date, 
 35      datetime.time, 
 36      decimal.Decimal, 
 37      dict, 
 38      list, 
 39      type(None) 
 40  ]) 
 41   
 42  re_date = re.compile('^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$') 
 43  re_time = re.compile('^([01]\d|2[0-3])\D?([0-5]\d)\D?([0-5]\d)?\D?(\d{3})?$') 
 44  re_datetime = re.compile('^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])(\D?([01]\d|2[0-3])\D?([0-5]\d)\D?([0-5]\d)?\D?(\d{3})?([zZ]|([\+-])([01]\d|2[0-3])\D?([0-5]\d)?)?)?$') 
 45  re_decimal = re.compile('^(\d+)\.(\d+)$') 
46 47 -class Property(object):
48 """ Property base which all other properties 49 inherit.""" 50 creation_counter = 0 51
52 - def __init__(self, verbose_name=None, name=None, 53 default=None, required=False, validators=None, 54 choices=None):
55 """ Default constructor for a property. 56 57 :param verbose_name: str, verbose name of field, could 58 be use for description 59 :param name: str, name of field 60 :param default: default value 61 :param required: True if field is required, default is False 62 :param validators: list of callable or callable, field validators 63 function that are executed when document is saved. 64 """ 65 self.verbose_name = verbose_name 66 self.name = name 67 self.default = default 68 self.required = required 69 self.validators = validators 70 self.choices = choices 71 self.creation_counter = Property.creation_counter 72 Property.creation_counter += 1
73
74 - def __property_config__(self, document_class, property_name):
75 self.document_class = document_class 76 if self.name is None: 77 self.name = property_name
78
79 - def __property_init__(self, document_instance, value):
80 """ method used to set value of the property when 81 we create the document. Don't check required. """ 82 if value is not None: 83 value = self.to_json(self.validate(value, required=False)) 84 document_instance._doc[self.name] = value
85
86 - def __get__(self, document_instance, document_class):
87 if document_instance is None: 88 return self 89 90 value = document_instance._doc.get(self.name) 91 if value is not None: 92 value = self._to_python(value) 93 94 return value
95
96 - def __set__(self, document_instance, value):
97 value = self.validate(value, required=False) 98 document_instance._doc[self.name] = self._to_json(value)
99
100 - def __delete__(self, document_instance):
101 pass
102
103 - def default_value(self):
104 """ return default value """ 105 106 default = self.default 107 if callable(default): 108 default = default() 109 return default
110
111 - def validate(self, value, required=True):
112 """ validate value """ 113 if required and self.empty(value): 114 if self.required: 115 raise BadValueError("Property %s is required." % self.name) 116 else: 117 if self.choices and value is not None: 118 if isinstance(self.choices, list): choice_list = self.choices 119 if isinstance(self.choices, dict): choice_list = self.choices.keys() 120 if isinstance(self.choices, tuple): choice_list = [key for (key, name) in self.choices] 121 122 if value not in choice_list: 123 raise BadValueError('Property %s is %r; must be one of %r' % ( 124 self.name, value, choice_list)) 125 if self.validators: 126 if isinstance(self.validators, (list, tuple,)): 127 for validator in self.validators: 128 if callable(validator): 129 validator(value) 130 elif callable(self.validators): 131 self.validators(value) 132 return value
133
134 - def empty(self, value):
135 """ test if value is empty """ 136 return not value or value is None
137
138 - def _to_python(self, value):
139 if value == None: 140 return value 141 return self.to_python(value)
142
143 - def _to_json(self, value):
144 if value == None: 145 return value 146 return self.to_json(value)
147
148 - def to_python(self, value):
149 """ convert to python type """ 150 return unicode(value)
151
152 - def to_json(self, value):
153 """ convert to json, Converted value is saved in couchdb. """ 154 return self.to_python(value)
155 156 data_type = None
157
158 -class StringProperty(Property):
159 """ string property str or unicode property 160 161 *Value type*: unicode 162 """ 163 164 to_python = unicode 165
166 - def validate(self, value, required=True):
167 value = super(StringProperty, self).validate(value, 168 required=required) 169 170 if value is None: 171 return value 172 173 if not isinstance(value, basestring): 174 raise BadValueError( 175 'Property %s must be unicode or str instance, not a %s' % (self.name, type(value).__name__)) 176 return value
177 178 data_type = unicode
179
180 -class IntegerProperty(Property):
181 """ Integer property. map to int 182 183 *Value type*: int 184 """ 185 to_python = int 186
187 - def empty(self, value):
188 return value is None
189
190 - def validate(self, value, required=True):
191 value = super(IntegerProperty, self).validate(value, 192 required=required) 193 194 if value is None: 195 return value 196 197 if value is not None and not isinstance(value, (int, long,)): 198 raise BadValueError( 199 'Property %s must be %s or long instance, not a %s' 200 % (self.name, type(self.data_type).__name__, 201 type(value).__name__)) 202 203 return value
204 205 data_type = int
206 LongProperty = IntegerProperty
207 208 -class FloatProperty(Property):
209 """ Float property, map to python float 210 211 *Value type*: float 212 """ 213 to_python = float 214 data_type = float 215
216 - def validate(self, value, required=True):
217 value = super(FloatProperty, self).validate(value, 218 required=required) 219 220 if value is None: 221 return value 222 223 if not isinstance(value, float): 224 raise BadValueError( 225 'Property %s must be float instance, not a %s' 226 % (self.name, type(value).__name__)) 227 228 return value
229 Number = FloatProperty
230 231 -class BooleanProperty(Property):
232 """ Boolean property, map to python bool 233 234 *ValueType*: bool 235 """ 236 to_python = bool 237 data_type = bool 238
239 - def validate(self, value, required=True):
240 value = super(BooleanProperty, self).validate(value, 241 required=required) 242 243 if value is None: 244 return value 245 246 if value is not None and not isinstance(value, bool): 247 raise BadValueError( 248 'Property %s must be bool instance, not a %s' 249 % (self.name, type(value).__name__)) 250 251 return value
252
253 - def empty(self, value):
254 """test if boolean is empty""" 255 return value is None
256
257 -class DecimalProperty(Property):
258 """ Decimal property, map to Decimal python object 259 260 *ValueType*: decimal.Decimal 261 """ 262 data_type = decimal.Decimal 263
264 - def to_python(self, value):
265 return decimal.Decimal(value)
266
267 - def to_json(self, value):
268 return unicode(value)
269
270 -class DateTimeProperty(Property):
271 """DateTime property. It convert iso3339 string 272 to python and vice-versa. Map to datetime.datetime 273 object. 274 275 *ValueType*: datetime.datetime 276 """ 277
278 - def __init__(self, verbose_name=None, auto_now=False, auto_now_add=False, 279 **kwds):
280 super(DateTimeProperty, self).__init__(verbose_name, **kwds) 281 self.auto_now = auto_now 282 self.auto_now_add = auto_now_add
283
284 - def validate(self, value, required=True):
285 value = super(DateTimeProperty, self).validate(value, required=required) 286 287 if value is None: 288 return value 289 290 if value and not isinstance(value, self.data_type): 291 raise BadValueError('Property %s must be a %s, current is %s' % 292 (self.name, self.data_type.__name__, type(value).__name__)) 293 return value
294
295 - def default_value(self):
296 if self.auto_now or self.auto_now_add: 297 return self.now() 298 return Property.default_value(self)
299
300 - def to_python(self, value):
301 if isinstance(value, basestring): 302 try: 303 value = value.split('.', 1)[0] # strip out microseconds 304 value = value[0:19] # remove timezone 305 value = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S') 306 except ValueError, e: 307 raise ValueError('Invalid ISO date/time %r' % value) 308 return value
309
310 - def to_json(self, value):
311 if self.auto_now: 312 value = self.now() 313 314 if value is None: 315 return value 316 return value.replace(microsecond=0).isoformat() + 'Z'
317 318 data_type = datetime.datetime 319 320 @staticmethod
321 - def now():
322 return datetime.datetime.utcnow()
323
324 -class DateProperty(DateTimeProperty):
325 """ Date property, like DateTime property but only 326 for Date. Map to datetime.date object 327 328 *ValueType*: datetime.date 329 """ 330 data_type = datetime.date 331 332 @staticmethod
333 - def now():
334 return datetime.datetime.now().date()
335
336 - def to_python(self, value):
337 if isinstance(value, basestring): 338 try: 339 value = datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) 340 except ValueError, e: 341 raise ValueError('Invalid ISO date %r' % value) 342 return value
343
344 - def to_json(self, value):
345 if value is None: 346 return value 347 return value.isoformat()
348
349 -class TimeProperty(DateTimeProperty):
350 """ Date property, like DateTime property but only 351 for time. Map to datetime.time object 352 353 *ValueType*: datetime.time 354 """ 355 356 data_type = datetime.time 357 358 @staticmethod
359 - def now(self):
360 return datetime.datetime.now().time()
361
362 - def to_python(self, value):
363 if isinstance(value, basestring): 364 try: 365 value = value.split('.', 1)[0] # strip out microseconds 366 value = datetime.time(*time.strptime(value, '%H:%M:%S')[3:6]) 367 except ValueError, e: 368 raise ValueError('Invalid ISO time %r' % value) 369 return value
370
371 - def to_json(self, value):
372 if value is None: 373 return value 374 return value.replace(microsecond=0).isoformat()
375
376 377 -class DictProperty(Property):
378 """ A property that stores a dict of things""" 379
380 - def __init__(self, verbose_name=None, default=None, 381 required=False, **kwds):
382 """ 383 :args verbose_name: Optional verbose name. 384 :args default: Optional default value; if omitted, an empty list is used. 385 :args**kwds: Optional additional keyword arguments, passed to base class. 386 387 Note that the only permissible value for 'required' is True. 388 """ 389 390 if default is None: 391 default = {} 392 393 Property.__init__(self, verbose_name, default=default, 394 required=required, **kwds)
395 396 data_type = dict 397
398 - def validate(self, value, required=True):
399 value = super(DictProperty, self).validate(value, required=required) 400 if value and value is not None: 401 if not isinstance(value, dict): 402 raise BadValueError('Property %s must be a dict' % self.name) 403 value = self.validate_dict_contents(value) 404 return value
405
406 - def validate_dict_contents(self, value):
407 try: 408 value = validate_dict_content(value) 409 except BadValueError: 410 raise BadValueError( 411 'Items of %s dict must all be in %s' % 412 (self.name, ALLOWED_PROPERTY_TYPES)) 413 return value
414
415 - def default_value(self):
416 """Default value for list. 417 418 Because the property supplied to 'default' is a static value, 419 that value must be shallow copied to prevent all fields with 420 default values from sharing the same instance. 421 422 Returns: 423 Copy of the default value. 424 """ 425 value = super(DictProperty, self).default_value() 426 if value is None: 427 value = {} 428 return dict(value)
429
430 - def to_python(self, value):
431 return LazyDict(value)
432
433 - def to_json(self, value):
434 return value_to_json(value)
435
436 437 438 -class ListProperty(Property):
439 """A property that stores a list of things. 440 441 """
442 - def __init__(self, verbose_name=None, default=None, 443 required=False, item_type=None, **kwds):
444 """Construct ListProperty. 445 446 447 :args verbose_name: Optional verbose name. 448 :args default: Optional default value; if omitted, an empty list is used. 449 :args**kwds: Optional additional keyword arguments, passed to base class. 450 451 452 """ 453 if default is None: 454 default = [] 455 456 if item_type is not None and item_type not in ALLOWED_PROPERTY_TYPES: 457 raise ValueError('item_type %s not in %s' % (item_type, ALLOWED_PROPERTY_TYPES)) 458 self.item_type = item_type 459 460 Property.__init__(self, verbose_name, default=default, 461 required=required, **kwds)
462 463 data_type = list 464
465 - def validate(self, value, required=True):
466 value = super(ListProperty, self).validate(value, required=required) 467 if value and value is not None: 468 if not isinstance(value, list): 469 raise BadValueError('Property %s must be a list' % self.name) 470 value = self.validate_list_contents(value) 471 return value
472
473 - def validate_list_contents(self, value):
474 value = validate_list_content(value, item_type=self.item_type) 475 try: 476 value = validate_list_content(value, item_type=self.item_type) 477 except BadValueError: 478 raise BadValueError( 479 'Items of %s list must all be in %s' % 480 (self.name, ALLOWED_PROPERTY_TYPES)) 481 return value
482
483 - def default_value(self):
484 """Default value for list. 485 486 Because the property supplied to 'default' is a static value, 487 that value must be shallow copied to prevent all fields with 488 default values from sharing the same instance. 489 490 Returns: 491 Copy of the default value. 492 """ 493 value = super(ListProperty, self).default_value() 494 if value is None: 495 value = [] 496 return list(value)
497
498 - def to_python(self, value):
499 return LazyList(value, item_type=self.item_type)
500
501 - def to_json(self, value):
502 return value_to_json(value, item_type=self.item_type)
503
504 505 -class StringListProperty(ListProperty):
506 """ shorthand for list that should containe only unicode""" 507
508 - def __init__(self, verbose_name=None, default=None, 509 required=False, **kwds):
510 super(StringListProperty, self).__init__(verbose_name=verbose_name, 511 default=default, required=required, item_type=basestring, **kwds)
512
513 # structures proxy 514 515 -class LazyDict(dict):
516 """ object to make sure we keep updated of dict 517 in _doc. We just override a dict and maintain change in 518 doc reference (doc[keyt] obviously). 519 520 if init_vals is specified, doc is overwritten 521 with the dict given. Otherwise, the values already in 522 doc are used. 523 """ 524
525 - def __init__(self, doc, item_type=None, init_vals=None):
526 dict.__init__(self) 527 self.item_type = item_type 528 529 self.doc = doc 530 if init_vals is None: 531 self._wrap() 532 else: 533 for key, value in init_vals.items(): 534 self[key] = value
535
536 - def _wrap(self):
537 for key, json_value in self.doc.items(): 538 if isinstance(json_value, dict): 539 value = LazyDict(json_value, item_type=self.item_type) 540 elif isinstance(json_value, list): 541 value = LazyList(json_value, item_type=self.item_type) 542 else: 543 value = value_to_python(json_value, self.item_type) 544 dict.__setitem__(self, key, value)
545
546 - def __setitem__(self, key, value):
547 if isinstance(value, dict): 548 self.doc[key] = {} 549 value = LazyDict(self.doc[key], item_type=self.item_type, init_vals=value) 550 elif isinstance(value, list): 551 self.doc[key] = [] 552 value = LazyList(self.doc[key], item_type=self.item_type, init_vals=value) 553 else: 554 self.doc.update({key: value_to_json(value, item_type=self.item_type) }) 555 super(LazyDict, self).__setitem__(key, value)
556
557 - def __delitem__(self, key):
558 del self.doc[key] 559 super(LazyDict, self).__delitem__(key)
560
561 - def pop(self, key, default=None):
562 del self.doc[key] 563 return super(LazyDict, self).pop(key, default=default)
564
565 - def setdefault(self, key, default):
566 if key in self: 567 return self[key] 568 self.doc.setdefault(key, value_to_json(default, item_type=self.item_type)) 569 super(LazyDict, self).setdefault(key, default) 570 return default
571
572 - def update(self, value):
573 for k, v in value.items(): 574 self[k] = v
575
576 - def popitem(self, value):
577 new_value = super(LazyDict, self).popitem(value) 578 self.doc.popitem(value_to_json(value, item_type=self.item_type)) 579 return new_value
580
581 - def clear(self):
582 self.doc.clear() 583 super(LazyDict, self).clear()
584
585 -class LazyList(list):
586 """ object to make sure we keep update of list 587 in _doc. We just override a list and maintain change in 588 doc reference (doc[index] obviously). 589 590 if init_vals is specified, doc is overwritten 591 with the list given. Otherwise, the values already in 592 doc are used. 593 """ 594
595 - def __init__(self, doc, item_type=None, init_vals=None):
596 list.__init__(self) 597 598 self.item_type = item_type 599 self.doc = doc 600 if init_vals is None: 601 # just wrap the current values 602 self._wrap() 603 else: 604 # initialize this list and the underlying list 605 # with the values given. 606 del self.doc[:] 607 for item in init_vals: 608 self.append(item)
609
610 - def _wrap(self):
611 for json_value in self.doc: 612 if isinstance(json_value, dict): 613 value = LazyDict(json_value, item_type=self.item_type) 614 elif isinstance(json_value, list): 615 value = LazyList(json_value, item_type=self.item_type) 616 else: 617 value = value_to_python(json_value, self.item_type) 618 list.append(self, value)
619
620 - def __delitem__(self, index):
621 del self.doc[index] 622 list.__delitem__(self, index)
623
624 - def __setitem__(self, index, value):
625 if isinstance(value, dict): 626 self.doc[index] = {} 627 value = LazyDict(self.doc[index], item_type=self.item_type, init_vals=value) 628 elif isinstance(value, list): 629 self.doc[index] = [] 630 value = LazyList(self.doc[index], item_type=self.item_type, init_vals=value) 631 else: 632 self.doc[index] = value_to_json(value, item_type=self.item_type) 633 list.__setitem__(self, index, value)
634 635
636 - def __delslice__(self, i, j):
637 del self.doc[i:j] 638 list.__delslice__(self, i, j)
639
640 - def __getslice__(self, i, j):
641 return LazyList(self.doc[i:j], self.item_type)
642
643 - def __setslice__(self, i, j, seq):
644 self.doc[i:j] = (value_to_json(v, item_type=self.item_type) for v in seq) 645 list.__setslice__(self, i, j, seq)
646
647 - def __contains__(self, value):
648 jvalue = value_to_json(value) 649 for m in self.doc: 650 if m == value: return True 651 return False
652
653 - def append(self, *args, **kwargs):
654 if args: 655 assert len(args) == 1 656 value = args[0] 657 else: 658 value = kwargs 659 660 index = len(self) 661 if isinstance(value, dict): 662 self.doc.append({}) 663 value = LazyDict(self.doc[index], item_type=self.item_type, init_vals=value) 664 elif isinstance(value, list): 665 self.doc.append([]) 666 value = LazyList(self.doc[index], item_type=self.item_type, init_vals=value) 667 else: 668 self.doc.append(value_to_json(value, item_type=self.item_type)) 669 super(LazyList, self).append(value)
670
671 - def index(self, x, *args):
672 x = value_to_json(x, item_type=self.item_type) 673 return self.doc.index(x)
674
675 - def remove(self, x):
676 del self[self.index(x)]
677
678 - def sort(self, cmp=None, key=None, reverse=False):
679 self.doc.sort(cmp, key, reverse) 680 list.sort(self, cmp, key, reverse)
681
682 - def reverse(self):
683 self.doc.reverse() 684 list.reverse(self)
685 686 687 # some mapping 688 689 MAP_TYPES_PROPERTIES = { 690 decimal.Decimal: DecimalProperty, 691 datetime.datetime: DateTimeProperty, 692 datetime.date: DateProperty, 693 datetime.time: TimeProperty, 694 str: StringProperty, 695 unicode: StringProperty, 696 bool: BooleanProperty, 697 int: IntegerProperty, 698 long: LongProperty, 699 float: FloatProperty, 700 list: ListProperty, 701 dict: DictProperty 702 }
703 704 -def convert_property(value):
705 """ convert a value to json from Property._to_json """ 706 if type(value) in MAP_TYPES_PROPERTIES: 707 prop = MAP_TYPES_PROPERTIES[type(value)]() 708 value = prop.to_json(value) 709 return value
710
711 712 -def value_to_property(value):
713 """ Convert value in a Property object """ 714 if type(value) in MAP_TYPES_PROPERTIES: 715 prop = MAP_TYPES_PROPERTIES[type(value)]() 716 return prop 717 else: 718 return value
719
720 # utilities functions 721 722 -def validate_list_content(value, item_type=None):
723 """ validate type of values in a list """ 724 return [validate_content(item, item_type=item_type) for item in value]
725
726 -def validate_dict_content(value, item_type=None):
727 """ validate type of values in a dict """ 728 return dict([(k, validate_content(v, 729 item_type=item_type)) for k, v in value.iteritems()])
730
731 -def validate_content(value, item_type=None):
732 """ validate a value. test if value is in supported types """ 733 if isinstance(value, list): 734 value = validate_list_content(value, item_type=item_type) 735 elif isinstance(value, dict): 736 value = validate_dict_content(value, item_type=item_type) 737 elif item_type is not None and not isinstance(value, item_type): 738 raise BadValueError( 739 'Items must all be in %s' % item_type) 740 elif type(value) not in ALLOWED_PROPERTY_TYPES: 741 raise BadValueError( 742 'Items must all be in %s' % 743 (ALLOWED_PROPERTY_TYPES)) 744 return value
745
746 -def dict_to_json(value, item_type=None):
747 """ convert a dict to json """ 748 return dict([(k, value_to_json(v, item_type=item_type)) for k, v in value.iteritems()])
749
750 -def list_to_json(value, item_type=None):
751 """ convert a list to json """ 752 return [value_to_json(item, item_type=item_type) for item in value]
753
754 -def value_to_json(value, item_type=None):
755 """ convert a value to json using appropriate regexp. 756 For Dates we use ISO 8601. Decimal are converted to string. 757 758 """ 759 if isinstance(value, datetime.datetime) and is_type_ok(item_type, datetime.datetime): 760 value = value.replace(microsecond=0).isoformat() + 'Z' 761 elif isinstance(value, datetime.date) and is_type_ok(item_type, datetime.date): 762 value = value.isoformat() 763 elif isinstance(value, datetime.time) and is_type_ok(item_type, datetime.time): 764 value = value.replace(microsecond=0).isoformat() 765 elif isinstance(value, decimal.Decimal) and is_type_ok(item_type, decimal.Decimal): 766 value = unicode(value) 767 elif isinstance(value, list): 768 value = list_to_json(value, item_type) 769 elif isinstance(value, dict): 770 value = dict_to_json(value, item_type) 771 return value
772
773 -def is_type_ok(item_type, value_type):
774 return item_type is None or item_type == value_type
775
776 777 -def value_to_python(value, item_type=None):
778 """ convert a json value to python type using regexp. values converted 779 have been put in json via `value_to_json` . 780 """ 781 data_type = None 782 if isinstance(value, basestring): 783 if re_date.match(value) and is_type_ok(item_type, datetime.datetime): 784 data_type = datetime.date 785 elif re_time.match(value) and is_type_ok(item_type, datetime.date): 786 data_type = datetime.time 787 elif re_datetime.match(value) and is_type_ok(item_type, datetime.time): 788 data_type = datetime.datetime 789 elif re_decimal.match(value) and is_type_ok(item_type, decimal.Decimal): 790 data_type = decimal.Decimal 791 if data_type is not None: 792 prop = MAP_TYPES_PROPERTIES[data_type]() 793 try: 794 #sometimes regex fail so return value 795 value = prop.to_python(value) 796 except: 797 pass 798 elif isinstance(value, list): 799 value = list_to_python(value, item_type=item_type) 800 elif isinstance(value, dict): 801 value = dict_to_python(value, item_type=item_type) 802 return value
803
804 -def list_to_python(value, item_type=None):
805 """ convert a list of json values to python list """ 806 return [value_to_python(item, item_type=item_type) for item in value]
807
808 -def dict_to_python(value, item_type=None):
809 """ convert a json object values to python dict """ 810 return dict([(k, value_to_python(v, item_type=item_type)) for k, v in value.iteritems()])
811