-
Notifications
You must be signed in to change notification settings - Fork 22
/
primitive_util.py
81 lines (68 loc) · 2.66 KB
/
primitive_util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/python
""" This a mixin to a generically serialize objects to primative types.
This is serializing the internal variables of classes, and hence is a
big abstraction leak. By mixing with this class, you can give yourself
headaches if you change the implementation of a class and want to work
with previously serialized versions of data.
"""
import collections
PRIMITIVES = [dict, str, int, list, float, unicode]
def to_primitive(val):
if hasattr(val, 'to_primitive_object'):
return val.to_primitive_object()
assert type(val) in PRIMITIVES, (val, type(val))
return val
class PrimitiveConversion(object):
def to_primitive_object(self):
ret = {}
for k, v in self.__dict__.iteritems():
ret[k] = to_primitive(v)
return ret
def from_primitive_object(self, obj):
# Get rid of _id because it's something that mongo injects into our
# objects, and it's not really natural to the objects themselves.
obj_keys_except_id = set(obj.keys()) - set(['_id'])
unicoded_keys = set(map(unicode, self.__dict__.keys()))
assert unicoded_keys == obj_keys_except_id, (
'%s != %s' % (str(unicoded_keys), str(obj_keys_except_id)))
for k in obj_keys_except_id:
if hasattr(self.__dict__[k], 'from_primitive_object'):
self.__dict__[k].from_primitive_object(obj[k])
else:
assert type(obj[k]) in PRIMITIVES, obj[k]
self.__dict__[k] = obj[k]
class ConvertibleDefaultDict(collections.defaultdict, PrimitiveConversion):
def __init__(self, value_type, key_type = str):
collections.defaultdict.__init__(self, value_type)
self.value_type = value_type
self.key_type = key_type
def to_primitive_object(self):
ret = {}
for key, val in self.iteritems():
if type(key) == unicode:
key = key.encode('utf-8')
else:
key = str(key)
ret[key] = to_primitive(val)
return ret
def from_primitive_object(self, obj):
for k, v in obj.iteritems():
if k == '_id': continue
val = self.value_type()
if hasattr(val, 'from_primitive_object'):
val.from_primitive_object(v)
else:
val = v
self[self.key_type(k)] = val
if __name__ == '__main__':
import pymongo
c = pymongo.Connection()
db = c.test
coll = db.prim
prim_a['_id'] = ''
coll.save(prim_a, safe='true')
a_from_db = list(coll.find())[0]
new_a = A()
new_a.from_primitive_object(a_from_db)
assert new_a.foo == a.foo
assert new_a.bar == a.bar