Created
December 8, 2017 10:32
-
-
Save gicmo/4a54e97d63794ae87a3442ad83104d4f to your computer and use it in GitHub Desktop.
Simple signal class for python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
class Signal(object): | |
def __init__(self, name): | |
self.name = name | |
self.callbacks = set() | |
def connect(self, callback): | |
self.callbacks.add(callback) | |
def disconnect(self, callback): | |
self.callbacks.remove(callback) | |
def disconnect_all(self): | |
self.callbacks = set() | |
def emit(self, *args, **kwargs): | |
for cb in self.callbacks: | |
cb(*args, **kwargs) | |
def __call__(self, *args, **kwargs): | |
self.emit(*args, **kwargs) | |
def __iadd__(self, callback): | |
self.connect(callback) | |
def __idel__(self, callback): | |
self.disconnect(callback) | |
@staticmethod | |
def enable(klass): | |
lst = getattr(klass, 'signals', []) | |
methods = [m for m in dir(klass) if not m.startswith('__')] | |
def install(l): | |
if l is None: | |
return | |
if l in methods: | |
print('WARNING: signal "%s" will overwrite method' % l) | |
def getter(self): | |
return self.signals[l] | |
def setter(self, value): | |
return self.signals[l] | |
p = property(getter, setter) | |
setattr(klass, l, p) | |
return Signal(l) | |
klass.signals = {l: install(l) for l in lst} | |
for m in methods: | |
method = getattr(klass, m) | |
name = getattr(method, 'signal', None) | |
method.signal = install(name) | |
klass.signals[name] = method.signal | |
return klass | |
@staticmethod | |
def autoemit(name, order='post'): | |
if order not in ['pre', 'post']: | |
raise ValueError('invalid order: ' + str(order)) | |
def decorator(f): | |
def wrapper(self, *args, **kwargs): | |
signal = f.signal | |
if not isinstance(signal, Signal): | |
return f(self, *args, **kwargs) | |
if order == 'pre': | |
signal.emit(self) | |
res = f(self, *args, **kwargs) | |
if order == 'post': | |
signal.emit(self) | |
return res | |
# will be replaced by the Signal object | |
# via Signal.enable | |
wrapper.signal = name | |
return wrapper | |
return decorator |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment