From 6cf4dbb8cceda7aff0ba30315359499a6e54a87b Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 15 May 2026 16:55:01 +0800 Subject: [PATCH] bugfix --- appPublic/event_dispatcher.py | 275 +++++++++++++++++----------------- 1 file changed, 138 insertions(+), 137 deletions(-) diff --git a/appPublic/event_dispatcher.py b/appPublic/event_dispatcher.py index d892e48..49e6e13 100644 --- a/appPublic/event_dispatcher.py +++ b/appPublic/event_dispatcher.py @@ -3,196 +3,197 @@ import inspect import traceback import weakref from typing import Callable, Any +from appPublic.log import debug, error, exception, warning class WeakCallback: - def __init__(self, func: Callable): + def __init__(self, func: Callable): - self._is_coroutine = inspect.iscoroutinefunction(func) + self._is_coroutine = inspect.iscoroutinefunction(func) - if inspect.ismethod(func): - self._ref = weakref.WeakMethod(func) - else: - self._ref = weakref.ref(func) + if inspect.ismethod(func): + self._ref = weakref.WeakMethod(func) + else: + self._ref = weakref.ref(func) - self._hash = hash(func) + self._hash = hash(func) - @property - def is_coroutine(self): - return self._is_coroutine + @property + def is_coroutine(self): + return self._is_coroutine - def get(self): - return self._ref() + def get(self): + return self._ref() - def __eq__(self, other): - return isinstance(other, WeakCallback) and self._hash == other._hash + def __eq__(self, other): + return isinstance(other, WeakCallback) and self._hash == other._hash - def __hash__(self): - return self._hash + def __hash__(self): + return self._hash class EventDispatcher: - def __init__( - self, - *, - continue_on_error=True, - log_traceback=True, - handler_timeout=None, - error_handler=None, - ): + def __init__( + self, + *, + continue_on_error=True, + log_traceback=True, + handler_timeout=None, + error_handler=None, + ): - self._events = {} + self._events = {} - self.continue_on_error = continue_on_error - self.log_traceback = log_traceback - self.handler_timeout = handler_timeout - self.error_handler = error_handler + self.continue_on_error = continue_on_error + self.log_traceback = log_traceback + self.handler_timeout = handler_timeout + self.error_handler = error_handler - def bind(self, event_name: str, func: Callable): + def bind(self, event_name: str, func: Callable): - if event_name not in self._events: - self._events[event_name] = set() + if event_name not in self._events: + self._events[event_name] = set() - self._events[event_name].add(WeakCallback(func)) + self._events[event_name].add(WeakCallback(func)) - def unbind(self, event_name: str, func: Callable): + def unbind(self, event_name: str, func: Callable): - if event_name not in self._events: - return + if event_name not in self._events: + return - target = WeakCallback(func) + target = WeakCallback(func) - self._events[event_name] = { - cb for cb in self._events[event_name] - if cb != target - } + self._events[event_name] = { + cb for cb in self._events[event_name] + if cb != target + } - if not self._events[event_name]: - del self._events[event_name] + if not self._events[event_name]: + del self._events[event_name] - async def _run_error_handler( - self, - event_name, - func, - exc, - ): + async def _run_error_handler( + self, + event_name, + func, + exc, + ): - if not self.error_handler: - return + if not self.error_handler: + return - try: + try: - if inspect.iscoroutinefunction(self.error_handler): - await self.error_handler( - event_name, - func, - exc, - ) - else: - self.error_handler( - event_name, - func, - exc, - ) + if inspect.iscoroutinefunction(self.error_handler): + await self.error_handler( + event_name, + func, + exc, + ) + else: + self.error_handler( + event_name, + func, + exc, + ) - except Exception as e: - print(f"[EventDispatcher] error_handler failed: {e}") + except Exception as e: + print(f"[EventDispatcher] error_handler failed: {e}") - async def _execute_handler( - self, - cb, - event_name, - data, - ): + async def _execute_handler( + self, + cb, + event_name, + data, + ): - func = cb.get() + func = cb.get() - if func is None: - return False + if func is None: + return False - try: + try: - if cb.is_coroutine: + if cb.is_coroutine: - coro = func(data) + coro = func(data) - if self.handler_timeout: - await asyncio.wait_for( - coro, - timeout=self.handler_timeout, - ) - else: - await coro + if self.handler_timeout: + await asyncio.wait_for( + coro, + timeout=self.handler_timeout, + ) + else: + await coro - else: + else: - if self.handler_timeout: + if self.handler_timeout: - await asyncio.wait_for( - asyncio.to_thread(func, data), - timeout=self.handler_timeout, - ) + await asyncio.wait_for( + asyncio.to_thread(func, data), + timeout=self.handler_timeout, + ) - else: - func(data) + else: + func(data) - return True + return True - except Exception as e: + except Exception as e: + debug( + f"[EventDispatcher] " + f"handler failed: " + f"event={event_name}, " + f"handler={func}" + ) - print( - f"[EventDispatcher] " - f"handler failed: " - f"event={event_name}, " - f"handler={func}" - ) + if self.log_traceback: + debug(f'{trackback.format_exc()}') + # traceback.print_exc() - if self.log_traceback: - traceback.print_exc() + await self._run_error_handler( + event_name, + func, + e, + ) - await self._run_error_handler( - event_name, - func, - e, - ) + if not self.continue_on_error: + raise - if not self.continue_on_error: - raise + return True - return True + async def dispatch( + self, + event_name: str, + data: Any = None, + ): - async def dispatch( - self, - event_name: str, - data: Any = None, - ): + if event_name not in self._events: + return - if event_name not in self._events: - return + dead_callbacks = [] - dead_callbacks = [] + for cb in list(self._events[event_name]): - for cb in list(self._events[event_name]): + func = cb.get() - func = cb.get() + if func is None: + dead_callbacks.append(cb) + continue - if func is None: - dead_callbacks.append(cb) - continue + await self._execute_handler( + cb, + event_name, + data, + ) - await self._execute_handler( - cb, - event_name, - data, - ) + for cb in dead_callbacks: + self._events[event_name].discard(cb) - for cb in dead_callbacks: - self._events[event_name].discard(cb) - - if ( - event_name in self._events - and not self._events[event_name] - ): - del self._events[event_name] + if ( + event_name in self._events + and not self._events[event_name] + ): + del self._events[event_name]