]>
Commit | Line | Data |
---|---|---|
3257aa99 DM |
1 | """Helper to provide extensibility for pickle/cPickle.\r |
2 | \r | |
3 | This is only useful to add pickle support for extension types defined in\r | |
4 | C, not for instances of user-defined classes.\r | |
5 | """\r | |
6 | \r | |
7 | from types import ClassType as _ClassType\r | |
8 | \r | |
9 | __all__ = ["pickle", "constructor",\r | |
10 | "add_extension", "remove_extension", "clear_extension_cache"]\r | |
11 | \r | |
12 | dispatch_table = {}\r | |
13 | \r | |
14 | def pickle(ob_type, pickle_function, constructor_ob=None):\r | |
15 | if type(ob_type) is _ClassType:\r | |
16 | raise TypeError("copy_reg is not intended for use with classes")\r | |
17 | \r | |
18 | if not hasattr(pickle_function, '__call__'):\r | |
19 | raise TypeError("reduction functions must be callable")\r | |
20 | dispatch_table[ob_type] = pickle_function\r | |
21 | \r | |
22 | # The constructor_ob function is a vestige of safe for unpickling.\r | |
23 | # There is no reason for the caller to pass it anymore.\r | |
24 | if constructor_ob is not None:\r | |
25 | constructor(constructor_ob)\r | |
26 | \r | |
27 | def constructor(object):\r | |
28 | if not hasattr(object, '__call__'):\r | |
29 | raise TypeError("constructors must be callable")\r | |
30 | \r | |
31 | # Example: provide pickling support for complex numbers.\r | |
32 | \r | |
33 | try:\r | |
34 | complex\r | |
35 | except NameError:\r | |
36 | pass\r | |
37 | else:\r | |
38 | \r | |
39 | def pickle_complex(c):\r | |
40 | return complex, (c.real, c.imag)\r | |
41 | \r | |
42 | pickle(complex, pickle_complex, complex)\r | |
43 | \r | |
44 | # Support for pickling new-style objects\r | |
45 | \r | |
46 | def _reconstructor(cls, base, state):\r | |
47 | if base is object:\r | |
48 | obj = object.__new__(cls)\r | |
49 | else:\r | |
50 | obj = base.__new__(cls, state)\r | |
51 | if base.__init__ != object.__init__:\r | |
52 | base.__init__(obj, state)\r | |
53 | return obj\r | |
54 | \r | |
55 | _HEAPTYPE = 1<<9\r | |
56 | \r | |
57 | # Python code for object.__reduce_ex__ for protocols 0 and 1\r | |
58 | \r | |
59 | def _reduce_ex(self, proto):\r | |
60 | assert proto < 2\r | |
61 | for base in self.__class__.__mro__:\r | |
62 | if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:\r | |
63 | break\r | |
64 | else:\r | |
65 | base = object # not really reachable\r | |
66 | if base is object:\r | |
67 | state = None\r | |
68 | else:\r | |
69 | if base is self.__class__:\r | |
70 | raise TypeError, "can't pickle %s objects" % base.__name__\r | |
71 | state = base(self)\r | |
72 | args = (self.__class__, base, state)\r | |
73 | try:\r | |
74 | getstate = self.__getstate__\r | |
75 | except AttributeError:\r | |
76 | if getattr(self, "__slots__", None):\r | |
77 | raise TypeError("a class that defines __slots__ without "\r | |
78 | "defining __getstate__ cannot be pickled")\r | |
79 | try:\r | |
80 | dict = self.__dict__\r | |
81 | except AttributeError:\r | |
82 | dict = None\r | |
83 | else:\r | |
84 | dict = getstate()\r | |
85 | if dict:\r | |
86 | return _reconstructor, args, dict\r | |
87 | else:\r | |
88 | return _reconstructor, args\r | |
89 | \r | |
90 | # Helper for __reduce_ex__ protocol 2\r | |
91 | \r | |
92 | def __newobj__(cls, *args):\r | |
93 | return cls.__new__(cls, *args)\r | |
94 | \r | |
95 | def _slotnames(cls):\r | |
96 | """Return a list of slot names for a given class.\r | |
97 | \r | |
98 | This needs to find slots defined by the class and its bases, so we\r | |
99 | can't simply return the __slots__ attribute. We must walk down\r | |
100 | the Method Resolution Order and concatenate the __slots__ of each\r | |
101 | class found there. (This assumes classes don't modify their\r | |
102 | __slots__ attribute to misrepresent their slots after the class is\r | |
103 | defined.)\r | |
104 | """\r | |
105 | \r | |
106 | # Get the value from a cache in the class if possible\r | |
107 | names = cls.__dict__.get("__slotnames__")\r | |
108 | if names is not None:\r | |
109 | return names\r | |
110 | \r | |
111 | # Not cached -- calculate the value\r | |
112 | names = []\r | |
113 | if not hasattr(cls, "__slots__"):\r | |
114 | # This class has no slots\r | |
115 | pass\r | |
116 | else:\r | |
117 | # Slots found -- gather slot names from all base classes\r | |
118 | for c in cls.__mro__:\r | |
119 | if "__slots__" in c.__dict__:\r | |
120 | slots = c.__dict__['__slots__']\r | |
121 | # if class has a single slot, it can be given as a string\r | |
122 | if isinstance(slots, basestring):\r | |
123 | slots = (slots,)\r | |
124 | for name in slots:\r | |
125 | # special descriptors\r | |
126 | if name in ("__dict__", "__weakref__"):\r | |
127 | continue\r | |
128 | # mangled names\r | |
129 | elif name.startswith('__') and not name.endswith('__'):\r | |
130 | names.append('_%s%s' % (c.__name__, name))\r | |
131 | else:\r | |
132 | names.append(name)\r | |
133 | \r | |
134 | # Cache the outcome in the class if at all possible\r | |
135 | try:\r | |
136 | cls.__slotnames__ = names\r | |
137 | except:\r | |
138 | pass # But don't die if we can't\r | |
139 | \r | |
140 | return names\r | |
141 | \r | |
142 | # A registry of extension codes. This is an ad-hoc compression\r | |
143 | # mechanism. Whenever a global reference to <module>, <name> is about\r | |
144 | # to be pickled, the (<module>, <name>) tuple is looked up here to see\r | |
145 | # if it is a registered extension code for it. Extension codes are\r | |
146 | # universal, so that the meaning of a pickle does not depend on\r | |
147 | # context. (There are also some codes reserved for local use that\r | |
148 | # don't have this restriction.) Codes are positive ints; 0 is\r | |
149 | # reserved.\r | |
150 | \r | |
151 | _extension_registry = {} # key -> code\r | |
152 | _inverted_registry = {} # code -> key\r | |
153 | _extension_cache = {} # code -> object\r | |
154 | # Don't ever rebind those names: cPickle grabs a reference to them when\r | |
155 | # it's initialized, and won't see a rebinding.\r | |
156 | \r | |
157 | def add_extension(module, name, code):\r | |
158 | """Register an extension code."""\r | |
159 | code = int(code)\r | |
160 | if not 1 <= code <= 0x7fffffff:\r | |
161 | raise ValueError, "code out of range"\r | |
162 | key = (module, name)\r | |
163 | if (_extension_registry.get(key) == code and\r | |
164 | _inverted_registry.get(code) == key):\r | |
165 | return # Redundant registrations are benign\r | |
166 | if key in _extension_registry:\r | |
167 | raise ValueError("key %s is already registered with code %s" %\r | |
168 | (key, _extension_registry[key]))\r | |
169 | if code in _inverted_registry:\r | |
170 | raise ValueError("code %s is already in use for key %s" %\r | |
171 | (code, _inverted_registry[code]))\r | |
172 | _extension_registry[key] = code\r | |
173 | _inverted_registry[code] = key\r | |
174 | \r | |
175 | def remove_extension(module, name, code):\r | |
176 | """Unregister an extension code. For testing only."""\r | |
177 | key = (module, name)\r | |
178 | if (_extension_registry.get(key) != code or\r | |
179 | _inverted_registry.get(code) != key):\r | |
180 | raise ValueError("key %s is not registered with code %s" %\r | |
181 | (key, code))\r | |
182 | del _extension_registry[key]\r | |
183 | del _inverted_registry[code]\r | |
184 | if code in _extension_cache:\r | |
185 | del _extension_cache[code]\r | |
186 | \r | |
187 | def clear_extension_cache():\r | |
188 | _extension_cache.clear()\r | |
189 | \r | |
190 | # Standard extension code assignments\r | |
191 | \r | |
192 | # Reserved ranges\r | |
193 | \r | |
194 | # First Last Count Purpose\r | |
195 | # 1 127 127 Reserved for Python standard library\r | |
196 | # 128 191 64 Reserved for Zope\r | |
197 | # 192 239 48 Reserved for 3rd parties\r | |
198 | # 240 255 16 Reserved for private use (will never be assigned)\r | |
199 | # 256 Inf Inf Reserved for future assignment\r | |
200 | \r | |
201 | # Extension codes are assigned by the Python Software Foundation.\r |