Skip to content

Commit 3ddec7f

Browse files
committed
copy: Add pristine from Python-3.3.3 tarball.
1 parent fedf90c commit 3ddec7f

File tree

1 file changed

+325
-0
lines changed

1 file changed

+325
-0
lines changed

‎copy/copy.py

+325
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
"""Generic (shallow and deep) copying operations.
2+
3+
Interface summary:
4+
5+
import copy
6+
7+
x = copy.copy(y) # make a shallow copy of y
8+
x = copy.deepcopy(y) # make a deep copy of y
9+
10+
For module specific errors, copy.Error is raised.
11+
12+
The difference between shallow and deep copying is only relevant for
13+
compound objects (objects that contain other objects, like lists or
14+
class instances).
15+
16+
- A shallow copy constructs a new compound object and then (to the
17+
extent possible) inserts *the same objects* into it that the
18+
original contains.
19+
20+
- A deep copy constructs a new compound object and then, recursively,
21+
inserts *copies* into it of the objects found in the original.
22+
23+
Two problems often exist with deep copy operations that don't exist
24+
with shallow copy operations:
25+
26+
a) recursive objects (compound objects that, directly or indirectly,
27+
contain a reference to themselves) may cause a recursive loop
28+
29+
b) because deep copy copies *everything* it may copy too much, e.g.
30+
administrative data structures that should be shared even between
31+
copies
32+
33+
Python's deep copy operation avoids these problems by:
34+
35+
a) keeping a table of objects already copied during the current
36+
copying pass
37+
38+
b) letting user-defined classes override the copying operation or the
39+
set of components copied
40+
41+
This version does not copy types like module, class, function, method,
42+
nor stack trace, stack frame, nor file, socket, window, nor array, nor
43+
any similar types.
44+
45+
Classes can use the same interfaces to control copying that they use
46+
to control pickling: they can define methods called __getinitargs__(),
47+
__getstate__() and __setstate__(). See the documentation for module
48+
"pickle" for information on these methods.
49+
"""
50+
51+
import types
52+
import weakref
53+
from copyreg import dispatch_table
54+
import builtins
55+
56+
class Error(Exception):
57+
pass
58+
error = Error # backward compatibility
59+
60+
try:
61+
from org.python.core import PyStringMap
62+
except ImportError:
63+
PyStringMap = None
64+
65+
__all__ = ["Error", "copy", "deepcopy"]
66+
67+
def copy(x):
68+
"""Shallow copy operation on arbitrary Python objects.
69+
70+
See the module's __doc__ string for more info.
71+
"""
72+
73+
cls = type(x)
74+
75+
copier = _copy_dispatch.get(cls)
76+
if copier:
77+
return copier(x)
78+
79+
copier = getattr(cls, "__copy__", None)
80+
if copier:
81+
return copier(x)
82+
83+
reductor = dispatch_table.get(cls)
84+
if reductor:
85+
rv = reductor(x)
86+
else:
87+
reductor = getattr(x, "__reduce_ex__", None)
88+
if reductor:
89+
rv = reductor(2)
90+
else:
91+
reductor = getattr(x, "__reduce__", None)
92+
if reductor:
93+
rv = reductor()
94+
else:
95+
raise Error("un(shallow)copyable object of type %s" % cls)
96+
97+
return _reconstruct(x, rv, 0)
98+
99+
100+
_copy_dispatch = d = {}
101+
102+
def _copy_immutable(x):
103+
return x
104+
for t in (type(None), int, float, bool, str, tuple,
105+
frozenset, type, range,
106+
types.BuiltinFunctionType, type(Ellipsis),
107+
types.FunctionType, weakref.ref):
108+
d[t] = _copy_immutable
109+
t = getattr(types, "CodeType", None)
110+
if t is not None:
111+
d[t] = _copy_immutable
112+
for name in ("complex", "unicode"):
113+
t = getattr(builtins, name, None)
114+
if t is not None:
115+
d[t] = _copy_immutable
116+
117+
def _copy_with_constructor(x):
118+
return type(x)(x)
119+
for t in (list, dict, set):
120+
d[t] = _copy_with_constructor
121+
122+
def _copy_with_copy_method(x):
123+
return x.copy()
124+
if PyStringMap is not None:
125+
d[PyStringMap] = _copy_with_copy_method
126+
127+
del d
128+
129+
def deepcopy(x, memo=None, _nil=[]):
130+
"""Deep copy operation on arbitrary Python objects.
131+
132+
See the module's __doc__ string for more info.
133+
"""
134+
135+
if memo is None:
136+
memo = {}
137+
138+
d = id(x)
139+
y = memo.get(d, _nil)
140+
if y is not _nil:
141+
return y
142+
143+
cls = type(x)
144+
145+
copier = _deepcopy_dispatch.get(cls)
146+
if copier:
147+
y = copier(x, memo)
148+
else:
149+
try:
150+
issc = issubclass(cls, type)
151+
except TypeError: # cls is not a class (old Boost; see SF #502085)
152+
issc = 0
153+
if issc:
154+
y = _deepcopy_atomic(x, memo)
155+
else:
156+
copier = getattr(x, "__deepcopy__", None)
157+
if copier:
158+
y = copier(memo)
159+
else:
160+
reductor = dispatch_table.get(cls)
161+
if reductor:
162+
rv = reductor(x)
163+
else:
164+
reductor = getattr(x, "__reduce_ex__", None)
165+
if reductor:
166+
rv = reductor(2)
167+
else:
168+
reductor = getattr(x, "__reduce__", None)
169+
if reductor:
170+
rv = reductor()
171+
else:
172+
raise Error(
173+
"un(deep)copyable object of type %s" % cls)
174+
y = _reconstruct(x, rv, 1, memo)
175+
176+
# If is its own copy, don't memoize.
177+
if y is not x:
178+
memo[d] = y
179+
_keep_alive(x, memo) # Make sure x lives at least as long as d
180+
return y
181+
182+
_deepcopy_dispatch = d = {}
183+
184+
def _deepcopy_atomic(x, memo):
185+
return x
186+
d[type(None)] = _deepcopy_atomic
187+
d[type(Ellipsis)] = _deepcopy_atomic
188+
d[int] = _deepcopy_atomic
189+
d[float] = _deepcopy_atomic
190+
d[bool] = _deepcopy_atomic
191+
try:
192+
d[complex] = _deepcopy_atomic
193+
except NameError:
194+
pass
195+
d[bytes] = _deepcopy_atomic
196+
d[str] = _deepcopy_atomic
197+
try:
198+
d[types.CodeType] = _deepcopy_atomic
199+
except AttributeError:
200+
pass
201+
d[type] = _deepcopy_atomic
202+
d[range] = _deepcopy_atomic
203+
d[types.BuiltinFunctionType] = _deepcopy_atomic
204+
d[types.FunctionType] = _deepcopy_atomic
205+
d[weakref.ref] = _deepcopy_atomic
206+
207+
def _deepcopy_list(x, memo):
208+
y = []
209+
memo[id(x)] = y
210+
for a in x:
211+
y.append(deepcopy(a, memo))
212+
return y
213+
d[list] = _deepcopy_list
214+
215+
def _deepcopy_tuple(x, memo):
216+
y = []
217+
for a in x:
218+
y.append(deepcopy(a, memo))
219+
# We're not going to put the tuple in the memo, but it's still important we
220+
# check for it, in case the tuple contains recursive mutable structures.
221+
try:
222+
return memo[id(x)]
223+
except KeyError:
224+
pass
225+
for i in range(len(x)):
226+
if x[i] is not y[i]:
227+
y = tuple(y)
228+
break
229+
else:
230+
y = x
231+
return y
232+
d[tuple] = _deepcopy_tuple
233+
234+
def _deepcopy_dict(x, memo):
235+
y = {}
236+
memo[id(x)] = y
237+
for key, value in x.items():
238+
y[deepcopy(key, memo)] = deepcopy(value, memo)
239+
return y
240+
d[dict] = _deepcopy_dict
241+
if PyStringMap is not None:
242+
d[PyStringMap] = _deepcopy_dict
243+
244+
def _deepcopy_method(x, memo): # Copy instance methods
245+
return type(x)(x.__func__, deepcopy(x.__self__, memo))
246+
_deepcopy_dispatch[types.MethodType] = _deepcopy_method
247+
248+
def _keep_alive(x, memo):
249+
"""Keeps a reference to the object x in the memo.
250+
251+
Because we remember objects by their id, we have
252+
to assure that possibly temporary objects are kept
253+
alive by referencing them.
254+
We store a reference at the id of the memo, which should
255+
normally not be used unless someone tries to deepcopy
256+
the memo itself...
257+
"""
258+
try:
259+
memo[id(memo)].append(x)
260+
except KeyError:
261+
# aha, this is the first one :-)
262+
memo[id(memo)]=[x]
263+
264+
def _reconstruct(x, info, deep, memo=None):
265+
if isinstance(info, str):
266+
return x
267+
assert isinstance(info, tuple)
268+
if memo is None:
269+
memo = {}
270+
n = len(info)
271+
assert n in (2, 3, 4, 5)
272+
callable, args = info[:2]
273+
if n > 2:
274+
state = info[2]
275+
else:
276+
state = {}
277+
if n > 3:
278+
listiter = info[3]
279+
else:
280+
listiter = None
281+
if n > 4:
282+
dictiter = info[4]
283+
else:
284+
dictiter = None
285+
if deep:
286+
args = deepcopy(args, memo)
287+
y = callable(*args)
288+
memo[id(x)] = y
289+
290+
if state:
291+
if deep:
292+
state = deepcopy(state, memo)
293+
if hasattr(y, '__setstate__'):
294+
y.__setstate__(state)
295+
else:
296+
if isinstance(state, tuple) and len(state) == 2:
297+
state, slotstate = state
298+
else:
299+
slotstate = None
300+
if state is not None:
301+
y.__dict__.update(state)
302+
if slotstate is not None:
303+
for key, value in slotstate.items():
304+
setattr(y, key, value)
305+
306+
if listiter is not None:
307+
for item in listiter:
308+
if deep:
309+
item = deepcopy(item, memo)
310+
y.append(item)
311+
if dictiter is not None:
312+
for key, value in dictiter:
313+
if deep:
314+
key = deepcopy(key, memo)
315+
value = deepcopy(value, memo)
316+
y[key] = value
317+
return y
318+
319+
del d
320+
321+
del types
322+
323+
# Helper for instance creation without calling __init__
324+
class _EmptyClass:
325+
pass

0 commit comments

Comments
 (0)