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=[]):
168 """Deep copy operation on arbitrary Python objects.
170 See the module's __doc__ string for more info.
177 y = memo.get(d, _nil)
183 copier = _deepcopy_dispatch.get(cls)
188 issc = issubclass(cls, type)
189 except TypeError: # cls is not a class (old Boost; see SF #502085)
192 y = _deepcopy_atomic(x, memo)
194 copier = getattr(x, "__deepcopy__", None)
198 reductor = dispatch_table.get(cls)
202 reductor = getattr(x, "__reduce_ex__", None)
206 reductor = getattr(x, "__reduce__", None)
211 "un(deep)copyable object of type %s" % cls)
212 y = _reconstruct(x, rv, 1, memo)
215 _keep_alive(x, memo) # Make sure x lives at least as long as d
218 _deepcopy_dispatch = d = {}
220 def _deepcopy_atomic(x, memo):
222 d[type(None)] = _deepcopy_atomic
223 d[int] = _deepcopy_atomic
224 d[long] = _deepcopy_atomic
225 d[float] = _deepcopy_atomic
226 d[bool] = _deepcopy_atomic
228 d[complex] = _deepcopy_atomic
231 d[str] = _deepcopy_atomic
233 d[unicode] = _deepcopy_atomic
237 d[types.CodeType] = _deepcopy_atomic
238 except AttributeError:
240 d[type] = _deepcopy_atomic
241 d[xrange] = _deepcopy_atomic
242 d[types.ClassType] = _deepcopy_atomic
243 d[types.BuiltinFunctionType] = _deepcopy_atomic
244 d[types.FunctionType] = _deepcopy_atomic
246 def _deepcopy_list(x, memo):
250 y.append(deepcopy(a, memo))
252 d[list] = _deepcopy_list
254 def _deepcopy_tuple(x, memo):
257 y.append(deepcopy(a, memo))
263 for i in range(len(x)):
271 d[tuple] = _deepcopy_tuple
273 def _deepcopy_dict(x, memo):
276 for key, value in x.iteritems():
277 y[deepcopy(key, memo)] = deepcopy(value, memo)
279 d[dict] = _deepcopy_dict
280 if PyStringMap is not None:
281 d[PyStringMap] = _deepcopy_dict
283 def _keep_alive(x, memo):
284 """Keeps a reference to the object x in the memo.
286 Because we remember objects by their id, we have
287 to assure that possibly temporary objects are kept
288 alive by referencing them.
289 We store a reference at the id of the memo, which should
290 normally not be used unless someone tries to deepcopy
294 memo[id(memo)].append(x)
296 # aha, this is the first one :-)
299 def _deepcopy_inst(x, memo):
300 if hasattr(x, '__deepcopy__'):
301 return x.__deepcopy__(memo)
302 if hasattr(x, '__getinitargs__'):
303 args = x.__getinitargs__()
304 args = deepcopy(args, memo)
305 y = x.__class__(*args)
308 y.__class__ = x.__class__
310 if hasattr(x, '__getstate__'):
311 state = x.__getstate__()
314 state = deepcopy(state, memo)
315 if hasattr(y, '__setstate__'):
316 y.__setstate__(state)
318 y.__dict__.update(state)
320 d[types.InstanceType] = _deepcopy_inst
322 def _reconstruct(x, info, deep, memo=None):
323 if isinstance(info, str):
325 assert isinstance(info, tuple)
329 assert n in (2, 3, 4, 5)
330 callable, args = info[:2]
344 args = deepcopy(args, memo)
347 if listiter is not None:
348 for item in listiter:
350 item = deepcopy(item, memo)
352 if dictiter is not None:
353 for key, value in dictiter:
355 key = deepcopy(key, memo)
356 value = deepcopy(value, memo)
360 state = deepcopy(state, memo)
361 if hasattr(y, '__setstate__'):
362 y.__setstate__(state)
364 if isinstance(state, tuple) and len(state) == 2:
365 state, slotstate = state
368 if state is not None:
369 y.__dict__.update(state)
370 if slotstate is not None:
371 for key, value in slotstate.iteritems():
372 setattr(y, key, value)
379 # Helper for instance creation without calling __init__
384 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
385 {'abc': 'ABC'}, (), [], {}]
393 def __init__(self, arg=None):
396 if __name__ == '__main__':
403 def __getstate__(self):
404 return {'a': self.a, 'arg': self.arg}
405 def __setstate__(self, state):
406 for key, value in state.iteritems():
407 setattr(self, key, value)
408 def __deepcopy__(self, memo=None):
409 new = self.__class__(deepcopy(self.arg, memo))
412 c = C('argument sketch')
422 l.append({l[1]: l, 'xyz': l[2]})
425 print map(repr.repr, l)
426 print map(repr.repr, l1)
427 print map(repr.repr, l2)
428 print map(repr.repr, l3)
431 print map(repr.repr, l)
432 print map(repr.repr, l1)
433 print map(repr.repr, l2)
434 print map(repr.repr, l3)
436 if __name__ == '__main__':