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

     1  """Weak reference support for Python.
     2  
     3  This module is an implementation of PEP 205:
     4  
     5  http://www.python.org/dev/peps/pep-0205/
     6  """
     7  
     8  # Naming convention: Variables named "wr" are weak reference objects;
     9  # they are called this instead of "ref" to avoid name collisions with
    10  # the module-global ref() function imported from _weakref.
    11  
    12  import UserDict
    13  
    14  #from _weakref import (
    15  #     getweakrefcount,
    16  #     getweakrefs,
    17  #     ref,
    18  #     proxy,
    19  #     CallableProxyType,
    20  #     ProxyType,
    21  #     ReferenceType)
    22  
    23  from '__go__/grumpy' import WeakRefType as ReferenceType
    24  ref = ReferenceType
    25  
    26  import _weakrefset
    27  WeakSet = _weakrefset.WeakSet
    28  _IterationGuard = _weakrefset._IterationGuard
    29  
    30  import exceptions
    31  ReferenceError = exceptions.ReferenceError
    32  
    33  
    34  #ProxyTypes = (ProxyType, CallableProxyType)
    35  
    36  #__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
    37  #           "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
    38  #           "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
    39  
    40  
    41  class WeakValueDictionary(UserDict.UserDict):
    42      """Mapping class that references values weakly.
    43  
    44      Entries in the dictionary will be discarded when no strong
    45      reference to the value exists anymore
    46      """
    47      # We inherit the constructor without worrying about the input
    48      # dictionary; since it uses our .update() method, we get the right
    49      # checks (if the other dictionary is a WeakValueDictionary,
    50      # objects are unwrapped on the way out, and we always wrap on the
    51      # way in).
    52  
    53      def __init__(*args, **kw):
    54          if not args:
    55              raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
    56                              "object needs an argument")
    57          self = args[0]
    58          args = args[1:]
    59          if len(args) > 1:
    60              raise TypeError('expected at most 1 arguments, got %d' % len(args))
    61          def remove(wr, selfref=ref(self)):
    62              self = selfref()
    63              if self is not None:
    64                  if self._iterating:
    65                      self._pending_removals.append(wr.key)
    66                  else:
    67                      del self.data[wr.key]
    68          self._remove = remove
    69          # A list of keys to be removed
    70          self._pending_removals = []
    71          self._iterating = set()
    72          UserDict.UserDict.__init__(self, *args, **kw)
    73  
    74      def _commit_removals(self):
    75          l = self._pending_removals
    76          d = self.data
    77          # We shouldn't encounter any KeyError, because this method should
    78          # always be called *before* mutating the dict.
    79          while l:
    80              del d[l.pop()]
    81  
    82      def __getitem__(self, key):
    83          o = self.data[key]()
    84          if o is None:
    85              raise KeyError, key
    86          else:
    87              return o
    88  
    89      def __delitem__(self, key):
    90          if self._pending_removals:
    91              self._commit_removals()
    92          del self.data[key]
    93  
    94      def __contains__(self, key):
    95          try:
    96              o = self.data[key]()
    97          except KeyError:
    98              return False
    99          return o is not None
   100  
   101      def has_key(self, key):
   102          try:
   103              o = self.data[key]()
   104          except KeyError:
   105              return False
   106          return o is not None
   107  
   108      def __repr__(self):
   109          return "<WeakValueDictionary at %s>" % id(self)
   110  
   111      def __setitem__(self, key, value):
   112          if self._pending_removals:
   113              self._commit_removals()
   114          self.data[key] = KeyedRef(value, self._remove, key)
   115  
   116      def clear(self):
   117          if self._pending_removals:
   118              self._commit_removals()
   119          self.data.clear()
   120  
   121      def copy(self):
   122          new = WeakValueDictionary()
   123          for key, wr in self.data.items():
   124              o = wr()
   125              if o is not None:
   126                  new[key] = o
   127          return new
   128  
   129      __copy__ = copy
   130  
   131      def __deepcopy__(self, memo):
   132          import copy
   133          new = self.__class__()
   134          for key, wr in self.data.items():
   135              o = wr()
   136              if o is not None:
   137                  new[copy.deepcopy(key, memo)] = o
   138          return new
   139  
   140      def get(self, key, default=None):
   141          try:
   142              wr = self.data[key]
   143          except KeyError:
   144              return default
   145          else:
   146              o = wr()
   147              if o is None:
   148                  # This should only happen
   149                  return default
   150              else:
   151                  return o
   152  
   153      def items(self):
   154          L = []
   155          for key, wr in self.data.items():
   156              o = wr()
   157              if o is not None:
   158                  L.append((key, o))
   159          return L
   160  
   161      def iteritems(self):
   162          with _IterationGuard(self):
   163              for wr in self.data.itervalues():
   164                  value = wr()
   165                  if value is not None:
   166                      yield wr.key, value
   167  
   168      def iterkeys(self):
   169          with _IterationGuard(self):
   170              for k in self.data.iterkeys():
   171                  yield k
   172  
   173      __iter__ = iterkeys
   174  
   175      def itervaluerefs(self):
   176          """Return an iterator that yields the weak references to the values.
   177  
   178          The references are not guaranteed to be 'live' at the time
   179          they are used, so the result of calling the references needs
   180          to be checked before being used.  This can be used to avoid
   181          creating references that will cause the garbage collector to
   182          keep the values around longer than needed.
   183  
   184          """
   185          with _IterationGuard(self):
   186              for wr in self.data.itervalues():
   187                  yield wr
   188  
   189      def itervalues(self):
   190          with _IterationGuard(self):
   191              for wr in self.data.itervalues():
   192                  obj = wr()
   193                  if obj is not None:
   194                      yield obj
   195  
   196      def popitem(self):
   197          if self._pending_removals:
   198              self._commit_removals()
   199          while 1:
   200              key, wr = self.data.popitem()
   201              o = wr()
   202              if o is not None:
   203                  return key, o
   204  
   205      def pop(self, key, *args):
   206          if self._pending_removals:
   207              self._commit_removals()
   208          try:
   209              o = self.data.pop(key)()
   210          except KeyError:
   211              if args:
   212                  return args[0]
   213              raise
   214          if o is None:
   215              raise KeyError, key
   216          else:
   217              return o
   218  
   219      def setdefault(self, key, default=None):
   220          try:
   221              wr = self.data[key]
   222          except KeyError:
   223              if self._pending_removals:
   224                  self._commit_removals()
   225              self.data[key] = KeyedRef(default, self._remove, key)
   226              return default
   227          else:
   228              return wr()
   229  
   230      def update(*args, **kwargs):
   231          if not args:
   232              raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
   233                              "object needs an argument")
   234          self = args[0]
   235          args = args[1:]
   236          if len(args) > 1:
   237              raise TypeError('expected at most 1 arguments, got %d' % len(args))
   238          dict = args[0] if args else None
   239          if self._pending_removals:
   240              self._commit_removals()
   241          d = self.data
   242          if dict is not None:
   243              if not hasattr(dict, "items"):
   244                  dict = type({})(dict)
   245              for key, o in dict.items():
   246                  d[key] = KeyedRef(o, self._remove, key)
   247          if len(kwargs):
   248              self.update(kwargs)
   249  
   250      def valuerefs(self):
   251          """Return a list of weak references to the values.
   252  
   253          The references are not guaranteed to be 'live' at the time
   254          they are used, so the result of calling the references needs
   255          to be checked before being used.  This can be used to avoid
   256          creating references that will cause the garbage collector to
   257          keep the values around longer than needed.
   258  
   259          """
   260          return self.data.values()
   261  
   262      def values(self):
   263          L = []
   264          for wr in self.data.values():
   265              o = wr()
   266              if o is not None:
   267                  L.append(o)
   268          return L
   269  
   270  
   271  class KeyedRef(ref):
   272      """Specialized reference that includes a key corresponding to the value.
   273  
   274      This is used in the WeakValueDictionary to avoid having to create
   275      a function object for each key stored in the mapping.  A shared
   276      callback object can use the 'key' attribute of a KeyedRef instead
   277      of getting a reference to the key from an enclosing scope.
   278  
   279      """
   280  
   281      __slots__ = "key",
   282  
   283      def __new__(type, ob, callback, key):
   284          self = ref.__new__(type, ob, callback)
   285          self.key = key
   286          return self
   287  
   288      def __init__(self, ob, callback, key):
   289          super(KeyedRef,  self).__init__(ob, callback)
   290  
   291  
   292  class WeakKeyDictionary(UserDict.UserDict):
   293      """ Mapping class that references keys weakly.
   294  
   295      Entries in the dictionary will be discarded when there is no
   296      longer a strong reference to the key. This can be used to
   297      associate additional data with an object owned by other parts of
   298      an application without adding attributes to those objects. This
   299      can be especially useful with objects that override attribute
   300      accesses.
   301      """
   302  
   303      def __init__(self, dict=None):
   304          self.data = {}
   305          def remove(k, selfref=ref(self)):
   306              self = selfref()
   307              if self is not None:
   308                  if self._iterating:
   309                      self._pending_removals.append(k)
   310                  else:
   311                      del self.data[k]
   312          self._remove = remove
   313          # A list of dead weakrefs (keys to be removed)
   314          self._pending_removals = []
   315          self._iterating = set()
   316          if dict is not None:
   317              self.update(dict)
   318  
   319      def _commit_removals(self):
   320          # NOTE: We don't need to call this method before mutating the dict,
   321          # because a dead weakref never compares equal to a live weakref,
   322          # even if they happened to refer to equal objects.
   323          # However, it means keys may already have been removed.
   324          l = self._pending_removals
   325          d = self.data
   326          while l:
   327              try:
   328                  del d[l.pop()]
   329              except KeyError:
   330                  pass
   331  
   332      def __delitem__(self, key):
   333          del self.data[ref(key)]
   334  
   335      def __getitem__(self, key):
   336          return self.data[ref(key)]
   337  
   338      def __repr__(self):
   339          return "<WeakKeyDictionary at %s>" % id(self)
   340  
   341      def __setitem__(self, key, value):
   342          self.data[ref(key, self._remove)] = value
   343  
   344      def copy(self):
   345          new = WeakKeyDictionary()
   346          for key, value in self.data.items():
   347              o = key()
   348              if o is not None:
   349                  new[o] = value
   350          return new
   351  
   352      __copy__ = copy
   353  
   354      def __deepcopy__(self, memo):
   355          import copy
   356          new = self.__class__()
   357          for key, value in self.data.items():
   358              o = key()
   359              if o is not None:
   360                  new[o] = copy.deepcopy(value, memo)
   361          return new
   362  
   363      def get(self, key, default=None):
   364          return self.data.get(ref(key),default)
   365  
   366      def has_key(self, key):
   367          try:
   368              wr = ref(key)
   369          except TypeError:
   370              return 0
   371          return wr in self.data
   372  
   373      def __contains__(self, key):
   374          try:
   375              wr = ref(key)
   376          except TypeError:
   377              return 0
   378          return wr in self.data
   379  
   380      def items(self):
   381          L = []
   382          for key, value in self.data.items():
   383              o = key()
   384              if o is not None:
   385                  L.append((o, value))
   386          return L
   387  
   388      def iteritems(self):
   389          with _IterationGuard(self):
   390              for wr, value in self.data.iteritems():
   391                  key = wr()
   392                  if key is not None:
   393                      yield key, value
   394  
   395      def iterkeyrefs(self):
   396          """Return an iterator that yields the weak references to the keys.
   397  
   398          The references are not guaranteed to be 'live' at the time
   399          they are used, so the result of calling the references needs
   400          to be checked before being used.  This can be used to avoid
   401          creating references that will cause the garbage collector to
   402          keep the keys around longer than needed.
   403  
   404          """
   405          with _IterationGuard(self):
   406              for wr in self.data.iterkeys():
   407                  yield wr
   408  
   409      def iterkeys(self):
   410          with _IterationGuard(self):
   411              for wr in self.data.iterkeys():
   412                  obj = wr()
   413                  if obj is not None:
   414                      yield obj
   415  
   416      __iter__ = iterkeys
   417  
   418      def itervalues(self):
   419          with _IterationGuard(self):
   420              for value in self.data.itervalues():
   421                  yield value
   422  
   423      def keyrefs(self):
   424          """Return a list of weak references to the keys.
   425  
   426          The references are not guaranteed to be 'live' at the time
   427          they are used, so the result of calling the references needs
   428          to be checked before being used.  This can be used to avoid
   429          creating references that will cause the garbage collector to
   430          keep the keys around longer than needed.
   431  
   432          """
   433          return self.data.keys()
   434  
   435      def keys(self):
   436          L = []
   437          for wr in self.data.keys():
   438              o = wr()
   439              if o is not None:
   440                  L.append(o)
   441          return L
   442  
   443      def popitem(self):
   444          while 1:
   445              key, value = self.data.popitem()
   446              o = key()
   447              if o is not None:
   448                  return o, value
   449  
   450      def pop(self, key, *args):
   451          return self.data.pop(ref(key), *args)
   452  
   453      def setdefault(self, key, default=None):
   454          return self.data.setdefault(ref(key, self._remove),default)
   455  
   456      def update(self, dict=None, **kwargs):
   457          d = self.data
   458          if dict is not None:
   459              if not hasattr(dict, "items"):
   460                  dict = type({})(dict)
   461              for key, value in dict.items():
   462                  d[ref(key, self._remove)] = value
   463          if len(kwargs):
   464              self.update(kwargs)