1717# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818
1919import asyncio
20+ from collections import OrderedDict
2021import inspect
2122import logging
22- from collections import OrderedDict
23+ from typing import Dict
2324
2425import pyrogram
2526from pyrogram import utils
2627from pyrogram .handlers import (
27- CallbackQueryHandler , MessageHandler , EditedMessageHandler , DeletedMessagesHandler ,
28+ Handler ,
29+ ErrorHandler , CallbackQueryHandler , MessageHandler , EditedMessageHandler , DeletedMessagesHandler ,
2830 UserStatusHandler , RawUpdateHandler , InlineQueryHandler , PollHandler , PreCheckoutQueryHandler ,
2931 ChosenInlineResultHandler , ChatMemberUpdatedHandler , ChatJoinRequestHandler , StoryHandler ,
3032 ShippingQueryHandler , MessageReactionHandler , MessageReactionCountHandler , ChatBoostHandler ,
@@ -294,7 +296,7 @@ async def stop(self, clear_handlers: bool = True):
294296
295297 log .info ("Stopped %s HandlerTasks" , self .client .workers )
296298
297- def add_handler (self , handler , group : int ):
299+ def add_handler (self , handler : Handler , group : int ):
298300 async def fn ():
299301 for lock in self .locks_list :
300302 await lock .acquire ()
@@ -311,16 +313,21 @@ async def fn():
311313
312314 self .client .loop .create_task (fn ())
313315
314- def remove_handler (self , handler , group : int ):
316+ def remove_handler (self , handler : Handler , group : int ):
315317 async def fn ():
316318 for lock in self .locks_list :
317319 await lock .acquire ()
318320
319321 try :
320322 if group not in self .groups :
321- raise ValueError (f"Group { group } does not exist. Handler was not removed." )
323+ raise ValueError (
324+ f"Group { group } does not exist. Handler was not removed."
325+ )
322326
323327 self .groups [group ].remove (handler )
328+
329+ if not self .groups [group ]:
330+ del self .groups [group ]
324331 finally :
325332 for lock in self .locks_list :
326333 lock .release ()
@@ -347,6 +354,9 @@ async def handler_worker(self, lock):
347354 async with lock :
348355 for group in self .groups .values ():
349356 for handler in group :
357+ if isinstance (handler , ErrorHandler ):
358+ continue
359+
350360 args = None
351361
352362 if isinstance (handler , handler_type ):
@@ -382,11 +392,62 @@ async def handler_worker(self, lock):
382392 raise
383393 except pyrogram .ContinuePropagation :
384394 continue
385- except Exception as e :
386- log .exception (e )
395+ except Exception as exc :
396+ await self .handle_update_handler_exception (
397+ exc , handler , update , users , chats
398+ )
387399
388400 break
389401 except pyrogram .StopPropagation :
390402 pass
391403 except Exception as e :
392404 log .exception (e )
405+
406+ async def handle_update_handler_exception (
407+ self ,
408+ exc : Exception ,
409+ update_handler : Handler ,
410+ update : "pyrogram.raw.base.Update" ,
411+ users : Dict [int , "pyrogram.raw.base.User" ],
412+ chats : Dict [int , "pyrogram.raw.base.Chat" ]
413+ ) -> None :
414+ handled = False
415+ try :
416+ for group in self .groups .values ():
417+ for handler in group :
418+ if not isinstance (handler , ErrorHandler ):
419+ continue
420+
421+ if not isinstance (exc , handler .exceptions ):
422+ continue
423+
424+ try :
425+ if inspect .iscoroutinefunction (handler .callback ):
426+ await handler .callback (
427+ self .client , exc , update_handler , update , users , chats
428+ )
429+ else :
430+ await self .client .loop .run_in_executor (
431+ self .client .executor , handler .callback ,
432+ self .client , exc , update_handler , update , users , chats
433+ )
434+ except pyrogram .StopPropagation :
435+ handled = True
436+ raise
437+ except pyrogram .ContinuePropagation :
438+ handled = True
439+ continue
440+ except Exception :
441+ log .exception ("Error handler raised an exception:" )
442+ else :
443+ handled = True
444+
445+ break
446+ except pyrogram .StopPropagation :
447+ pass
448+ finally :
449+ if not handled :
450+ log .error (
451+ f"Unexpected exception raised in { type (update_handler ).__name__ } :" ,
452+ exc_info = (type (exc ), exc , exc .__traceback__ )
453+ )
0 commit comments