1+ from abc import ABCMeta
12from uuid import uuid4
23
34from pybotx import Bot , IncomingMessage
910 SendErrorExplainToUserHandler ,
1011)
1112
13+ HandlerOrHandlerClass = (
14+ AbstractExceptionHandler | type [AbstractExceptionHandler ] | ABCMeta
15+ )
16+
1217
1318class ExceptionHandlersChainExecutor :
1419 """
@@ -24,7 +29,8 @@ class ExceptionHandlersChainExecutor:
2429 """
2530
2631 def __init__ (
27- self , handlers : list [type [AbstractExceptionHandler ] | AbstractExceptionHandler ]
32+ self ,
33+ handlers : list [HandlerOrHandlerClass ] | None = None ,
2834 ):
2935 self ._chain_head , self ._chain_tail = self ._create_chain (handlers )
3036
@@ -52,13 +58,26 @@ async def execute_chain(
5258 await self ._chain_head .handle_exception (exc , bot , message , exception_id )
5359
5460 def _get_handler (
55- self , handler : AbstractExceptionHandler | type [AbstractExceptionHandler ]
61+ self ,
62+ handler : HandlerOrHandlerClass ,
5663 ) -> AbstractExceptionHandler :
5764 return handler if isinstance (handler , AbstractExceptionHandler ) else handler ()
5865
5966 def _create_chain (
60- self , handlers : list [type [AbstractExceptionHandler ] | AbstractExceptionHandler ]
67+ self ,
68+ handlers : list [HandlerOrHandlerClass ] | None = None ,
6169 ) -> tuple [AbstractExceptionHandler | None , AbstractExceptionHandler | None ]:
70+ """
71+ Create a linked list of exception handlers from the given list.
72+
73+ This method takes a sequence of exception handler classes or instances
74+ and chains them together into a linked list. The returned tuple contains
75+ the head and tail of the constructed chain.
76+
77+ warning:
78+ This method modifies the passed objects of
79+ class:`AbstractExceptionHandler` type in place.
80+ """
6281 if not handlers :
6382 return None , None
6483
@@ -71,29 +90,39 @@ def _create_chain(
7190 tail_handler = new_tail_handler
7291 return head_handler , tail_handler
7392
74- def extend (
75- self , handlers : list [AbstractExceptionHandler | type [AbstractExceptionHandler ]]
76- ):
93+ def extend (self , handlers : list [HandlerOrHandlerClass ] | None ) -> None :
7794 """Append handlers to the chain"""
95+ if not handlers :
96+ return
97+
7898 new_head , new_tail = self ._create_chain (handlers )
79- if self ._chain_head is None :
99+ if self ._is_empty () :
80100 self ._chain_head = new_head
81101 else :
82- self ._chain_tail .next_handler = new_head
102+ # The tail and head cannot be None at the same time.
103+ self ._chain_tail .next_handler = new_head # type: ignore
83104
84105 self ._chain_tail = new_tail
85106
86- def append (
87- self , handler : AbstractExceptionHandler | type [AbstractExceptionHandler ]
88- ):
89- """Append handler to the end of chain"""
107+ def append (self , handler : HandlerOrHandlerClass ) -> None :
108+ """Append handler to the end of a chain"""
90109 new_tail = self ._get_handler (handler )
91- self ._chain_tail .next_handler = new_tail
92110
111+ if self ._is_empty ():
112+ self ._chain_head = new_tail
113+ self ._chain_tail = new_tail
114+ else :
115+ self ._chain_tail .next_handler = new_tail # type:ignore
116+
117+ def _is_empty (self ) -> bool :
118+ return self ._chain_head is None and self ._chain_tail is None
93119
94- DEFAULT_HANDLERS = [
120+
121+ DEFAULT_HANDLERS : list [HandlerOrHandlerClass ] = [
95122 LoggingExceptionHandler ,
96123 DropFSMOnErrorHandler ,
97124]
98125
99- DEFAULT_HANDLERS_WITH_EXPLAIN = DEFAULT_HANDLERS + [SendErrorExplainToUserHandler ]
126+ DEFAULT_HANDLERS_WITH_EXPLAIN : list [HandlerOrHandlerClass ] = DEFAULT_HANDLERS + [
127+ SendErrorExplainToUserHandler
128+ ]
0 commit comments