Package: whine
whineBecause every system time-to-time needs to whine about somethingIntroductionwhineis a very lightweight package for custom implementations of subscribing and dispatching event messages, using an observer-like pattern.Thewhine.EventHandlerprovides the means to create event-subscribing and dispatching activities.
It allows to separate the logic of responsability amongs the components, and bring them together.Here is a breakdown of responsabilities, which are mentioned in the examples:Dispatchers: provide the functionality of conveying a message of an event. Dispatch classes need to have a.emit_messagemethod implemented, and their instances would be registered with theEventHandler.Event functions: standalone functions, which compose your message text with any arguments (if needed). These functions would be used to subscribe to anEventHandlerinstance with anevent name.Event name: a value, used to represent the event, using a string (treat it as a constant).Dispatch: an action whenEventHandler.dispatchmethod is called with anevent name- a message is then created using theevent function, and dispatched using registereddispatchers.Such approach separates the logic, between how an event notification is conveyed, how a message is composed, and a way how an event message is emitted. If any means of these components are changed, they would not need to be altered in one place, keeping the rest of the setup working as intended.Use CasesUse a notification platform for dispatching a message (eg: Telegram, Slack, e-mail, logging, etc.)Create a function, that formats a message content (eg: failed scheduled task, new user registration). Since the functions are standalone, have the freedom of passing any parameters, those help to format the message value (eg: class instances).Dispatch an event notification in a convenient place (eg: in an except block, post-action signals)InstallationRequires Python 3.8+pipinstallwhineQuick StartfromwhineimportEventHandlerevents=EventHandler()# Create a dispatcher class for processing messages# Implement a `.emit_message` method in that class# Use a decorator to automatically add to dispatchers# There can be multiple dispatchers added to an EventHandler instance@events.registerclassSimpleDispatcher:defemit_message(self,message:str)->None:print(message)# Create a function, for processing a message, that returns a string# The function can take any arguments it may need to form an event message# Decorate an event function with the `.subscribe`, and provide an event name ('SIMPLE')@events.subscribe("SIMPLE")defsimple_event(value)->str:returnf"Simple event for{value}"# Trigger the event function, and pass any positional or keyword argumentsevents.dispatch("SIMPLE","my value")# An output from the event function is then emitted by all registered dispatchersMore ExamplesLogging and Telegram whinersThis example demonstrates an event handler, that uses Telegram and Logging dispatchers.
A function is created and subscribed to, so a pre-defined message is created from aUserinstance.
An event is dispatched when a user is created, so the message is emited to all dispatchers.importosimportloggingimporttelebotfromwhineimportEventHandlerfromdataclassesimportdataclassevents=EventHandler()@dataclassclassUser:name:str@events.register(os.environ["TELEGRAM_CHAT_ID"],os.environ["TELEGRAM_TOKEN"])classTelegramDispatcher:def__init__(self,chat_id:int,token:str):self.chat_id=chat_idself.bot=telebot.TeleBot(token)defemit_message(self,message:str)->None:self.bot.send_message(self.chat_id,message)classLoggerDispatcher:def__init__(self,level:int=logging.WARNING):self.level=levelself.logger=logging.getLogger(__name__)defemit_message(self,message:str)->None:self.logger.log(self.level,message)# @events.register  # can be used as a naked decorator (when init takes no args)# Alternatively, create a dispatcher instance and add to the EventHandlerevents.add_dispatcher(LoggerDispatcher())@events.subscribe("NEW_USER")defevent_new_user(user:User)->str:returnf"A new user was created{user.name}, welcome them on the platform!"# Explicitly added subscribtion to an event with a static lambda functionevents.add_subscriber("BACKUP_COMPLETED",lambda:"The weekly backup was completed!")defcreate_new_user(name:str)->User:"""User creation function, also dispatches an event"""user=User(name=name)events.dispatch("NEW_USER",user)# an event is dispatched with a position argreturnuserdefweekly_backup():"""Some function that performs backups"""...# some implementationevents.dispatch("BACKUP_COMPLETED")# an event is dispatched (no args)DevelopmentInstall development dependencies:# pip install pipenvpipenvinstall--devBuild docs:pdoc--html--force-odocswhine