11import contextlib
2+ from types import TracebackType
23import weakref
34import warnings
4- from typing import TYPE_CHECKING , Callable , Optional , Any , cast
5+ from typing import TYPE_CHECKING , Callable , Generator , Iterator , List , Literal , Optional , Any , Self , Type , cast
6+ from pathlib import Path
57
68from pytestqt .exceptions import TimeoutError , ScreenshotError
79from pytestqt .qt_compat import qt_api
1214 SignalEmittedError ,
1315 CallbackBlocker ,
1416 CallbackCalledTwiceError ,
17+ CheckParamsCb ,
1518)
1619
20+ from pytest import FixtureRequest
21+
22+ # Type hint objects until figuring out how to import across qt
23+ # versions possibly using 'qtpy' library.
24+ QWidget = Any
25+ SignalInstance = Any
26+ QRect = Any
27+ QKeySequence = Any
28+
1729if TYPE_CHECKING :
18- # Type hint objects until figuring out how to import across qt
19- # versions possibly using 'qtpy' library.
20- QWidget = Any
30+ # Keep local import behavior the same.
31+ from pytestqt .exceptions import CapturedExceptions
2132
22- BeforeCloseFunc = Callable [["QWidget" ], None ]
33+ BeforeCloseFunc = Callable [[QWidget ], None ]
34+ WaitSignalsOrder = Literal ["none" , "simple" , "strict" ]
2335
2436
25- def _parse_ini_boolean (value : bool | str ) -> bool :
37+ def _parse_ini_boolean (value : Any ) -> bool :
2638 if value in (True , False ):
2739 return cast ("bool" , value )
2840 try :
@@ -154,7 +166,7 @@ class QtBot:
154166
155167 """
156168
157- def __init__ (self , request ) :
169+ def __init__ (self , request : FixtureRequest ) -> None :
158170 self ._request = request
159171 # pep8 aliases. Set here to automatically use implementations defined in sub-classes for alias creation
160172 self .add_widget = self .addWidget
@@ -168,7 +180,7 @@ def __init__(self, request):
168180 self .wait_until = self .waitUntil
169181 self .wait_callback = self .waitCallback
170182
171- def _should_raise (self , raising_arg ) :
183+ def _should_raise (self , raising_arg : Optional [ bool ]) -> bool :
172184 ini_val = self ._request .config .getini ("qt_default_raising" )
173185
174186 if raising_arg is not None :
@@ -178,7 +190,7 @@ def _should_raise(self, raising_arg):
178190 else :
179191 return True
180192
181- def addWidget (self , widget , * , before_close_func : Optional [BeforeCloseFunc ] = None ):
193+ def addWidget (self , widget : QWidget , * , before_close_func : Optional [BeforeCloseFunc ] = None ) -> None :
182194 """
183195 Adds a widget to be tracked by this bot. This is not required, but will ensure that the
184196 widget gets closed by the end of the test, so it is highly recommended.
@@ -196,7 +208,7 @@ def addWidget(self, widget, *, before_close_func: Optional[BeforeCloseFunc] = No
196208 raise TypeError (f"Need to pass a QWidget to addWidget: { widget !r} " )
197209 _add_widget (self ._request .node , widget , before_close_func = before_close_func )
198210
199- def waitActive (self , widget , * , timeout : int = 5000 ):
211+ def waitActive (self , widget : QWidget , * , timeout : int = 5000 ) -> "_WaitWidgetContextManager" :
200212 """
201213 Context manager that waits for ``timeout`` milliseconds or until the window is active.
202214 If window is not exposed within ``timeout`` milliseconds, raise
@@ -223,7 +235,7 @@ def waitActive(self, widget, *, timeout: int = 5000):
223235 "qWaitForWindowActive" , "activated" , widget , timeout
224236 )
225237
226- def waitExposed (self , widget , * , timeout = 5000 ):
238+ def waitExposed (self , widget : QWidget , * , timeout : int = 5000 ) -> "_WaitWidgetContextManager" :
227239 """
228240 Context manager that waits for ``timeout`` milliseconds or until the window is exposed.
229241 If the window is not exposed within ``timeout`` milliseconds, raise
@@ -250,7 +262,7 @@ def waitExposed(self, widget, *, timeout=5000):
250262 "qWaitForWindowExposed" , "exposed" , widget , timeout
251263 )
252264
253- def waitForWindowShown (self , widget ) :
265+ def waitForWindowShown (self , widget : QWidget ) -> bool :
254266 """
255267 Waits until the window is shown in the screen. This is mainly useful for asynchronous
256268 systems like X11, where a window will be mapped to screen some time after being asked to
@@ -282,7 +294,7 @@ def waitForWindowShown(self, widget):
282294 )
283295 return qt_api .QtTest .QTest .qWaitForWindowExposed (widget )
284296
285- def stop (self ):
297+ def stop (self ) -> None :
286298 """
287299 Stops the current test flow, letting the user interact with any visible widget.
288300
@@ -303,7 +315,14 @@ def stop(self):
303315 for widget , visible in widget_and_visibility :
304316 widget .setVisible (visible )
305317
306- def waitSignal (self , signal , * , timeout = 5000 , raising = None , check_params_cb = None ):
318+ def waitSignal (
319+ self ,
320+ signal : "SignalInstance" ,
321+ * ,
322+ timeout : int = 5000 ,
323+ raising : Optional [bool ] = None ,
324+ check_params_cb : Optional [CheckParamsCb ] = None ,
325+ ) -> "SignalBlocker" :
307326 """
308327 .. versionadded:: 1.2
309328
@@ -366,13 +385,13 @@ def waitSignal(self, signal, *, timeout=5000, raising=None, check_params_cb=None
366385
367386 def waitSignals (
368387 self ,
369- signals ,
388+ signals : List [ SignalInstance ] ,
370389 * ,
371- timeout = 5000 ,
372- raising = None ,
373- check_params_cbs = None ,
374- order = "none" ,
375- ):
390+ timeout : int = 5000 ,
391+ raising : Optional [ bool ] = None ,
392+ check_params_cbs : Optional [ List [ CheckParamsCb ]] = None ,
393+ order : WaitSignalsOrder = "none" ,
394+ ) -> "MultiSignalBlocker" :
376395 """
377396 .. versionadded:: 1.4
378397
@@ -454,7 +473,7 @@ def waitSignals(
454473 blocker .add_signals (signals )
455474 return blocker
456475
457- def wait (self , ms ) :
476+ def wait (self , ms : int ) -> None :
458477 """
459478 .. versionadded:: 1.9
460479
@@ -467,7 +486,7 @@ def wait(self, ms):
467486 blocker .wait ()
468487
469488 @contextlib .contextmanager
470- def assertNotEmitted (self , signal , * , wait = 0 ):
489+ def assertNotEmitted (self , signal : SignalInstance , * , wait : int = 0 ) -> Generator [ None , None , None ] :
471490 """
472491 .. versionadded:: 1.11
473492
@@ -488,7 +507,7 @@ def assertNotEmitted(self, signal, *, wait=0):
488507 yield
489508 spy .assert_not_emitted ()
490509
491- def waitUntil (self , callback , * , timeout = 5000 ):
510+ def waitUntil (self , callback : Callable [[], Optional [ bool ]], * , timeout : int = 5000 ) -> None :
492511 """
493512 .. versionadded:: 2.0
494513
@@ -559,7 +578,7 @@ def timed_out():
559578 raise TimeoutError (timeout_msg )
560579 self .wait (10 )
561580
562- def waitCallback (self , * , timeout = 5000 , raising = None ):
581+ def waitCallback (self , * , timeout : int = 5000 , raising : Optional [ bool ] = None ) -> "CallbackBlocker" :
563582 """
564583 .. versionadded:: 3.1
565584
@@ -601,7 +620,7 @@ def waitCallback(self, *, timeout=5000, raising=None):
601620 return blocker
602621
603622 @contextlib .contextmanager
604- def captureExceptions (self ):
623+ def captureExceptions (self ) -> Generator [ "CapturedExceptions" , None , None ] :
605624 """
606625 .. versionadded:: 2.1
607626
@@ -625,9 +644,7 @@ def captureExceptions(self):
625644 with capture_exceptions () as exceptions :
626645 yield exceptions
627646
628- capture_exceptions = captureExceptions
629-
630- def screenshot (self , widget , suffix = "" , region = None ):
647+ def screenshot (self , widget : QWidget , suffix : str = "" , region : Optional [QRect ]= None ) -> Path :
631648 """
632649 .. versionadded:: 4.1
633650
@@ -700,13 +717,13 @@ def keyRelease(*args, **kwargs):
700717 qt_api .QtTest .QTest .keyRelease (* args , ** kwargs )
701718
702719 @staticmethod
703- def keySequence (widget , key_sequence ) :
720+ def keySequence (widget : QWidget , key_sequence : QKeySequence ) -> None :
704721 if not hasattr (qt_api .QtTest .QTest , "keySequence" ):
705722 raise NotImplementedError ("This method is available from Qt 5.10 upwards." )
706723 qt_api .QtTest .QTest .keySequence (widget , key_sequence )
707724
708725 @staticmethod
709- def keyToAscii (key ) :
726+ def keyToAscii (key : Any ) -> None :
710727 if not hasattr (qt_api .QtTest .QTest , "keyToAscii" ):
711728 raise NotImplementedError ("This method isn't available on PyQt5." )
712729 qt_api .QtTest .QTest .keyToAscii (key )
@@ -740,11 +757,11 @@ def mouseRelease(*args, **kwargs):
740757
741758
742759def _add_widget (
743- item ,
744- widget ,
760+ item : Any ,
761+ widget : QWidget ,
745762 * ,
746763 before_close_func : Optional [BeforeCloseFunc ] = None ,
747- ):
764+ ) -> None :
748765 """
749766 Register a widget into the given pytest item for later closing.
750767 """
@@ -753,7 +770,7 @@ def _add_widget(
753770 item .qt_widgets = qt_widgets
754771
755772
756- def _close_widgets (item ) :
773+ def _close_widgets (item : Any ) -> None :
757774 """
758775 Close all widgets registered in the pytest item.
759776 """
@@ -769,7 +786,7 @@ def _close_widgets(item):
769786 del item .qt_widgets
770787
771788
772- def _iter_widgets (item ) :
789+ def _iter_widgets (item : Any ) -> Iterator [ weakref . ReferenceType [ QWidget ]] :
773790 """
774791 Iterates over widgets registered in the given pytest item.
775792 """
@@ -782,7 +799,7 @@ class _WaitWidgetContextManager:
782799 Context manager implementation used by ``waitActive`` and ``waitExposed`` methods.
783800 """
784801
785- def __init__ (self , method_name , adjective_name , widget , timeout ) :
802+ def __init__ (self , method_name : str , adjective_name : str , widget : QWidget , timeout : int ) -> None :
786803 """
787804 :param str method_name: name to the ``QtTest`` method to call to check if widget is active/exposed.
788805 :param str adjective_name: "activated" or "exposed".
@@ -794,11 +811,11 @@ def __init__(self, method_name, adjective_name, widget, timeout):
794811 self ._widget = widget
795812 self ._timeout = timeout
796813
797- def __enter__ (self ):
814+ def __enter__ (self ) -> Self :
798815 __tracebackhide__ = True
799816 return self
800817
801- def __exit__ (self , exc_type , exc_val , exc_tb ) :
818+ def __exit__ (self , exc_type : Optional [ Type [ BaseException ]] , exc_val : Optional [ BaseException ] , exc_tb : Optional [ TracebackType ]) -> None :
802819 __tracebackhide__ = True
803820 try :
804821 if exc_type is None :
0 commit comments