2020import inspect
2121import logging
2222from collections import OrderedDict
23+ from operator import itemgetter
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 ,
@@ -78,6 +80,7 @@ def __init__(self, client: "pyrogram.Client"):
7880
7981 self .updates_queue = asyncio .Queue ()
8082 self .groups = OrderedDict ()
83+ self .error_handlers_groups = OrderedDict ()
8184
8285 async def message_parser (update , users , chats ):
8386 connection_id = getattr (update , "connection_id" , None )
@@ -294,17 +297,21 @@ async def stop(self, clear_handlers: bool = True):
294297
295298 log .info ("Stopped %s HandlerTasks" , self .client .workers )
296299
297- def add_handler (self , handler , group : int ):
300+ def add_handler (self , handler : Union [ Handler , ErrorHandler ] , group : int ):
298301 async def fn ():
299302 for lock in self .locks_list :
300303 await lock .acquire ()
301304
302305 try :
303- if group not in self .groups :
304- self .groups [group ] = []
305- self .groups = OrderedDict (sorted (self .groups .items ()))
306-
307- self .groups [group ].append (handler )
306+ if isinstance (handler , ErrorHandler ):
307+ self .error_handlers_groups .setdefault (group , []).append (handler )
308+ self .error_handlers_groups = OrderedDict (sorted (self .error_handlers_groups .items (), key = itemgetter (0 )))
309+ else :
310+ if group not in self .groups :
311+ self .groups [group ] = []
312+ self .groups = OrderedDict (sorted (self .groups .items ()))
313+
314+ self .groups [group ].append (handler )
308315 finally :
309316 for lock in self .locks_list :
310317 lock .release ()
@@ -317,10 +324,22 @@ async def fn():
317324 await lock .acquire ()
318325
319326 try :
320- if group not in self .groups :
321- raise ValueError (f"Group { group } does not exist. Handler was not removed." )
322-
323- self .groups [group ].remove (handler )
327+ if isinstance (handler , ErrorHandler ):
328+ if group not in self .error_handlers_groups :
329+ raise ValueError (
330+ f"Group { group } does not exist in error handlers; "
331+ "Error handler was not removed"
332+ )
333+
334+ self .error_handlers_groups [group ].remove (handler )
335+
336+ if not self .error_handlers_groups [group ]:
337+ del self .error_handlers_groups [group ]
338+ else :
339+ if group not in self .groups :
340+ raise ValueError (f"Group { group } does not exist. Handler was not removed." )
341+
342+ self .groups [group ].remove (handler )
324343 finally :
325344 for lock in self .locks_list :
326345 lock .release ()
@@ -382,11 +401,50 @@ async def handler_worker(self, lock):
382401 raise
383402 except pyrogram .ContinuePropagation :
384403 continue
385- except Exception as e :
386- log . exception ( e )
404+ except Exception as exc :
405+ await self . handle_update_handler_exception ( exc , handler , args )
387406
388407 break
389408 except pyrogram .StopPropagation :
390409 pass
391410 except Exception as e :
392411 log .exception (e )
412+
413+ async def handle_update_handler_exception (self , exc : Exception , update_handler : Handler , args : Tuple [Any , ...]) -> None :
414+ handled = False
415+ try :
416+ for group in self .error_handlers_groups .values ():
417+ for handler in group :
418+ if not isinstance (exc , handler .exceptions ):
419+ continue
420+
421+ try :
422+ if inspect .iscoroutinefunction (handler .callback ):
423+ await handler .callback (
424+ exc , update_handler , self .client , * args
425+ )
426+ else :
427+ await self .client .loop .run_in_executor (
428+ self .client .executor , handler .callback ,
429+ exc , update_handler , self .client , * args
430+ )
431+ except pyrogram .StopPropagation :
432+ handled = True
433+ raise
434+ except pyrogram .ContinuePropagation :
435+ handled = True
436+ continue
437+ except Exception :
438+ log .exception ("Error handler raised an exception:" )
439+ else :
440+ handled = True
441+
442+ break
443+ except pyrogram .StopPropagation :
444+ pass
445+ finally :
446+ if not handled :
447+ log .error (
448+ f"Unexpected exception raised in { type (update_handler ).__name__ } :" ,
449+ exc_info = (type (exc ), exc , exc .__traceback__ )
450+ )
0 commit comments