comparison piecrust/fastpickle.py @ 459:2ef04e16f0b9

internal: Add support for fake pickling of date/time structures.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 11 Jul 2015 00:44:58 -0700
parents 298f8f46432a
children b015e38d4ee1
comparison
equal deleted inserted replaced
458:612ed0526afd 459:2ef04e16f0b9
9 9
10 def unpickle(data): 10 def unpickle(data):
11 return _unpickle_object(data) 11 return _unpickle_object(data)
12 12
13 13
14 def _tuple_dispatch(obj, func): 14 _PICKLING = 0
15 _UNPICKLING = 1
16
17
18 def _tuple_dispatch(obj, func, op):
15 res = [None] * len(obj) 19 res = [None] * len(obj)
16 for i, c in enumerate(obj): 20 for i, c in enumerate(obj):
17 res[i] = func(c) 21 res[i] = func(c)
18 return tuple(res) 22 return tuple(res)
19 23
20 24
21 def _list_dispatch(obj, func): 25 def _list_dispatch(obj, func, op):
22 res = [None] * len(obj) 26 res = [None] * len(obj)
23 for i, c in enumerate(obj): 27 for i, c in enumerate(obj):
24 res[i] = func(c) 28 res[i] = func(c)
25 return res 29 return res
26 30
27 31
28 def _dict_dispatch(obj, func): 32 def _dict_dispatch(obj, func, op):
29 res = {} 33 res = {}
30 for k, v in obj.items(): 34 for k, v in obj.items():
31 res[k] = func(v) 35 res[k] = func(v)
32 return res 36 return res
33 37
34 38
35 def _set_dispatch(obj, func): 39 def _set_dispatch(obj, func, op):
36 res = set() 40 res = set()
37 for v in obj: 41 for v in obj:
38 res.add(func(v)) 42 res.add(func(v))
39 return res 43 return res
44
45
46 def _date_convert(obj, op):
47 if op == _PICKLING:
48 return {'__class__': 'date',
49 'year': obj.year,
50 'month': obj.month,
51 'day': obj.day}
52 elif op == _UNPICKLING:
53 return datetime.date(
54 obj['year'], obj['month'], obj['day'])
55
56
57 def _datetime_convert(obj, op):
58 if op == _PICKLING:
59 return {'__class__': 'datetime',
60 'year': obj.year,
61 'month': obj.month,
62 'day': obj.day,
63 'hour': obj.hour,
64 'minute': obj.minute,
65 'second': obj.second,
66 'microsecond': obj.microsecond}
67 elif op == _UNPICKLING:
68 return datetime.datetime(
69 obj['year'], obj['month'], obj['day'],
70 obj['hour'], obj['minute'], obj['second'], obj['microsecond'])
71
72
73 def _time_convert(obj, op):
74 if op == _PICKLING:
75 return {'__class__': 'time',
76 'hour': obj.hour,
77 'minute': obj.minute,
78 'second': obj.second,
79 'microsecond': obj.microsecond}
80 elif op == _UNPICKLING:
81 return datetime.time(
82 obj['hour'], obj['minute'], obj['second'], obj['microsecond'])
40 83
41 84
42 _identity_dispatch = object() 85 _identity_dispatch = object()
43 86
44 _type_dispatch = { 87 _type_dispatch = {
45 type(None): _identity_dispatch, 88 type(None): _identity_dispatch,
46 bool: _identity_dispatch, 89 bool: _identity_dispatch,
47 int: _identity_dispatch, 90 int: _identity_dispatch,
48 float: _identity_dispatch, 91 float: _identity_dispatch,
49 str: _identity_dispatch, 92 str: _identity_dispatch,
50 datetime.date: _identity_dispatch,
51 datetime.datetime: _identity_dispatch,
52 datetime.time: _identity_dispatch,
53 tuple: _tuple_dispatch, 93 tuple: _tuple_dispatch,
54 list: _list_dispatch, 94 list: _list_dispatch,
55 dict: _dict_dispatch, 95 dict: _dict_dispatch,
56 collections.OrderedDict: _dict_dispatch, 96 collections.OrderedDict: _dict_dispatch,
57 set: _set_dispatch 97 set: _set_dispatch
98 }
99
100
101 _type_convert = {
102 datetime.date: _date_convert,
103 datetime.datetime: _datetime_convert,
104 datetime.time: _time_convert
105 }
106
107
108 _type_unconvert = {
109 'date': _date_convert,
110 'datetime': _datetime_convert,
111 'time': _time_convert
58 } 112 }
59 113
60 114
61 def _pickle_object(obj): 115 def _pickle_object(obj):
62 t = type(obj) 116 t = type(obj)
63 disp = _type_dispatch.get(t) 117 disp = _type_dispatch.get(t)
64 if disp is _identity_dispatch: 118 if disp is _identity_dispatch:
65 return obj 119 return obj
66 120
67 if disp is not None: 121 if disp is not None:
68 return disp(obj, _pickle_object) 122 return disp(obj, _pickle_object, _PICKLING)
69 123
70 if isinstance(obj, Exception): 124 conv = _type_convert.get(t)
71 return obj 125 if conv is not None:
126 return conv(obj, _PICKLING)
72 127
73 getter = getattr(obj, '__getstate__', None) 128 getter = getattr(obj, '__getstate__', None)
74 if getter is not None: 129 if getter is not None:
75 state = getter() 130 state = getter()
76 else: 131 else:
77 state = obj.__dict__ 132 state = obj.__dict__
78 133
79 state = _dict_dispatch(state, _pickle_object) 134 state = _dict_dispatch(state, _pickle_object, _PICKLING)
80 state['__class__'] = obj.__class__.__name__ 135 state['__class__'] = obj.__class__.__name__
81 state['__module__'] = obj.__class__.__module__ 136 state['__module__'] = obj.__class__.__module__
82 137
83 return state 138 return state
84 139
88 disp = _type_dispatch.get(t) 143 disp = _type_dispatch.get(t)
89 if disp is _identity_dispatch: 144 if disp is _identity_dispatch:
90 return state 145 return state
91 146
92 if (disp is not None and 147 if (disp is not None and
93 (t != dict or '__module__' not in state)): 148 (t != dict or '__class__' not in state)):
94 return disp(state, _unpickle_object) 149 return disp(state, _unpickle_object, _UNPICKLING)
95 150
96 if isinstance(state, Exception): 151 class_name = state['__class__']
97 return state 152 conv = _type_unconvert.get(class_name)
153 if conv is not None:
154 return conv(state, _UNPICKLING)
98 155
99 mod_name = state['__module__'] 156 mod_name = state['__module__']
100 mod = sys.modules[mod_name] 157 mod = sys.modules[mod_name]
101 class_name = state['__class__']
102 class_def = getattr(mod, class_name) 158 class_def = getattr(mod, class_name)
103 obj = class_def.__new__(class_def) 159 obj = class_def.__new__(class_def)
104 160
105 del state['__class__'] 161 del state['__class__']
106 del state['__module__'] 162 del state['__module__']