finalize.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #
  2. # Module supporting finaliztion using weakrefs
  3. #
  4. # processing/finalize.py
  5. #
  6. # Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
  7. #
  8. import weakref
  9. import itertools
  10. from processing.logger import subDebug
  11. __all__ = ['Finalize', '_runFinalizers']
  12. _registry = {}
  13. _counter = itertools.count()
  14. class Finalize(object):
  15. '''
  16. Class which supports object finalization using weakrefs
  17. '''
  18. def __init__(self, obj, callback, args=(), kwargs=None, exitpriority=None):
  19. assert exitpriority is None or type(exitpriority) is int
  20. assert callback is not None
  21. if obj is not None:
  22. self._weakref = weakref.ref(obj, self)
  23. else:
  24. assert exitpriority is not None
  25. self._callback = callback
  26. self._args = args
  27. self._kwargs = kwargs or {}
  28. self._key = (exitpriority, _counter.next())
  29. _registry[self._key] = self
  30. def __call__(self, wr=None):
  31. '''
  32. Run the callback unless it has already been called or cancelled
  33. Returns True if callback was run otherwise returns False
  34. '''
  35. try:
  36. del _registry[self._key]
  37. except KeyError:
  38. subDebug('finalizer no longer registered')
  39. else:
  40. subDebug('finalizer calling %s with args %s and kwargs %s',
  41. self._callback, self._args, self._kwargs)
  42. self._callback(*self._args, **self._kwargs)
  43. self._weakref = self._callback = self._args = \
  44. self._kwargs = self._key = None
  45. return True
  46. def cancel(self):
  47. '''
  48. Cancel finalization of the object
  49. '''
  50. try:
  51. del _registry[self._key]
  52. except KeyError:
  53. pass
  54. else:
  55. self._weakref = self._callback = self._args = \
  56. self._kwargs = self._key = None
  57. def stillActive(self):
  58. '''
  59. Return whether this finalizer is still waiting to invoke callback
  60. '''
  61. return self._key in _registry
  62. def __repr__(self):
  63. try:
  64. obj = self._weakref()
  65. except (AttributeError, TypeError):
  66. obj = None
  67. if obj is None:
  68. return '<Finalize object, dead>'
  69. x = '<Finalize object, callback=%s' % \
  70. getattr(self._callback, '__name__', self._callback)
  71. if self._args:
  72. x += ', args=' + str(self._args)
  73. if self._kwargs:
  74. x += ', kwargs=' + str(self._kwargs)
  75. if self._key[0] is not None:
  76. x += ', exitprority=' + str(self._key[0])
  77. return x + '>'
  78. def _runFinalizers(minpriority=None):
  79. '''
  80. Run all finalizers whose exit priority is not None and at least minpriority
  81. Finalizers with highest priority are called first; finalizers with
  82. the same priority will be called in reverse order of creation.
  83. '''
  84. if minpriority is None:
  85. f = lambda p : p[0][0] is not None
  86. else:
  87. f = lambda p : p[0][0] is not None and p[0][0] >= minpriority
  88. items = sorted(filter(f, _registry.items()), reverse=True)
  89. for key, finalizer in items:
  90. subDebug('calling %s', finalizer)
  91. try:
  92. finalizer()
  93. except Exception:
  94. import traceback
  95. traceback.print_exc()
  96. if minpriority is None:
  97. _registry.clear()