17db96d56Sopenharmony_ci"""Generic (shallow and deep) copying operations.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciInterface summary:
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci        import copy
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci        x = copy.copy(y)        # make a shallow copy of y
87db96d56Sopenharmony_ci        x = copy.deepcopy(y)    # make a deep copy of y
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ciFor module specific errors, copy.Error is raised.
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciThe difference between shallow and deep copying is only relevant for
137db96d56Sopenharmony_cicompound objects (objects that contain other objects, like lists or
147db96d56Sopenharmony_ciclass instances).
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci- A shallow copy constructs a new compound object and then (to the
177db96d56Sopenharmony_ci  extent possible) inserts *the same objects* into it that the
187db96d56Sopenharmony_ci  original contains.
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci- A deep copy constructs a new compound object and then, recursively,
217db96d56Sopenharmony_ci  inserts *copies* into it of the objects found in the original.
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ciTwo problems often exist with deep copy operations that don't exist
247db96d56Sopenharmony_ciwith shallow copy operations:
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci a) recursive objects (compound objects that, directly or indirectly,
277db96d56Sopenharmony_ci    contain a reference to themselves) may cause a recursive loop
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci b) because deep copy copies *everything* it may copy too much, e.g.
307db96d56Sopenharmony_ci    administrative data structures that should be shared even between
317db96d56Sopenharmony_ci    copies
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ciPython's deep copy operation avoids these problems by:
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci a) keeping a table of objects already copied during the current
367db96d56Sopenharmony_ci    copying pass
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci b) letting user-defined classes override the copying operation or the
397db96d56Sopenharmony_ci    set of components copied
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ciThis version does not copy types like module, class, function, method,
427db96d56Sopenharmony_cinor stack trace, stack frame, nor file, socket, window, nor any
437db96d56Sopenharmony_cisimilar types.
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ciClasses can use the same interfaces to control copying that they use
467db96d56Sopenharmony_cito control pickling: they can define methods called __getinitargs__(),
477db96d56Sopenharmony_ci__getstate__() and __setstate__().  See the documentation for module
487db96d56Sopenharmony_ci"pickle" for information on these methods.
497db96d56Sopenharmony_ci"""
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ciimport types
527db96d56Sopenharmony_ciimport weakref
537db96d56Sopenharmony_cifrom copyreg import dispatch_table
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ciclass Error(Exception):
567db96d56Sopenharmony_ci    pass
577db96d56Sopenharmony_cierror = Error   # backward compatibility
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_citry:
607db96d56Sopenharmony_ci    from org.python.core import PyStringMap
617db96d56Sopenharmony_ciexcept ImportError:
627db96d56Sopenharmony_ci    PyStringMap = None
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci__all__ = ["Error", "copy", "deepcopy"]
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_cidef copy(x):
677db96d56Sopenharmony_ci    """Shallow copy operation on arbitrary Python objects.
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci    See the module's __doc__ string for more info.
707db96d56Sopenharmony_ci    """
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci    cls = type(x)
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    copier = _copy_dispatch.get(cls)
757db96d56Sopenharmony_ci    if copier:
767db96d56Sopenharmony_ci        return copier(x)
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci    if issubclass(cls, type):
797db96d56Sopenharmony_ci        # treat it as a regular class:
807db96d56Sopenharmony_ci        return _copy_immutable(x)
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci    copier = getattr(cls, "__copy__", None)
837db96d56Sopenharmony_ci    if copier is not None:
847db96d56Sopenharmony_ci        return copier(x)
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci    reductor = dispatch_table.get(cls)
877db96d56Sopenharmony_ci    if reductor is not None:
887db96d56Sopenharmony_ci        rv = reductor(x)
897db96d56Sopenharmony_ci    else:
907db96d56Sopenharmony_ci        reductor = getattr(x, "__reduce_ex__", None)
917db96d56Sopenharmony_ci        if reductor is not None:
927db96d56Sopenharmony_ci            rv = reductor(4)
937db96d56Sopenharmony_ci        else:
947db96d56Sopenharmony_ci            reductor = getattr(x, "__reduce__", None)
957db96d56Sopenharmony_ci            if reductor:
967db96d56Sopenharmony_ci                rv = reductor()
977db96d56Sopenharmony_ci            else:
987db96d56Sopenharmony_ci                raise Error("un(shallow)copyable object of type %s" % cls)
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci    if isinstance(rv, str):
1017db96d56Sopenharmony_ci        return x
1027db96d56Sopenharmony_ci    return _reconstruct(x, None, *rv)
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci_copy_dispatch = d = {}
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_cidef _copy_immutable(x):
1087db96d56Sopenharmony_ci    return x
1097db96d56Sopenharmony_cifor t in (type(None), int, float, bool, complex, str, tuple,
1107db96d56Sopenharmony_ci          bytes, frozenset, type, range, slice, property,
1117db96d56Sopenharmony_ci          types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
1127db96d56Sopenharmony_ci          types.FunctionType, weakref.ref):
1137db96d56Sopenharmony_ci    d[t] = _copy_immutable
1147db96d56Sopenharmony_cit = getattr(types, "CodeType", None)
1157db96d56Sopenharmony_ciif t is not None:
1167db96d56Sopenharmony_ci    d[t] = _copy_immutable
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_cid[list] = list.copy
1197db96d56Sopenharmony_cid[dict] = dict.copy
1207db96d56Sopenharmony_cid[set] = set.copy
1217db96d56Sopenharmony_cid[bytearray] = bytearray.copy
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciif PyStringMap is not None:
1247db96d56Sopenharmony_ci    d[PyStringMap] = PyStringMap.copy
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_cidel d, t
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_cidef deepcopy(x, memo=None, _nil=[]):
1297db96d56Sopenharmony_ci    """Deep copy operation on arbitrary Python objects.
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci    See the module's __doc__ string for more info.
1327db96d56Sopenharmony_ci    """
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci    if memo is None:
1357db96d56Sopenharmony_ci        memo = {}
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci    d = id(x)
1387db96d56Sopenharmony_ci    y = memo.get(d, _nil)
1397db96d56Sopenharmony_ci    if y is not _nil:
1407db96d56Sopenharmony_ci        return y
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci    cls = type(x)
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci    copier = _deepcopy_dispatch.get(cls)
1457db96d56Sopenharmony_ci    if copier is not None:
1467db96d56Sopenharmony_ci        y = copier(x, memo)
1477db96d56Sopenharmony_ci    else:
1487db96d56Sopenharmony_ci        if issubclass(cls, type):
1497db96d56Sopenharmony_ci            y = _deepcopy_atomic(x, memo)
1507db96d56Sopenharmony_ci        else:
1517db96d56Sopenharmony_ci            copier = getattr(x, "__deepcopy__", None)
1527db96d56Sopenharmony_ci            if copier is not None:
1537db96d56Sopenharmony_ci                y = copier(memo)
1547db96d56Sopenharmony_ci            else:
1557db96d56Sopenharmony_ci                reductor = dispatch_table.get(cls)
1567db96d56Sopenharmony_ci                if reductor:
1577db96d56Sopenharmony_ci                    rv = reductor(x)
1587db96d56Sopenharmony_ci                else:
1597db96d56Sopenharmony_ci                    reductor = getattr(x, "__reduce_ex__", None)
1607db96d56Sopenharmony_ci                    if reductor is not None:
1617db96d56Sopenharmony_ci                        rv = reductor(4)
1627db96d56Sopenharmony_ci                    else:
1637db96d56Sopenharmony_ci                        reductor = getattr(x, "__reduce__", None)
1647db96d56Sopenharmony_ci                        if reductor:
1657db96d56Sopenharmony_ci                            rv = reductor()
1667db96d56Sopenharmony_ci                        else:
1677db96d56Sopenharmony_ci                            raise Error(
1687db96d56Sopenharmony_ci                                "un(deep)copyable object of type %s" % cls)
1697db96d56Sopenharmony_ci                if isinstance(rv, str):
1707db96d56Sopenharmony_ci                    y = x
1717db96d56Sopenharmony_ci                else:
1727db96d56Sopenharmony_ci                    y = _reconstruct(x, memo, *rv)
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    # If is its own copy, don't memoize.
1757db96d56Sopenharmony_ci    if y is not x:
1767db96d56Sopenharmony_ci        memo[d] = y
1777db96d56Sopenharmony_ci        _keep_alive(x, memo) # Make sure x lives at least as long as d
1787db96d56Sopenharmony_ci    return y
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci_deepcopy_dispatch = d = {}
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_cidef _deepcopy_atomic(x, memo):
1837db96d56Sopenharmony_ci    return x
1847db96d56Sopenharmony_cid[type(None)] = _deepcopy_atomic
1857db96d56Sopenharmony_cid[type(Ellipsis)] = _deepcopy_atomic
1867db96d56Sopenharmony_cid[type(NotImplemented)] = _deepcopy_atomic
1877db96d56Sopenharmony_cid[int] = _deepcopy_atomic
1887db96d56Sopenharmony_cid[float] = _deepcopy_atomic
1897db96d56Sopenharmony_cid[bool] = _deepcopy_atomic
1907db96d56Sopenharmony_cid[complex] = _deepcopy_atomic
1917db96d56Sopenharmony_cid[bytes] = _deepcopy_atomic
1927db96d56Sopenharmony_cid[str] = _deepcopy_atomic
1937db96d56Sopenharmony_cid[types.CodeType] = _deepcopy_atomic
1947db96d56Sopenharmony_cid[type] = _deepcopy_atomic
1957db96d56Sopenharmony_cid[range] = _deepcopy_atomic
1967db96d56Sopenharmony_cid[types.BuiltinFunctionType] = _deepcopy_atomic
1977db96d56Sopenharmony_cid[types.FunctionType] = _deepcopy_atomic
1987db96d56Sopenharmony_cid[weakref.ref] = _deepcopy_atomic
1997db96d56Sopenharmony_cid[property] = _deepcopy_atomic
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_cidef _deepcopy_list(x, memo, deepcopy=deepcopy):
2027db96d56Sopenharmony_ci    y = []
2037db96d56Sopenharmony_ci    memo[id(x)] = y
2047db96d56Sopenharmony_ci    append = y.append
2057db96d56Sopenharmony_ci    for a in x:
2067db96d56Sopenharmony_ci        append(deepcopy(a, memo))
2077db96d56Sopenharmony_ci    return y
2087db96d56Sopenharmony_cid[list] = _deepcopy_list
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_cidef _deepcopy_tuple(x, memo, deepcopy=deepcopy):
2117db96d56Sopenharmony_ci    y = [deepcopy(a, memo) for a in x]
2127db96d56Sopenharmony_ci    # We're not going to put the tuple in the memo, but it's still important we
2137db96d56Sopenharmony_ci    # check for it, in case the tuple contains recursive mutable structures.
2147db96d56Sopenharmony_ci    try:
2157db96d56Sopenharmony_ci        return memo[id(x)]
2167db96d56Sopenharmony_ci    except KeyError:
2177db96d56Sopenharmony_ci        pass
2187db96d56Sopenharmony_ci    for k, j in zip(x, y):
2197db96d56Sopenharmony_ci        if k is not j:
2207db96d56Sopenharmony_ci            y = tuple(y)
2217db96d56Sopenharmony_ci            break
2227db96d56Sopenharmony_ci    else:
2237db96d56Sopenharmony_ci        y = x
2247db96d56Sopenharmony_ci    return y
2257db96d56Sopenharmony_cid[tuple] = _deepcopy_tuple
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_cidef _deepcopy_dict(x, memo, deepcopy=deepcopy):
2287db96d56Sopenharmony_ci    y = {}
2297db96d56Sopenharmony_ci    memo[id(x)] = y
2307db96d56Sopenharmony_ci    for key, value in x.items():
2317db96d56Sopenharmony_ci        y[deepcopy(key, memo)] = deepcopy(value, memo)
2327db96d56Sopenharmony_ci    return y
2337db96d56Sopenharmony_cid[dict] = _deepcopy_dict
2347db96d56Sopenharmony_ciif PyStringMap is not None:
2357db96d56Sopenharmony_ci    d[PyStringMap] = _deepcopy_dict
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_cidef _deepcopy_method(x, memo): # Copy instance methods
2387db96d56Sopenharmony_ci    return type(x)(x.__func__, deepcopy(x.__self__, memo))
2397db96d56Sopenharmony_cid[types.MethodType] = _deepcopy_method
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_cidel d
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_cidef _keep_alive(x, memo):
2447db96d56Sopenharmony_ci    """Keeps a reference to the object x in the memo.
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci    Because we remember objects by their id, we have
2477db96d56Sopenharmony_ci    to assure that possibly temporary objects are kept
2487db96d56Sopenharmony_ci    alive by referencing them.
2497db96d56Sopenharmony_ci    We store a reference at the id of the memo, which should
2507db96d56Sopenharmony_ci    normally not be used unless someone tries to deepcopy
2517db96d56Sopenharmony_ci    the memo itself...
2527db96d56Sopenharmony_ci    """
2537db96d56Sopenharmony_ci    try:
2547db96d56Sopenharmony_ci        memo[id(memo)].append(x)
2557db96d56Sopenharmony_ci    except KeyError:
2567db96d56Sopenharmony_ci        # aha, this is the first one :-)
2577db96d56Sopenharmony_ci        memo[id(memo)]=[x]
2587db96d56Sopenharmony_ci
2597db96d56Sopenharmony_cidef _reconstruct(x, memo, func, args,
2607db96d56Sopenharmony_ci                 state=None, listiter=None, dictiter=None,
2617db96d56Sopenharmony_ci                 *, deepcopy=deepcopy):
2627db96d56Sopenharmony_ci    deep = memo is not None
2637db96d56Sopenharmony_ci    if deep and args:
2647db96d56Sopenharmony_ci        args = (deepcopy(arg, memo) for arg in args)
2657db96d56Sopenharmony_ci    y = func(*args)
2667db96d56Sopenharmony_ci    if deep:
2677db96d56Sopenharmony_ci        memo[id(x)] = y
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci    if state is not None:
2707db96d56Sopenharmony_ci        if deep:
2717db96d56Sopenharmony_ci            state = deepcopy(state, memo)
2727db96d56Sopenharmony_ci        if hasattr(y, '__setstate__'):
2737db96d56Sopenharmony_ci            y.__setstate__(state)
2747db96d56Sopenharmony_ci        else:
2757db96d56Sopenharmony_ci            if isinstance(state, tuple) and len(state) == 2:
2767db96d56Sopenharmony_ci                state, slotstate = state
2777db96d56Sopenharmony_ci            else:
2787db96d56Sopenharmony_ci                slotstate = None
2797db96d56Sopenharmony_ci            if state is not None:
2807db96d56Sopenharmony_ci                y.__dict__.update(state)
2817db96d56Sopenharmony_ci            if slotstate is not None:
2827db96d56Sopenharmony_ci                for key, value in slotstate.items():
2837db96d56Sopenharmony_ci                    setattr(y, key, value)
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_ci    if listiter is not None:
2867db96d56Sopenharmony_ci        if deep:
2877db96d56Sopenharmony_ci            for item in listiter:
2887db96d56Sopenharmony_ci                item = deepcopy(item, memo)
2897db96d56Sopenharmony_ci                y.append(item)
2907db96d56Sopenharmony_ci        else:
2917db96d56Sopenharmony_ci            for item in listiter:
2927db96d56Sopenharmony_ci                y.append(item)
2937db96d56Sopenharmony_ci    if dictiter is not None:
2947db96d56Sopenharmony_ci        if deep:
2957db96d56Sopenharmony_ci            for key, value in dictiter:
2967db96d56Sopenharmony_ci                key = deepcopy(key, memo)
2977db96d56Sopenharmony_ci                value = deepcopy(value, memo)
2987db96d56Sopenharmony_ci                y[key] = value
2997db96d56Sopenharmony_ci        else:
3007db96d56Sopenharmony_ci            for key, value in dictiter:
3017db96d56Sopenharmony_ci                y[key] = value
3027db96d56Sopenharmony_ci    return y
3037db96d56Sopenharmony_ci
3047db96d56Sopenharmony_cidel types, weakref, PyStringMap
305