1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
24 Generic (shallow and deep) copying operations.
30 x = copy.copy(y) # make a shallow copy of y
31 x = copy.deepcopy(y) # make a deep copy of y
33 For module specific errors, copy.Error is raised.
35 The difference between shallow and deep copying is only relevant for
36 compound objects (objects that contain other objects, like lists or
39 - A shallow copy constructs a new compound object and then (to the
40 extent possible) inserts *the same objects* into it that the
43 - A deep copy constructs a new compound object and then, recursively,
44 inserts *copies* into it of the objects found in the original.
46 Two problems often exist with deep copy operations that don't exist
47 with shallow copy operations:
49 a) recursive objects (compound objects that, directly or indirectly,
50 contain a reference to themselves) may cause a recursive loop
52 b) because deep copy copies *everything* it may copy too much, e.g.
53 administrative data structures that should be shared even between
56 Python's deep copy operation avoids these problems by:
58 a) keeping a table of objects already copied during the current
61 b) letting user-defined classes override the copying operation or the
62 set of components copied
64 This version does not copy types like module, class, function, method,
65 nor stack trace, stack frame, nor file, socket, window, nor array, nor
68 Classes can use the same interfaces to control copying that they use
69 to control pickling: they can define methods called __getinitargs__(),
70 __getstate__() and __setstate__(). See the documentation for module
71 "pickle" for information on these methods.
75 from copy_reg import dispatch_table
77 class Error(Exception):
79 error = Error # backward compatibility
82 from org.python.core import PyStringMap
86 __all__ = ["Error", "copy", "deepcopy"]
89 """Shallow copy operation on arbitrary Python objects.
91 See the module's __doc__ string for more info.
96 copier = _copy_dispatch.get(cls)
100 copier = getattr(cls, "__copy__", None)
104 reductor = dispatch_table.get(cls)
108 reductor = getattr(x, "__reduce_ex__", None)
112 reductor = getattr(x, "__reduce__", None)
116 raise Error("un(shallow)copyable object of type %s" % cls)
118 return _reconstruct(x, rv, 0)
121 _copy_dispatch = d = {}
123 def _copy_immutable(x):
125 for t in (type(None), int, long, float, bool, str, tuple,
126 frozenset, type, xrange, types.ClassType,
127 types.BuiltinFunctionType,
129 d[t] = _copy_immutable
130 for name in ("ComplexType", "UnicodeType", "CodeType"):
131 t = getattr(types, name, None)
133 d[t] = _copy_immutable
135 def _copy_with_constructor(x):
137 for t in (list, dict, set):
138 d[t] = _copy_with_constructor
140 def _copy_with_copy_method(x):
142 if PyStringMap is not None:
143 d[PyStringMap] = _copy_with_copy_method
146 if hasattr(x, '__copy__'):
148 if hasattr(x, '__getinitargs__'):
149 args = x.__getinitargs__()
150 y = x.__class__(*args)
153 y.__class__ = x.__class__
154 if hasattr(x, '__getstate__'):
155 state = x.__getstate__()
158 if hasattr(y, '__setstate__'):
159 y.__setstate__(state)
161 y.__dict__.update(state)
163 d[types.InstanceType] = _copy_inst
167 def deepcopy(x, memo=None, _nil=None):
168 """Deep copy operation on arbitrary Python objects.
170 See the module's __doc__ string for more info.
179 y = memo.get(d, _nil)
185 copier = _deepcopy_dispatch.get(cls)
190 issc = issubclass(cls, type)
191 except TypeError: # cls is not a class (old Boost; see SF #502085)
194 y = _deepcopy_atomic(x, memo)
196 copier = getattr(x, "__deepcopy__", None)
200 reductor = dispatch_table.get(cls)
204 reductor = getattr(x, "__reduce_ex__", None)
208 reductor = getattr(x, "__reduce__", None)
213 "un(deep)copyable object of type %s" % cls)
214 y = _reconstruct(x, rv, 1, memo)
217 _keep_alive(x, memo) # Make sure x lives at least as long as d
220 _deepcopy_dispatch = d = {}
222 def _deepcopy_atomic(x, memo):
224 d[type(None)] = _deepcopy_atomic
225 d[int] = _deepcopy_atomic
226 d[long] = _deepcopy_atomic
227 d[float] = _deepcopy_atomic
228 d[bool] = _deepcopy_atomic
230 d[complex] = _deepcopy_atomic
233 d[str] = _deepcopy_atomic
235 d[unicode] = _deepcopy_atomic
239 d[types.CodeType] = _deepcopy_atomic
240 except AttributeError:
242 d[type] = _deepcopy_atomic
243 d[xrange] = _deepcopy_atomic
244 d[types.ClassType] = _deepcopy_atomic
245 d[types.BuiltinFunctionType] = _deepcopy_atomic
246 d[types.FunctionType] = _deepcopy_atomic
248 def _deepcopy_list(x, memo):
252 y.append(deepcopy(a, memo))
254 d[list] = _deepcopy_list
256 def _deepcopy_tuple(x, memo):
259 y.append(deepcopy(a, memo))
265 for i in range(len(x)):
273 d[tuple] = _deepcopy_tuple
275 def _deepcopy_dict(x, memo):
278 for key, value in x.iteritems():
279 y[deepcopy(key, memo)] = deepcopy(value, memo)
281 d[dict] = _deepcopy_dict
282 if PyStringMap is not None:
283 d[PyStringMap] = _deepcopy_dict
285 def _keep_alive(x, memo):
286 """Keeps a reference to the object x in the memo.
288 Because we remember objects by their id, we have
289 to assure that possibly temporary objects are kept
290 alive by referencing them.
291 We store a reference at the id of the memo, which should
292 normally not be used unless someone tries to deepcopy
296 memo[id(memo)].append(x)
298 # aha, this is the first one :-)
301 def _deepcopy_inst(x, memo):
302 if hasattr(x, '__deepcopy__'):
303 return x.__deepcopy__(memo)
304 if hasattr(x, '__getinitargs__'):
305 args = x.__getinitargs__()
306 args = deepcopy(args, memo)
307 y = x.__class__(*args)
310 y.__class__ = x.__class__
312 if hasattr(x, '__getstate__'):
313 state = x.__getstate__()
316 state = deepcopy(state, memo)
317 if hasattr(y, '__setstate__'):
318 y.__setstate__(state)
320 y.__dict__.update(state)
322 d[types.InstanceType] = _deepcopy_inst
324 def _reconstruct(x, info, deep, memo=None):
325 if isinstance(info, str):
327 assert isinstance(info, tuple)
331 assert n in (2, 3, 4, 5)
332 callable, args = info[:2]
346 args = deepcopy(args, memo)
349 if listiter is not None:
350 for item in listiter:
352 item = deepcopy(item, memo)
354 if dictiter is not None:
355 for key, value in dictiter:
357 key = deepcopy(key, memo)
358 value = deepcopy(value, memo)
362 state = deepcopy(state, memo)
363 if hasattr(y, '__setstate__'):
364 y.__setstate__(state)
366 if isinstance(state, tuple) and len(state) == 2:
367 state, slotstate = state
370 if state is not None:
371 y.__dict__.update(state)
372 if slotstate is not None:
373 for key, value in slotstate.iteritems():
374 setattr(y, key, value)
381 # Helper for instance creation without calling __init__
386 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
387 {'abc': 'ABC'}, (), [], {}]
395 def __init__(self, arg=None):
398 if __name__ == '__main__':
405 def __getstate__(self):
406 return {'a': self.a, 'arg': self.arg}
407 def __setstate__(self, state):
408 for key, value in state.iteritems():
409 setattr(self, key, value)
410 def __deepcopy__(self, memo=None):
411 new = self.__class__(deepcopy(self.arg, memo))
414 c = C('argument sketch')
424 l.append({l[1]: l, 'xyz': l[2]})
427 print map(repr.repr, l)
428 print map(repr.repr, l1)
429 print map(repr.repr, l2)
430 print map(repr.repr, l3)
433 print map(repr.repr, l)
434 print map(repr.repr, l1)
435 print map(repr.repr, l2)
436 print map(repr.repr, l3)
438 if __name__ == '__main__':