Mercurial > piecrust2
comparison piecrust/fastpickle.py @ 450:298f8f46432a
internal: Add a `fastpickle` module to help with multiprocess serialization.
Looks like we're wasting a lot of time serializing custom class information
for the workers, so this new module helps to convert classes to standard
structures (dicts, lists, etc).
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Mon, 06 Jul 2015 21:29:17 -0700 |
parents | |
children | 2ef04e16f0b9 |
comparison
equal
deleted
inserted
replaced
449:30f2c2a595f5 | 450:298f8f46432a |
---|---|
1 import sys | |
2 import datetime | |
3 import collections | |
4 | |
5 | |
6 def pickle(obj): | |
7 return _pickle_object(obj) | |
8 | |
9 | |
10 def unpickle(data): | |
11 return _unpickle_object(data) | |
12 | |
13 | |
14 def _tuple_dispatch(obj, func): | |
15 res = [None] * len(obj) | |
16 for i, c in enumerate(obj): | |
17 res[i] = func(c) | |
18 return tuple(res) | |
19 | |
20 | |
21 def _list_dispatch(obj, func): | |
22 res = [None] * len(obj) | |
23 for i, c in enumerate(obj): | |
24 res[i] = func(c) | |
25 return res | |
26 | |
27 | |
28 def _dict_dispatch(obj, func): | |
29 res = {} | |
30 for k, v in obj.items(): | |
31 res[k] = func(v) | |
32 return res | |
33 | |
34 | |
35 def _set_dispatch(obj, func): | |
36 res = set() | |
37 for v in obj: | |
38 res.add(func(v)) | |
39 return res | |
40 | |
41 | |
42 _identity_dispatch = object() | |
43 | |
44 _type_dispatch = { | |
45 type(None): _identity_dispatch, | |
46 bool: _identity_dispatch, | |
47 int: _identity_dispatch, | |
48 float: _identity_dispatch, | |
49 str: _identity_dispatch, | |
50 datetime.date: _identity_dispatch, | |
51 datetime.datetime: _identity_dispatch, | |
52 datetime.time: _identity_dispatch, | |
53 tuple: _tuple_dispatch, | |
54 list: _list_dispatch, | |
55 dict: _dict_dispatch, | |
56 collections.OrderedDict: _dict_dispatch, | |
57 set: _set_dispatch | |
58 } | |
59 | |
60 | |
61 def _pickle_object(obj): | |
62 t = type(obj) | |
63 disp = _type_dispatch.get(t) | |
64 if disp is _identity_dispatch: | |
65 return obj | |
66 | |
67 if disp is not None: | |
68 return disp(obj, _pickle_object) | |
69 | |
70 if isinstance(obj, Exception): | |
71 return obj | |
72 | |
73 getter = getattr(obj, '__getstate__', None) | |
74 if getter is not None: | |
75 state = getter() | |
76 else: | |
77 state = obj.__dict__ | |
78 | |
79 state = _dict_dispatch(state, _pickle_object) | |
80 state['__class__'] = obj.__class__.__name__ | |
81 state['__module__'] = obj.__class__.__module__ | |
82 | |
83 return state | |
84 | |
85 | |
86 def _unpickle_object(state): | |
87 t = type(state) | |
88 disp = _type_dispatch.get(t) | |
89 if disp is _identity_dispatch: | |
90 return state | |
91 | |
92 if (disp is not None and | |
93 (t != dict or '__module__' not in state)): | |
94 return disp(state, _unpickle_object) | |
95 | |
96 if isinstance(state, Exception): | |
97 return state | |
98 | |
99 mod_name = state['__module__'] | |
100 mod = sys.modules[mod_name] | |
101 class_name = state['__class__'] | |
102 class_def = getattr(mod, class_name) | |
103 obj = class_def.__new__(class_def) | |
104 | |
105 del state['__class__'] | |
106 del state['__module__'] | |
107 attr_names = list(state.keys()) | |
108 for name in attr_names: | |
109 state[name] = _unpickle_object(state[name]) | |
110 | |
111 obj.__dict__.update(state) | |
112 | |
113 return obj | |
114 |