Advertisement
Guest User

Untitled

a guest
May 4th, 2015
215
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.84 KB | None | 0 0
  1. """
  2. Green Rocket is a simple and compact implementation of Observer
  3. (or Publish/Subscribe) design pattern via signals.
  4.  
  5. Create specific signal using base one::
  6.  
  7. >>> from greenrocket import Signal
  8. >>> class MySignal(Signal):
  9. ... pass
  10. ...
  11.  
  12. Subscribe handler::
  13.  
  14. >>> @MySignal.subscribe
  15. ... def handler(signal):
  16. ... print('handler: ' + repr(signal))
  17. ...
  18.  
  19. Fire signal::
  20.  
  21. >>> MySignal().fire()
  22. handler: MySignal()
  23.  
  24. Note, that signal propagates over inheritance, i.e. all subscribers of base
  25. signal will be called when child one is fired::
  26.  
  27. >>> @Signal.subscribe
  28. ... def base_hadler(signal):
  29. ... print('base_handler: ' + repr(signal))
  30. ...
  31. >>> MySignal().fire()
  32. handler: MySignal()
  33. base_handler: MySignal()
  34.  
  35. Unsubscribe handler::
  36.  
  37. >>> MySignal.unsubscribe(handler)
  38. >>> MySignal().fire()
  39. base_handler: MySignal()
  40.  
  41. The handler is subscribed using weak reference. So if you create and subscribe
  42. a handler in local scope (for example inside a generator), it will unsubscribed
  43. automatically.
  44.  
  45. >>> def gen():
  46. ... @MySignal.subscribe
  47. ... def local_handler(signal):
  48. ... print('local_handler: ' + repr(signal))
  49. ... yield 1
  50. ...
  51. >>> for value in gen():
  52. ... MySignal(value=value).fire()
  53. ...
  54. local_handler: MySignal(value=1)
  55. base_handler: MySignal(value=1)
  56. >>> import gc # PyPy fails the following test without
  57. >>> _ = gc.collect() # an explicit call of garbage collector.
  58. >>> MySignal(value=2).fire()
  59. base_handler: MySignal(value=2)
  60.  
  61. As you can see above, signal constructor accepts keyword arguments. These
  62. arguments are available as signal attributes::
  63.  
  64. >>> s = MySignal(a=1, b=2)
  65. >>> s.a
  66. 1
  67. >>> s.b
  68. 2
  69.  
  70. Signal suppresses any exception which is raised on handler call. It uses
  71. logger named ``greenrocket`` from standard ``logging`` module to log errors and
  72. debug information.
  73.  
  74. """
  75.  
  76. from logging import getLogger
  77. try:
  78. from weakref import WeakSet
  79. except ImportError:
  80. # Python 2.6
  81. from weakrefset import WeakSet
  82.  
  83.  
  84. __all__ = ['Signal']
  85. __version__ = '0.21'
  86. __author__ = 'Dmitry Vakhrushev <self@kr41.net>'
  87. __license__ = 'BSD'
  88.  
  89.  
  90. class SignalMeta(type):
  91. """ Signal Meta Class """
  92.  
  93. def __init__(cls, class_name, bases, attrs):
  94. cls.__handlers__ = WeakSet()
  95.  
  96.  
  97. # For compatibility between Python 2.x and Python 3.x
  98. BaseSignal = SignalMeta('BaseSignal', (object,), {})
  99.  
  100.  
  101. class Signal(BaseSignal):
  102. """ Base Signal Class """
  103.  
  104. logger = getLogger(__name__)
  105.  
  106. @classmethod
  107. def subscribe(cls, handler):
  108. """ Subscribe handler to signal. May be used as decorator """
  109. cls.logger.debug('Subscribe %r on %r', handler, cls)
  110. cls.__handlers__.add(handler)
  111. return handler
  112.  
  113. @classmethod
  114. def unsubscribe(cls, handler):
  115. """ Unsubscribe handler from signal """
  116. cls.logger.debug('Unsubscribe %r from %r', handler, cls)
  117. cls.__handlers__.discard(handler)
  118.  
  119. def __init__(self, **kw):
  120. self.__dict__.update(kw)
  121.  
  122. def __repr__(self):
  123. params = []
  124. for k, v in self.__dict__.items():
  125. params.append('{0}={1!r}'.format(k, v))
  126. params = ', '.join(params)
  127. return '{0}({1})'.format(self.__class__.__name__, params)
  128.  
  129. def fire(self):
  130. """ Fire signal """
  131. self.logger.debug('Fired %r', self)
  132. for cls in self.__class__.__mro__:
  133. if hasattr(cls, '__handlers__'):
  134. self.logger.debug('Propagate on %r', cls)
  135. for handler in cls.__handlers__:
  136. try:
  137. self.logger.debug('Call %r', handler)
  138. handler(self)
  139. except:
  140. self.logger.error('Failed on processing %r by %r',
  141. self, handler, exc_info=True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement