You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

weakref_backports.py 2.1 KiB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. """
  2. weakref_backports is a partial backport of the weakref module for python
  3. versions below 3.4.
  4. Copyright (C) 2013 Python Software Foundation, see license.python.txt for
  5. details.
  6. The following changes were made to the original sources during backporting:
  7. * Added `self` to `super` calls.
  8. * Removed `from None` when raising exceptions.
  9. """
  10. from weakref import ref
  11. class WeakMethod(ref):
  12. """
  13. A custom `weakref.ref` subclass which simulates a weak reference to
  14. a bound method, working around the lifetime problem of bound methods.
  15. """
  16. __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
  17. def __new__(cls, meth, callback=None):
  18. try:
  19. obj = meth.__self__
  20. func = meth.__func__
  21. except AttributeError:
  22. raise TypeError("argument should be a bound method, not {}"
  23. .format(type(meth)))
  24. def _cb(arg):
  25. # The self-weakref trick is needed to avoid creating a reference
  26. # cycle.
  27. self = self_wr()
  28. if self._alive:
  29. self._alive = False
  30. if callback is not None:
  31. callback(self)
  32. self = ref.__new__(cls, obj, _cb)
  33. self._func_ref = ref(func, _cb)
  34. self._meth_type = type(meth)
  35. self._alive = True
  36. self_wr = ref(self)
  37. return self
  38. def __call__(self):
  39. obj = super(WeakMethod, self).__call__()
  40. func = self._func_ref()
  41. if obj is None or func is None:
  42. return None
  43. return self._meth_type(func, obj)
  44. def __eq__(self, other):
  45. if isinstance(other, WeakMethod):
  46. if not self._alive or not other._alive:
  47. return self is other
  48. return ref.__eq__(self, other) and self._func_ref == other._func_ref
  49. return False
  50. def __ne__(self, other):
  51. if isinstance(other, WeakMethod):
  52. if not self._alive or not other._alive:
  53. return self is not other
  54. return ref.__ne__(self, other) or self._func_ref != other._func_ref
  55. return True
  56. __hash__ = ref.__hash__