Added docstrings for signals

This commit is contained in:
ChrisLR 2022-04-12 18:51:09 -04:00
parent c22a08851f
commit 326b32a587

View file

@ -1,4 +1,19 @@
"""
Components - ChrisLR 2022
This file contains classes functions related to signals.
"""
def as_listener(func=None, signal_name=None): def as_listener(func=None, signal_name=None):
"""
Decorator style function that marks a method to be connected as listener.
It will use the provided signal name and default to the decorated function name.
Args:
func (callable): The method to mark as listener
signal_name (str): The name of the signal to listen to, defaults to function name.
"""
if not func and signal_name: if not func and signal_name:
def wrapper(func): def wrapper(func):
func._listener_signal_name = signal_name func._listener_signal_name = signal_name
@ -11,6 +26,14 @@ def as_listener(func=None, signal_name=None):
def as_responder(func=None, signal_name=None): def as_responder(func=None, signal_name=None):
"""
Decorator style function that marks a method to be connected as responder.
It will use the provided signal name and default to the decorated function name.
Args:
func (callable): The method to mark as responder
signal_name (str): The name of the signal to respond to, defaults to function name.
"""
if not func and signal_name: if not func and signal_name:
def wrapper(func): def wrapper(func):
func._responder_signal_name = signal_name func._responder_signal_name = signal_name
@ -23,6 +46,12 @@ def as_responder(func=None, signal_name=None):
class SignalsHandler(object): class SignalsHandler(object):
"""
This object handles all about signals.
It holds the connected listeners and responders.
It allows triggering signals or querying responders.
"""
def __init__(self, host): def __init__(self, host):
self.host = host self.host = host
self.listeners = {} self.listeners = {}
@ -30,16 +59,40 @@ class SignalsHandler(object):
self.add_object_listeners_and_responders(host) self.add_object_listeners_and_responders(host)
def add_listener(self, signal_name, callback): def add_listener(self, signal_name, callback):
"""
Connect a listener to a specific signal.
Args:
signal_name (str): The name of the signal to listen to
callback (callable): The callable that is called when the signal is triggered
"""
signal_listeners = self.listeners.setdefault(signal_name, []) signal_listeners = self.listeners.setdefault(signal_name, [])
if callback not in signal_listeners: if callback not in signal_listeners:
signal_listeners.append(callback) signal_listeners.append(callback)
def add_responder(self, signal_name, callback): def add_responder(self, signal_name, callback):
"""
Connect a responder to a specific signal.
Args:
signal_name (str): The name of the signal to respond to
callback (callable): The callable that is called when the signal is queried
"""
signal_responders = self.responders.setdefault(signal_name, []) signal_responders = self.responders.setdefault(signal_name, [])
if callback not in signal_responders: if callback not in signal_responders:
signal_responders.append(callback) signal_responders.append(callback)
def remove_listener(self, signal_name, callback): def remove_listener(self, signal_name, callback):
"""
Removes a listener for a specific signal.
Args:
signal_name (str): The name of the signal to disconnect from
callback (callable): The callable that was used to connect
"""
signal_listeners = self.listeners.get(signal_name) signal_listeners = self.listeners.get(signal_name)
if not signal_listeners: if not signal_listeners:
return return
@ -48,6 +101,13 @@ class SignalsHandler(object):
signal_listeners.remove(callback) signal_listeners.remove(callback)
def remove_responder(self, signal_name, callback): def remove_responder(self, signal_name, callback):
"""
Removes a responder for a specific signal.
Args:
signal_name (str): The name of the signal to disconnect from
callback (callable): The callable that was used to connect
"""
signal_responders = self.responders.get(signal_name) signal_responders = self.responders.get(signal_name)
if not signal_responders: if not signal_responders:
return return
@ -56,7 +116,14 @@ class SignalsHandler(object):
signal_responders.remove(callback) signal_responders.remove(callback)
def trigger(self, signal_name, *args, **kwargs): def trigger(self, signal_name, *args, **kwargs):
""" This method fires a signal but does not return anything """ """
Triggers a specific signal with specified args and kwargs
This method does not return anything
Args:
signal_name (str): The name of the signal to trigger
"""
callbacks = self.listeners.get(signal_name) callbacks = self.listeners.get(signal_name)
if not callbacks: if not callbacks:
return return
@ -65,7 +132,23 @@ class SignalsHandler(object):
callback(*args, **kwargs) callback(*args, **kwargs)
def query(self, signal_name, *args, default=None, aggregate_func=None, **kwargs): def query(self, signal_name, *args, default=None, aggregate_func=None, **kwargs):
""" This method fires a signal query that retrieves values """ """
Queries a specific signal with specified args and kwargs
This method will return the responses from its connected responders.
If an aggregate_func is specified, it is called with the responses
and its result is returned instead.
Args:
signal_name (str): The name of the signal to trigger
default (any): The value to use when no responses are given
It will be passed to aggregate_func if it is also given.
aggregate_func (callable): The function to process the results before returning.
Returns:
list: An iterable of the responses
OR the aggregated result when aggregate_func is specified.
"""
callbacks = self.responders.get(signal_name) callbacks = self.responders.get(signal_name)
if not callbacks: if not callbacks:
@ -86,6 +169,12 @@ class SignalsHandler(object):
return responses return responses
def add_object_listeners_and_responders(self, obj): def add_object_listeners_and_responders(self, obj):
"""
This connects the methods marked as listener or responder from an object.
Args:
obj (object): The instance of an object to connect to this handler.
"""
type_host = type(obj) type_host = type(obj)
for att_name, att_obj in type_host.__dict__.items(): for att_name, att_obj in type_host.__dict__.items():
listener_signal_name = getattr(att_obj, '_listener_signal_name', None) listener_signal_name = getattr(att_obj, '_listener_signal_name', None)
@ -99,6 +188,12 @@ class SignalsHandler(object):
self.add_responder(signal_name=responder_signal_name, callback=callback) self.add_responder(signal_name=responder_signal_name, callback=callback)
def remove_object_listeners_and_responders(self, obj): def remove_object_listeners_and_responders(self, obj):
"""
This disconnects the methods marked as listener or responder from an object.
Args:
obj (object): The instance of an object to disconnect from this handler.
"""
type_host = type(obj) type_host = type(obj)
for att_name, att_obj in type_host.__dict__.items(): for att_name, att_obj in type_host.__dict__.items():
listener_signal_name = getattr(att_obj, '_listener_signal_name', None) listener_signal_name = getattr(att_obj, '_listener_signal_name', None)