github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/copy.py (about)

     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  from '__go__/grumpy' import WeakRefType
    52  import types
    53  #from copy_reg import dispatch_table
    54  import copy_reg
    55  dispatch_table = copy_reg.dispatch_table
    56  # Import directly from grumpy to avoid circular imports with weakref module.
    57  
    58  class Error(Exception):
    59      pass
    60  error = Error   # backward compatibility
    61  
    62  #try:
    63  #    from org.python.core import PyStringMap
    64  #except ImportError:
    65  PyStringMap = None
    66  
    67  __all__ = ["Error", "copy", "deepcopy"]
    68  
    69  def copy(x):
    70      """Shallow copy operation on arbitrary Python objects.
    71  
    72      See the module's __doc__ string for more info.
    73      """
    74  
    75      cls = type(x)
    76  
    77      copier = _copy_dispatch.get(cls)
    78      if copier:
    79          return copier(x)
    80  
    81      copier = getattr(cls, "__copy__", None)
    82      if copier:
    83          return copier(x)
    84  
    85      reductor = dispatch_table.get(cls)
    86      if reductor:
    87          rv = reductor(x)
    88      else:
    89          reductor = getattr(x, "__reduce_ex__", None)
    90          if reductor:
    91              rv = reductor(2)
    92          else:
    93              reductor = getattr(x, "__reduce__", None)
    94              if reductor:
    95                  rv = reductor()
    96              else:
    97                  raise Error("un(shallow)copyable object of type %s" % cls)
    98  
    99      return _reconstruct(x, rv, 0)
   100  
   101  
   102  _copy_dispatch = d = {}
   103  
   104  def _copy_immutable(x):
   105      return x
   106  for t in (type(None), int, float, bool, str, tuple, long,
   107            type, xrange, frozenset,  #types.ClassType
   108            types.BuiltinFunctionType,  # type(Ellipsis),
   109            types.FunctionType, WeakRefType):
   110      d[t] = _copy_immutable
   111  for name in ("ComplexType", "UnicodeType", "CodeType"):
   112      t = getattr(types, name, None)
   113      if t is not None:
   114          d[t] = _copy_immutable
   115  
   116  def _copy_with_constructor(x):
   117      return type(x)(x)
   118  for t in (list, dict):  # , set
   119      d[t] = _copy_with_constructor
   120  
   121  def _copy_with_copy_method(x):
   122      return x.copy()
   123  if PyStringMap is not None:
   124      d[PyStringMap] = _copy_with_copy_method
   125  
   126  #def _copy_inst(x):
   127  #    if hasattr(x, '__copy__'):
   128  #        return x.__copy__()
   129  #    if hasattr(x, '__getinitargs__'):
   130  #        args = x.__getinitargs__()
   131  #        y = x.__class__(*args)
   132  #    else:
   133  #        y = _EmptyClass()
   134  #        y.__class__ = x.__class__
   135  #    if hasattr(x, '__getstate__'):
   136  #        state = x.__getstate__()
   137  #    else:
   138  #        state = x.__dict__
   139  #    if hasattr(y, '__setstate__'):
   140  #        y.__setstate__(state)
   141  #    else:
   142  #        y.__dict__.update(state)
   143  #    return y
   144  #d[types.InstanceType] = _copy_inst
   145  
   146  del d
   147  
   148  def deepcopy(x, memo=None, _nil=[]):
   149      """Deep copy operation on arbitrary Python objects.
   150  
   151      See the module's __doc__ string for more info.
   152      """
   153  
   154      if memo is None:
   155          memo = {}
   156  
   157      d = id(x)
   158      y = memo.get(d, _nil)
   159      if y is not _nil:
   160          return y
   161  
   162      cls = type(x)
   163  
   164      copier = _deepcopy_dispatch.get(cls)
   165      if copier:
   166          y = copier(x, memo)
   167      else:
   168          try:
   169              issc = issubclass(cls, type)
   170          except TypeError: # cls is not a class (old Boost; see SF #502085)
   171              issc = 0
   172          if issc:
   173              y = _deepcopy_atomic(x, memo)
   174          else:
   175              copier = getattr(x, "__deepcopy__", None)
   176              if copier:
   177                  y = copier(memo)
   178              else:
   179                  reductor = dispatch_table.get(cls)
   180                  if reductor:
   181                      rv = reductor(x)
   182                  else:
   183                      reductor = getattr(x, "__reduce_ex__", None)
   184                      if reductor:
   185                          rv = reductor(2)
   186                      else:
   187                          reductor = getattr(x, "__reduce__", None)
   188                          if reductor:
   189                              rv = reductor()
   190                          else:
   191                              raise Error(
   192                                  "un(deep)copyable object of type %s" % cls)
   193                  y = _reconstruct(x, rv, 1, memo)
   194  
   195      memo[d] = y
   196      _keep_alive(x, memo) # Make sure x lives at least as long as d
   197      return y
   198  
   199  _deepcopy_dispatch = d = {}
   200  
   201  def _deepcopy_atomic(x, memo):
   202      return x
   203  d[type(None)] = _deepcopy_atomic
   204  #d[type(Ellipsis)] = _deepcopy_atomic
   205  d[int] = _deepcopy_atomic
   206  d[long] = _deepcopy_atomic
   207  d[float] = _deepcopy_atomic
   208  d[bool] = _deepcopy_atomic
   209  try:
   210      d[complex] = _deepcopy_atomic
   211  except NameError:
   212      pass
   213  d[str] = _deepcopy_atomic
   214  try:
   215      d[unicode] = _deepcopy_atomic
   216  except NameError:
   217      pass
   218  try:
   219      d[types.CodeType] = _deepcopy_atomic
   220  except AttributeError:
   221      pass
   222  d[type] = _deepcopy_atomic
   223  d[xrange] = _deepcopy_atomic
   224  #d[types.ClassType] = _deepcopy_atomic
   225  d[types.BuiltinFunctionType] = _deepcopy_atomic
   226  d[types.FunctionType] = _deepcopy_atomic
   227  d[WeakRefType] = _deepcopy_atomic
   228  
   229  def _deepcopy_list(x, memo):
   230      y = []
   231      memo[id(x)] = y
   232      for a in x:
   233          y.append(deepcopy(a, memo))
   234      return y
   235  d[list] = _deepcopy_list
   236  
   237  def _deepcopy_tuple(x, memo):
   238      y = []
   239      for a in x:
   240          y.append(deepcopy(a, memo))
   241      d = id(x)
   242      try:
   243          return memo[d]
   244      except KeyError:
   245          pass
   246      for i in range(len(x)):
   247          if x[i] is not y[i]:
   248              y = tuple(y)
   249              break
   250      else:
   251          y = x
   252      memo[d] = y
   253      return y
   254  d[tuple] = _deepcopy_tuple
   255  
   256  def _deepcopy_dict(x, memo):
   257      y = {}
   258      memo[id(x)] = y
   259      for key, value in x.iteritems():
   260          y[deepcopy(key, memo)] = deepcopy(value, memo)
   261      return y
   262  d[dict] = _deepcopy_dict
   263  if PyStringMap is not None:
   264      d[PyStringMap] = _deepcopy_dict
   265  
   266  def _deepcopy_method(x, memo): # Copy instance methods
   267      return type(x)(x.im_func, deepcopy(x.im_self, memo), x.im_class)
   268  _deepcopy_dispatch[types.MethodType] = _deepcopy_method
   269  
   270  def _keep_alive(x, memo):
   271      """Keeps a reference to the object x in the memo.
   272  
   273      Because we remember objects by their id, we have
   274      to assure that possibly temporary objects are kept
   275      alive by referencing them.
   276      We store a reference at the id of the memo, which should
   277      normally not be used unless someone tries to deepcopy
   278      the memo itself...
   279      """
   280      try:
   281          memo[id(memo)].append(x)
   282      except KeyError:
   283          # aha, this is the first one :-)
   284          memo[id(memo)]=[x]
   285  
   286  #def _deepcopy_inst(x, memo):
   287  #    if hasattr(x, '__deepcopy__'):
   288  #        return x.__deepcopy__(memo)
   289  #    if hasattr(x, '__getinitargs__'):
   290  #        args = x.__getinitargs__()
   291  #        args = deepcopy(args, memo)
   292  #        y = x.__class__(*args)
   293  #    else:
   294  #        y = _EmptyClass()
   295  #        y.__class__ = x.__class__
   296  #    memo[id(x)] = y
   297  #    if hasattr(x, '__getstate__'):
   298  #        state = x.__getstate__()
   299  #    else:
   300  #        state = x.__dict__
   301  #    state = deepcopy(state, memo)
   302  #    if hasattr(y, '__setstate__'):
   303  #        y.__setstate__(state)
   304  #    else:
   305  #        y.__dict__.update(state)
   306  #    return y
   307  #d[types.InstanceType] = _deepcopy_inst
   308  
   309  def _reconstruct(x, info, deep, memo=None):
   310      if isinstance(info, str):
   311          return x
   312      assert isinstance(info, tuple)
   313      if memo is None:
   314          memo = {}
   315      n = len(info)
   316      assert n in (2, 3, 4, 5)
   317      callable, args = info[:2]
   318      if n > 2:
   319          state = info[2]
   320      else:
   321          state = None
   322      if n > 3:
   323          listiter = info[3]
   324      else:
   325          listiter = None
   326      if n > 4:
   327          dictiter = info[4]
   328      else:
   329          dictiter = None
   330      if deep:
   331          args = deepcopy(args, memo)
   332      y = callable(*args)
   333      memo[id(x)] = y
   334  
   335      if state is not None:
   336          if deep:
   337              state = deepcopy(state, memo)
   338          if hasattr(y, '__setstate__'):
   339              y.__setstate__(state)
   340          else:
   341              if isinstance(state, tuple) and len(state) == 2:
   342                  state, slotstate = state
   343              else:
   344                  slotstate = None
   345              if state is not None:
   346                  y.__dict__.update(state)
   347              if slotstate is not None:
   348                  for key, value in slotstate.iteritems():
   349                      setattr(y, key, value)
   350  
   351      if listiter is not None:
   352          for item in listiter:
   353              if deep:
   354                  item = deepcopy(item, memo)
   355              y.append(item)
   356      if dictiter is not None:
   357          for key, value in dictiter:
   358              if deep:
   359                  key = deepcopy(key, memo)
   360                  value = deepcopy(value, memo)
   361              y[key] = value
   362      return y
   363  
   364  del d
   365  
   366  del types
   367  
   368  # Helper for instance creation without calling __init__
   369  #class _EmptyClass:
   370  #    pass
   371  
   372  def _test():
   373      #l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
   374      l = [None, 1, 3.14, 'xyzzy', (1,), [3.14, 'abc'],
   375           {'abc': 'ABC'}, (), [], {}]
   376      l1 = copy(l)
   377      print l1==l
   378      l1 = map(copy, l)
   379      print l1==l
   380      l1 = deepcopy(l)
   381      print l1==l
   382      class C:
   383          def __init__(self, arg=None):
   384              self.a = 1
   385              self.arg = arg
   386              if __name__ == '__main__':
   387                  import sys
   388                  file = sys.argv[0]
   389              else:
   390                  file = __file__
   391              self.fp = open(file)
   392              self.fp.close()
   393          def __getstate__(self):
   394              return {'a': self.a, 'arg': self.arg}
   395          def __setstate__(self, state):
   396              for key, value in state.iteritems():
   397                  setattr(self, key, value)
   398          def __deepcopy__(self, memo=None):
   399              new = self.__class__(deepcopy(self.arg, memo))
   400              new.a = self.a
   401              return new
   402      c = C('argument sketch')
   403      l.append(c)
   404      l2 = copy(l)
   405      print l == l2
   406      print l
   407      print l2
   408      l2 = deepcopy(l)
   409      print l == l2
   410      print l
   411      print l2
   412      l.append({l[1]: l, 'xyz': l[2]})
   413      l3 = copy(l)
   414      import repr
   415      print map(repr.repr, l)
   416      print map(repr.repr, l1)
   417      print map(repr.repr, l2)
   418      print map(repr.repr, l3)
   419      l3 = deepcopy(l)
   420      import repr
   421      print map(repr.repr, l)
   422      print map(repr.repr, l1)
   423      print map(repr.repr, l2)
   424      print map(repr.repr, l3)
   425      class odict(dict):
   426          def __init__(self, d = {}):
   427              self.a = 99
   428              dict.__init__(self, d)
   429          def __setitem__(self, k, i):
   430              dict.__setitem__(self, k, i)
   431              self.a
   432      o = odict({"A" : "B"})
   433      x = deepcopy(o)
   434      print(o, x)
   435  
   436  if __name__ == '__main__':
   437      _test()