callbacks.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. from PyQt4 import QtCore
  2. class NoCallbackError(Exception):
  3. pass
  4. class CallbackExistsError(Exception):
  5. pass
  6. class CallbackHandler(QtCore.QObject):
  7. """
  8. Handler for custom callbacks.
  9. It can handle synchronous callbacks as well as async callbacks (using pyqtSignals)
  10. """
  11. callback_signal = QtCore.pyqtSignal(str, list, dict)
  12. def __init__(self):
  13. super(CallbackHandler, self).__init__()
  14. self._callbacks = {}
  15. self.callback_signal.connect(self.__async_callback_receiver)
  16. def callback(self, name, *args, **kwargs):
  17. """
  18. Call all registered callback method for name
  19. This passes all additional arguments and keyword arguments down to the callbacks
  20. NOTE: all callbacks therefore need to accept the same number of arguments
  21. :param name: the name for which the callbacks are to be called
  22. :param args: arguments to be passed to the callbacks
  23. :param kwargs: keyword arguments to be passed to the callbacks
  24. """
  25. if name in self._callbacks:
  26. for callback in self._callbacks[name]:
  27. callback(*args, **kwargs)
  28. else:
  29. raise NoCallbackError("Callback " + name + " not registered.")
  30. def __async_callback_receiver(self, name, *args):
  31. """
  32. Internal Method (Called when async callbacks are to be executed)
  33. """
  34. self.callback(str(name), *args[0], **args[1])
  35. def async_callback(self, name, *args, **kwargs):
  36. """
  37. Perform a async callback (same as callback but through pyqtSignal and therefore allowed in threads)
  38. :param name: the name for which the callbacks are to be called
  39. :param args: arguments to be passed to the callbacks
  40. :param kwargs: keyword arguments to be passed to the callbacks
  41. """
  42. if name in self._callbacks:
  43. self.callback_signal.emit(name, list(args), dict(kwargs))
  44. else:
  45. raise NoCallbackError("Callback " + name + " not registered.")
  46. def add_callback(self, name, callback):
  47. """
  48. Register a callback for name
  49. :param name: the name to register against
  50. :param callback: the callback to register
  51. """
  52. if name in self._callbacks:
  53. if callback in self._callbacks[name]:
  54. raise CallbackExistsError("Callback " + name + " already registered.")
  55. else:
  56. self._callbacks[name].append(callback)
  57. else:
  58. self._callbacks[name] = [callback, ]
  59. def delete_callback(self, name, callback):
  60. """
  61. Delete a callback from name
  62. if no callback for name is left the whole group is deleted
  63. :param name: the name to delete the callback from
  64. :param callback: the callback to delete
  65. """
  66. if name not in self._callbacks:
  67. raise NoCallbackError("Callback " + name + " not registered.")
  68. else:
  69. if callback in self._callbacks[name]:
  70. self._callbacks[name].remove(callback)
  71. else:
  72. raise NoCallbackError("Callback " + str(callback) + " not registered in " + name+".")
  73. if len(self._callbacks[name]) == 0:
  74. self.delete_callback_class(name)
  75. def delete_callback_class(self, name):
  76. """
  77. Delete a whole callback class
  78. :param name: the name of the class
  79. """
  80. if name in self._callbacks:
  81. del self._callbacks[name]
  82. else:
  83. raise NoCallbackError("Callback " + name + " not registered.")
  84. callbacks = CallbackHandler()