1
1
import contextlib
2
+ from types import TracebackType
2
3
import weakref
3
4
import 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
5
7
6
8
from pytestqt .exceptions import TimeoutError , ScreenshotError
7
9
from pytestqt .qt_compat import qt_api
12
14
SignalEmittedError ,
13
15
CallbackBlocker ,
14
16
CallbackCalledTwiceError ,
17
+ CheckParamsCb ,
15
18
)
16
19
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
+
17
29
if 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
21
32
22
- BeforeCloseFunc = Callable [["QWidget" ], None ]
33
+ BeforeCloseFunc = Callable [[QWidget ], None ]
34
+ WaitSignalsOrder = Literal ["none" , "simple" , "strict" ]
23
35
24
36
25
- def _parse_ini_boolean (value : bool | str ) -> bool :
37
+ def _parse_ini_boolean (value : Any ) -> bool :
26
38
if value in (True , False ):
27
39
return cast ("bool" , value )
28
40
try :
@@ -154,7 +166,7 @@ class QtBot:
154
166
155
167
"""
156
168
157
- def __init__ (self , request ) :
169
+ def __init__ (self , request : FixtureRequest ) -> None :
158
170
self ._request = request
159
171
# pep8 aliases. Set here to automatically use implementations defined in sub-classes for alias creation
160
172
self .add_widget = self .addWidget
@@ -168,7 +180,7 @@ def __init__(self, request):
168
180
self .wait_until = self .waitUntil
169
181
self .wait_callback = self .waitCallback
170
182
171
- def _should_raise (self , raising_arg ) :
183
+ def _should_raise (self , raising_arg : Optional [ bool ]) -> bool :
172
184
ini_val = self ._request .config .getini ("qt_default_raising" )
173
185
174
186
if raising_arg is not None :
@@ -178,7 +190,7 @@ def _should_raise(self, raising_arg):
178
190
else :
179
191
return True
180
192
181
- def addWidget (self , widget , * , before_close_func : Optional [BeforeCloseFunc ] = None ):
193
+ def addWidget (self , widget : QWidget , * , before_close_func : Optional [BeforeCloseFunc ] = None ) -> None :
182
194
"""
183
195
Adds a widget to be tracked by this bot. This is not required, but will ensure that the
184
196
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
196
208
raise TypeError (f"Need to pass a QWidget to addWidget: { widget !r} " )
197
209
_add_widget (self ._request .node , widget , before_close_func = before_close_func )
198
210
199
- def waitActive (self , widget , * , timeout : int = 5000 ):
211
+ def waitActive (self , widget : QWidget , * , timeout : int = 5000 ) -> "_WaitWidgetContextManager" :
200
212
"""
201
213
Context manager that waits for ``timeout`` milliseconds or until the window is active.
202
214
If window is not exposed within ``timeout`` milliseconds, raise
@@ -223,7 +235,7 @@ def waitActive(self, widget, *, timeout: int = 5000):
223
235
"qWaitForWindowActive" , "activated" , widget , timeout
224
236
)
225
237
226
- def waitExposed (self , widget , * , timeout = 5000 ):
238
+ def waitExposed (self , widget : QWidget , * , timeout : int = 5000 ) -> "_WaitWidgetContextManager" :
227
239
"""
228
240
Context manager that waits for ``timeout`` milliseconds or until the window is exposed.
229
241
If the window is not exposed within ``timeout`` milliseconds, raise
@@ -250,7 +262,7 @@ def waitExposed(self, widget, *, timeout=5000):
250
262
"qWaitForWindowExposed" , "exposed" , widget , timeout
251
263
)
252
264
253
- def waitForWindowShown (self , widget ) :
265
+ def waitForWindowShown (self , widget : QWidget ) -> bool :
254
266
"""
255
267
Waits until the window is shown in the screen. This is mainly useful for asynchronous
256
268
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):
282
294
)
283
295
return qt_api .QtTest .QTest .qWaitForWindowExposed (widget )
284
296
285
- def stop (self ):
297
+ def stop (self ) -> None :
286
298
"""
287
299
Stops the current test flow, letting the user interact with any visible widget.
288
300
@@ -303,7 +315,14 @@ def stop(self):
303
315
for widget , visible in widget_and_visibility :
304
316
widget .setVisible (visible )
305
317
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" :
307
326
"""
308
327
.. versionadded:: 1.2
309
328
@@ -366,13 +385,13 @@ def waitSignal(self, signal, *, timeout=5000, raising=None, check_params_cb=None
366
385
367
386
def waitSignals (
368
387
self ,
369
- signals ,
388
+ signals : List [ SignalInstance ] ,
370
389
* ,
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" :
376
395
"""
377
396
.. versionadded:: 1.4
378
397
@@ -454,7 +473,7 @@ def waitSignals(
454
473
blocker .add_signals (signals )
455
474
return blocker
456
475
457
- def wait (self , ms ) :
476
+ def wait (self , ms : int ) -> None :
458
477
"""
459
478
.. versionadded:: 1.9
460
479
@@ -467,7 +486,7 @@ def wait(self, ms):
467
486
blocker .wait ()
468
487
469
488
@contextlib .contextmanager
470
- def assertNotEmitted (self , signal , * , wait = 0 ):
489
+ def assertNotEmitted (self , signal : SignalInstance , * , wait : int = 0 ) -> Generator [ None , None , None ] :
471
490
"""
472
491
.. versionadded:: 1.11
473
492
@@ -488,7 +507,7 @@ def assertNotEmitted(self, signal, *, wait=0):
488
507
yield
489
508
spy .assert_not_emitted ()
490
509
491
- def waitUntil (self , callback , * , timeout = 5000 ):
510
+ def waitUntil (self , callback : Callable [[], Optional [ bool ]], * , timeout : int = 5000 ) -> None :
492
511
"""
493
512
.. versionadded:: 2.0
494
513
@@ -559,7 +578,7 @@ def timed_out():
559
578
raise TimeoutError (timeout_msg )
560
579
self .wait (10 )
561
580
562
- def waitCallback (self , * , timeout = 5000 , raising = None ):
581
+ def waitCallback (self , * , timeout : int = 5000 , raising : Optional [ bool ] = None ) -> "CallbackBlocker" :
563
582
"""
564
583
.. versionadded:: 3.1
565
584
@@ -601,7 +620,7 @@ def waitCallback(self, *, timeout=5000, raising=None):
601
620
return blocker
602
621
603
622
@contextlib .contextmanager
604
- def captureExceptions (self ):
623
+ def captureExceptions (self ) -> Generator [ "CapturedExceptions" , None , None ] :
605
624
"""
606
625
.. versionadded:: 2.1
607
626
@@ -625,9 +644,7 @@ def captureExceptions(self):
625
644
with capture_exceptions () as exceptions :
626
645
yield exceptions
627
646
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 :
631
648
"""
632
649
.. versionadded:: 4.1
633
650
@@ -700,13 +717,13 @@ def keyRelease(*args, **kwargs):
700
717
qt_api .QtTest .QTest .keyRelease (* args , ** kwargs )
701
718
702
719
@staticmethod
703
- def keySequence (widget , key_sequence ) :
720
+ def keySequence (widget : QWidget , key_sequence : QKeySequence ) -> None :
704
721
if not hasattr (qt_api .QtTest .QTest , "keySequence" ):
705
722
raise NotImplementedError ("This method is available from Qt 5.10 upwards." )
706
723
qt_api .QtTest .QTest .keySequence (widget , key_sequence )
707
724
708
725
@staticmethod
709
- def keyToAscii (key ) :
726
+ def keyToAscii (key : Any ) -> None :
710
727
if not hasattr (qt_api .QtTest .QTest , "keyToAscii" ):
711
728
raise NotImplementedError ("This method isn't available on PyQt5." )
712
729
qt_api .QtTest .QTest .keyToAscii (key )
@@ -740,11 +757,11 @@ def mouseRelease(*args, **kwargs):
740
757
741
758
742
759
def _add_widget (
743
- item ,
744
- widget ,
760
+ item : Any ,
761
+ widget : QWidget ,
745
762
* ,
746
763
before_close_func : Optional [BeforeCloseFunc ] = None ,
747
- ):
764
+ ) -> None :
748
765
"""
749
766
Register a widget into the given pytest item for later closing.
750
767
"""
@@ -753,7 +770,7 @@ def _add_widget(
753
770
item .qt_widgets = qt_widgets
754
771
755
772
756
- def _close_widgets (item ) :
773
+ def _close_widgets (item : Any ) -> None :
757
774
"""
758
775
Close all widgets registered in the pytest item.
759
776
"""
@@ -769,7 +786,7 @@ def _close_widgets(item):
769
786
del item .qt_widgets
770
787
771
788
772
- def _iter_widgets (item ) :
789
+ def _iter_widgets (item : Any ) -> Iterator [ weakref . ReferenceType [ QWidget ]] :
773
790
"""
774
791
Iterates over widgets registered in the given pytest item.
775
792
"""
@@ -782,7 +799,7 @@ class _WaitWidgetContextManager:
782
799
Context manager implementation used by ``waitActive`` and ``waitExposed`` methods.
783
800
"""
784
801
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 :
786
803
"""
787
804
:param str method_name: name to the ``QtTest`` method to call to check if widget is active/exposed.
788
805
:param str adjective_name: "activated" or "exposed".
@@ -794,11 +811,11 @@ def __init__(self, method_name, adjective_name, widget, timeout):
794
811
self ._widget = widget
795
812
self ._timeout = timeout
796
813
797
- def __enter__ (self ):
814
+ def __enter__ (self ) -> Self :
798
815
__tracebackhide__ = True
799
816
return self
800
817
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 :
802
819
__tracebackhide__ = True
803
820
try :
804
821
if exc_type is None :
0 commit comments