23
23
MutableMapping ,
24
24
NamedTuple ,
25
25
Optional ,
26
+ Protocol ,
26
27
Sequence ,
27
28
Set ,
28
29
Tuple ,
@@ -106,6 +107,40 @@ def __repr__(self) -> str:
106
107
MAX_VARIABLE_ITEMS_DISPLAY = 500 # Maximum items to display in variable view
107
108
108
109
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
+
109
144
class DebugRepr (reprlib .Repr ):
110
145
def __init__ (self ) -> None :
111
146
super ().__init__ ()
@@ -259,12 +294,14 @@ class PathMapping(NamedTuple):
259
294
remote_root : Optional [str ]
260
295
261
296
262
- if get_robot_version () < (7 , 0 ):
297
+ class DebugLoggerBase :
298
+ def __init__ (self ) -> None :
299
+ self .steps : List [Any ] = []
300
+
263
301
264
- class DebugLogger :
265
- def __init__ (self ) -> None :
266
- self .steps : List [Any ] = []
302
+ if get_robot_version () < (7 , 0 ):
267
303
304
+ class DebugLogger (DebugLoggerBase ):
268
305
def start_keyword (self , kw : Any ) -> None :
269
306
self .steps .append (kw )
270
307
@@ -275,10 +312,7 @@ def end_keyword(self, kw: Any) -> None:
275
312
from robot import result , running
276
313
from robot .output .loggerapi import LoggerApi
277
314
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]
282
316
def start_try (self , data : "running.Try" , result : "result.Try" ) -> None :
283
317
self .steps .append (data )
284
318
@@ -295,12 +329,6 @@ def end_keyword(self, data: running.Keyword, result: result.Keyword) -> None:
295
329
breakpoint_id_manager = IdManager ()
296
330
297
331
298
- class ExceptionInformation (TypedDict ):
299
- text : Optional [str ]
300
- description : str
301
- status : str
302
-
303
-
304
332
class _DebuggerInstanceDescriptor :
305
333
"""Descriptor that forwards all attribute access to the singleton instance."""
306
334
@@ -395,8 +423,8 @@ def __init__(self) -> None:
395
423
self .attached = False
396
424
self .path_mappings : List [PathMapping ] = []
397
425
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
400
428
self ._evaluate_keyword_event = threading .Event ()
401
429
self ._evaluate_keyword_event .set ()
402
430
self ._after_evaluate_keyword_event = threading .Event ()
@@ -843,7 +871,7 @@ def wait_for_running(self) -> None:
843
871
break
844
872
self ._current_exception = None
845
873
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 :
847
875
if self .group_output :
848
876
source = attributes .get ("source" )
849
877
line_no = attributes .get ("lineno" )
@@ -862,7 +890,7 @@ def start_output_group(self, name: str, attributes: Dict[str, Any], type: Option
862
890
),
863
891
)
864
892
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 :
866
894
if self .group_output :
867
895
source = attributes .get ("source" )
868
896
line_no = attributes .get ("lineno" )
@@ -889,7 +917,7 @@ def add_stackframe_entry(
889
917
line : Optional [int ],
890
918
column : Optional [int ] = None ,
891
919
* ,
892
- handler : Any = None ,
920
+ handler : Optional [ KeywordHandlerProtocol ] = None ,
893
921
libname : Optional [str ] = None ,
894
922
kwname : Optional [str ] = None ,
895
923
longname : Optional [str ] = None ,
@@ -943,7 +971,7 @@ def remove_stackframe_entry(
943
971
line : Optional [int ],
944
972
column : Optional [int ] = None ,
945
973
* ,
946
- handler : Any = None ,
974
+ handler : Optional [ KeywordHandlerProtocol ] = None ,
947
975
) -> None :
948
976
self .full_stack_frames .popleft ()
949
977
@@ -961,7 +989,7 @@ def remove_stackframe_entry(
961
989
if self .stack_frames :
962
990
self .stack_frames [0 ].stack_frames .popleft ()
963
991
964
- def start_suite (self , name : str , attributes : Dict [ str , Any ] ) -> None :
992
+ def start_suite (self , name : str , attributes : AttributeDict ) -> None :
965
993
if self .state == State .CallKeyword :
966
994
return
967
995
@@ -1009,7 +1037,7 @@ def start_suite(self, name: str, attributes: Dict[str, Any]) -> None:
1009
1037
1010
1038
self .wait_for_running ()
1011
1039
1012
- def end_suite (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1040
+ def end_suite (self , name : str , attributes : AttributeDict ) -> None :
1013
1041
if self .state == State .CallKeyword :
1014
1042
return
1015
1043
@@ -1031,7 +1059,7 @@ def end_suite(self, name: str, attributes: Dict[str, Any]) -> None:
1031
1059
1032
1060
self .remove_stackframe_entry (name , type , source , line_no )
1033
1061
1034
- def start_test (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1062
+ def start_test (self , name : str , attributes : AttributeDict ) -> None :
1035
1063
if self .state == State .CallKeyword :
1036
1064
return
1037
1065
@@ -1058,7 +1086,7 @@ def start_test(self, name: str, attributes: Dict[str, Any]) -> None:
1058
1086
1059
1087
self .wait_for_running ()
1060
1088
1061
- def end_test (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1089
+ def end_test (self , name : str , attributes : AttributeDict ) -> None :
1062
1090
if self .state == State .CallKeyword :
1063
1091
return
1064
1092
@@ -1092,7 +1120,7 @@ def get_current_keyword_handler(self, name: str) -> UserKeywordHandler:
1092
1120
def get_current_keyword_handler (self , name : str ) -> UserKeywordHandler :
1093
1121
return EXECUTION_CONTEXTS .current .namespace .get_runner (name )._handler
1094
1122
1095
- def start_keyword (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1123
+ def start_keyword (self , name : str , attributes : AttributeDict ) -> None :
1096
1124
if self .state == State .CallKeyword :
1097
1125
return
1098
1126
@@ -1107,7 +1135,7 @@ def start_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
1107
1135
libname = attributes .get ("libname" )
1108
1136
kwname = attributes .get ("kwname" )
1109
1137
1110
- handler : Any = None
1138
+ handler : Optional [ KeywordHandlerProtocol ] = None
1111
1139
if type in ["KEYWORD" , "SETUP" , "TEARDOWN" ]:
1112
1140
try :
1113
1141
handler = self .get_current_keyword_handler (name )
@@ -1222,7 +1250,7 @@ def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1222
1250
return False
1223
1251
return True
1224
1252
1225
- def end_keyword (self , name : str , attributes : Dict [ str , Any ] ) -> None :
1253
+ def end_keyword (self , name : str , attributes : AttributeDict ) -> None :
1226
1254
if self .state == State .CallKeyword :
1227
1255
return
1228
1256
@@ -1253,7 +1281,7 @@ def end_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
1253
1281
type = attributes .get ("type" , "KEYWORD" )
1254
1282
kwname = attributes .get ("kwname" )
1255
1283
1256
- handler : Any = None
1284
+ handler : Optional [ KeywordHandlerProtocol ] = None
1257
1285
if type in ["KEYWORD" , "SETUP" , "TEARDOWN" ]:
1258
1286
try :
1259
1287
handler = self .get_current_keyword_handler (name )
@@ -1378,7 +1406,7 @@ def yield_stack() -> Iterator[StackFrame]:
1378
1406
"DEBUG" : "\u001b [38;5;8m" ,
1379
1407
}
1380
1408
1381
- def log_message (self , message : Dict [ str , Any ] ) -> None :
1409
+ def log_message (self , message : LogMessage ) -> None :
1382
1410
level = message ["level" ]
1383
1411
msg = message ["message" ]
1384
1412
@@ -1438,7 +1466,7 @@ def _build_output(self, level: str, msg: str, timestamp: str) -> str:
1438
1466
+ f"{ msg } \n "
1439
1467
)
1440
1468
1441
- def message (self , message : Dict [ str , Any ] ) -> None :
1469
+ def message (self , message : LogMessage ) -> None :
1442
1470
level = message ["level" ]
1443
1471
current_frame = self .full_stack_frames [0 ] if self .full_stack_frames else None
1444
1472
@@ -1905,7 +1933,7 @@ def _create_evaluate_result(self, value: Any) -> EvaluateResult:
1905
1933
1906
1934
return EvaluateResult (result = repr (value ), type = repr (type (value )))
1907
1935
1908
- def run_in_robot_thread (self , kw : Callable [[], Any ] ) -> Any :
1936
+ def run_in_robot_thread (self , kw : KeywordCallable ) -> EvaluationResult :
1909
1937
with self .condition :
1910
1938
self ._keyword_to_evaluate = kw
1911
1939
self ._evaluated_keyword_result = None
0 commit comments