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