2323 MutableMapping ,
2424 NamedTuple ,
2525 Optional ,
26+ Protocol ,
2627 Sequence ,
2728 Set ,
2829 Tuple ,
@@ -106,6 +107,40 @@ def __repr__(self) -> str:
106107MAX_VARIABLE_ITEMS_DISPLAY = 500 # Maximum items to display in variable view
107108
108109
110+ # Type definitions for better type safety
111+ EvaluationResult = Union [Any , Exception ]
112+ KeywordCallable = Callable [[], EvaluationResult ]
113+ AttributeDict = Dict [str , Any ]
114+
115+
116+ class ExceptionInformation (TypedDict , total = False ):
117+ text : Optional [str ]
118+ description : str
119+ status : str
120+
121+
122+ class LogMessage (TypedDict , total = False ):
123+ level : str
124+ message : str
125+ timestamp : str
126+ html : Optional [str ]
127+
128+
129+ class RobotContextProtocol (Protocol ):
130+ """Protocol for Robot Framework execution context."""
131+
132+ variables : Any
133+ namespace : Any
134+
135+
136+ class KeywordHandlerProtocol (Protocol ):
137+ """Protocol for Robot Framework keyword handlers."""
138+
139+ name : str
140+ args : Any # Robot version dependent type
141+ arguments : Any # Robot version dependent type
142+
143+
109144class DebugRepr (reprlib .Repr ):
110145 def __init__ (self ) -> None :
111146 super ().__init__ ()
@@ -259,12 +294,14 @@ class PathMapping(NamedTuple):
259294 remote_root : Optional [str ]
260295
261296
262- if get_robot_version () < (7 , 0 ):
297+ class DebugLoggerBase :
298+ def __init__ (self ) -> None :
299+ self .steps : List [Any ] = []
300+
263301
264- class DebugLogger :
265- def __init__ (self ) -> None :
266- self .steps : List [Any ] = []
302+ if get_robot_version () < (7 , 0 ):
267303
304+ class DebugLogger (DebugLoggerBase ):
268305 def start_keyword (self , kw : Any ) -> None :
269306 self .steps .append (kw )
270307
@@ -275,10 +312,7 @@ def end_keyword(self, kw: Any) -> None:
275312 from robot import result , running
276313 from robot .output .loggerapi import LoggerApi
277314
278- class DebugLogger (LoggerApi ): # type: ignore[no-redef]
279- def __init__ (self ) -> None :
280- self .steps : List [Any ] = []
281-
315+ class DebugLogger (DebugLoggerBase , LoggerApi ): # type: ignore[no-redef]
282316 def start_try (self , data : "running.Try" , result : "result.Try" ) -> None :
283317 self .steps .append (data )
284318
@@ -295,12 +329,6 @@ def end_keyword(self, data: running.Keyword, result: result.Keyword) -> None:
295329breakpoint_id_manager = IdManager ()
296330
297331
298- class ExceptionInformation (TypedDict ):
299- text : Optional [str ]
300- description : str
301- status : str
302-
303-
304332class _DebuggerInstanceDescriptor :
305333 """Descriptor that forwards all attribute access to the singleton instance."""
306334
@@ -395,8 +423,8 @@ def __init__(self) -> None:
395423 self .attached = False
396424 self .path_mappings : List [PathMapping ] = []
397425
398- self ._keyword_to_evaluate : Optional [Callable [..., Any ] ] = None
399- self ._evaluated_keyword_result : Any = None
426+ self ._keyword_to_evaluate : Optional [KeywordCallable ] = None
427+ self ._evaluated_keyword_result : Optional [ EvaluationResult ] = None
400428 self ._evaluate_keyword_event = threading .Event ()
401429 self ._evaluate_keyword_event .set ()
402430 self ._after_evaluate_keyword_event = threading .Event ()
@@ -843,7 +871,7 @@ def wait_for_running(self) -> None:
843871 break
844872 self ._current_exception = None
845873
846- def start_output_group (self , name : str , attributes : Dict [ str , Any ] , type : Optional [str ] = None ) -> None :
874+ def start_output_group (self , name : str , attributes : AttributeDict , type : Optional [str ] = None ) -> None :
847875 if self .group_output :
848876 source = attributes .get ("source" )
849877 line_no = attributes .get ("lineno" )
@@ -862,7 +890,7 @@ def start_output_group(self, name: str, attributes: Dict[str, Any], type: Option
862890 ),
863891 )
864892
865- def end_output_group (self , name : str , attributes : Dict [ str , Any ] , type : Optional [str ] = None ) -> None :
893+ def end_output_group (self , name : str , attributes : AttributeDict , type : Optional [str ] = None ) -> None :
866894 if self .group_output :
867895 source = attributes .get ("source" )
868896 line_no = attributes .get ("lineno" )
@@ -889,7 +917,7 @@ def add_stackframe_entry(
889917 line : Optional [int ],
890918 column : Optional [int ] = None ,
891919 * ,
892- handler : Any = None ,
920+ handler : Optional [ KeywordHandlerProtocol ] = None ,
893921 libname : Optional [str ] = None ,
894922 kwname : Optional [str ] = None ,
895923 longname : Optional [str ] = None ,
@@ -943,7 +971,7 @@ def remove_stackframe_entry(
943971 line : Optional [int ],
944972 column : Optional [int ] = None ,
945973 * ,
946- handler : Any = None ,
974+ handler : Optional [ KeywordHandlerProtocol ] = None ,
947975 ) -> None :
948976 self .full_stack_frames .popleft ()
949977
@@ -961,7 +989,7 @@ def remove_stackframe_entry(
961989 if self .stack_frames :
962990 self .stack_frames [0 ].stack_frames .popleft ()
963991
964- def start_suite (self , name : str , attributes : Dict [ str , Any ] ) -> None :
992+ def start_suite (self , name : str , attributes : AttributeDict ) -> None :
965993 if self .state == State .CallKeyword :
966994 return
967995
@@ -1009,7 +1037,7 @@ def start_suite(self, name: str, attributes: Dict[str, Any]) -> None:
10091037
10101038 self .wait_for_running ()
10111039
1012- def end_suite (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1040+ def end_suite (self , name : str , attributes : AttributeDict ) -> None :
10131041 if self .state == State .CallKeyword :
10141042 return
10151043
@@ -1031,7 +1059,7 @@ def end_suite(self, name: str, attributes: Dict[str, Any]) -> None:
10311059
10321060 self .remove_stackframe_entry (name , type , source , line_no )
10331061
1034- def start_test (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1062+ def start_test (self , name : str , attributes : AttributeDict ) -> None :
10351063 if self .state == State .CallKeyword :
10361064 return
10371065
@@ -1058,7 +1086,7 @@ def start_test(self, name: str, attributes: Dict[str, Any]) -> None:
10581086
10591087 self .wait_for_running ()
10601088
1061- def end_test (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1089+ def end_test (self , name : str , attributes : AttributeDict ) -> None :
10621090 if self .state == State .CallKeyword :
10631091 return
10641092
@@ -1092,7 +1120,7 @@ def get_current_keyword_handler(self, name: str) -> UserKeywordHandler:
10921120 def get_current_keyword_handler (self , name : str ) -> UserKeywordHandler :
10931121 return EXECUTION_CONTEXTS .current .namespace .get_runner (name )._handler
10941122
1095- def start_keyword (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1123+ def start_keyword (self , name : str , attributes : AttributeDict ) -> None :
10961124 if self .state == State .CallKeyword :
10971125 return
10981126
@@ -1107,7 +1135,7 @@ def start_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
11071135 libname = attributes .get ("libname" )
11081136 kwname = attributes .get ("kwname" )
11091137
1110- handler : Any = None
1138+ handler : Optional [ KeywordHandlerProtocol ] = None
11111139 if type in ["KEYWORD" , "SETUP" , "TEARDOWN" ]:
11121140 try :
11131141 handler = self .get_current_keyword_handler (name )
@@ -1222,7 +1250,7 @@ def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
12221250 return False
12231251 return True
12241252
1225- def end_keyword (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1253+ def end_keyword (self , name : str , attributes : AttributeDict ) -> None :
12261254 if self .state == State .CallKeyword :
12271255 return
12281256
@@ -1253,7 +1281,7 @@ def end_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
12531281 type = attributes .get ("type" , "KEYWORD" )
12541282 kwname = attributes .get ("kwname" )
12551283
1256- handler : Any = None
1284+ handler : Optional [ KeywordHandlerProtocol ] = None
12571285 if type in ["KEYWORD" , "SETUP" , "TEARDOWN" ]:
12581286 try :
12591287 handler = self .get_current_keyword_handler (name )
@@ -1378,7 +1406,7 @@ def yield_stack() -> Iterator[StackFrame]:
13781406 "DEBUG" : "\u001b [38;5;8m" ,
13791407 }
13801408
1381- def log_message (self , message : Dict [ str , Any ] ) -> None :
1409+ def log_message (self , message : LogMessage ) -> None :
13821410 level = message ["level" ]
13831411 msg = message ["message" ]
13841412
@@ -1438,7 +1466,7 @@ def _build_output(self, level: str, msg: str, timestamp: str) -> str:
14381466 + f"{ msg } \n "
14391467 )
14401468
1441- def message (self , message : Dict [ str , Any ] ) -> None :
1469+ def message (self , message : LogMessage ) -> None :
14421470 level = message ["level" ]
14431471 current_frame = self .full_stack_frames [0 ] if self .full_stack_frames else None
14441472
@@ -1905,7 +1933,7 @@ def _create_evaluate_result(self, value: Any) -> EvaluateResult:
19051933
19061934 return EvaluateResult (result = repr (value ), type = repr (type (value )))
19071935
1908- def run_in_robot_thread (self , kw : Callable [[], Any ] ) -> Any :
1936+ def run_in_robot_thread (self , kw : KeywordCallable ) -> EvaluationResult :
19091937 with self .condition :
19101938 self ._keyword_to_evaluate = kw
19111939 self ._evaluated_keyword_result = None
0 commit comments