1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
# (C) Copyright 2005-2023 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Tools for testing. """
from contextlib import contextmanager
import os
import sys
from pyface.qt.QtCore import QTimer
from pyface.util.guisupport import get_app_qt4
@contextmanager
def event_loop():
""" Post and process the Qt events at the exit of the code block. """
app = get_app_qt4()
yield
app.sendPostedEvents()
app.processEvents()
@contextmanager
def delete_widget(widget, timeout=1.0):
""" Context manager that executes the event loop so that we can safely
delete a Qt widget.
"""
app = get_app_qt4()
timer = QTimer()
timer.setSingleShot(True)
timer.setInterval(round(timeout * 1000))
timer.timeout.connect(app.quit)
widget.destroyed.connect(app.quit)
yield
timer.start()
if hasattr(app, 'exec'):
app.exec()
else:
app.exec_()
if not timer.isActive():
# We exited the event loop on timeout.
msg = "Could not destroy widget before timeout: {!r}"
raise AssertionError(msg.format(widget))
@contextmanager
def _convert_none_to_null_handle(stream):
""" If 'stream' is None, provide a temporary handle to /dev/null. """
if stream is None:
out = open(os.devnull, "w")
try:
yield out
finally:
out.close()
else:
yield stream
@contextmanager
def silence_output(out=None, err=None):
""" Re-direct the stderr and stdout streams while in the block. """
with _convert_none_to_null_handle(out) as out:
with _convert_none_to_null_handle(err) as err:
_old_stderr = sys.stderr
_old_stderr.flush()
_old_stdout = sys.stdout
_old_stdout.flush()
try:
sys.stdout = out
sys.stderr = err
yield
finally:
sys.stdout = _old_stdout
sys.stderr = _old_stderr
def print_qt_widget_tree(widget, level=0):
""" Debugging helper to print out the Qt widget tree starting at a
particular `widget`.
Parameters
----------
widget : QObject
The root widget in the tree to print.
level : int
The current level in the tree. Used internally for displaying the
tree level.
"""
level = level + 4
if level == 0:
print()
print(" " * level, widget)
for child in widget.children():
print_qt_widget_tree(child, level=level)
if level == 0:
print()
def find_qt_widget(start, type_, test=None):
"""Recursively walks the Qt widget tree from Qt widget `start` until it
finds a widget of type `type_` (a QWidget subclass) that
satisfies the provided `test` method.
Parameters
----------
start : QWidget
The widget from which to start walking the tree
type_ : type
A subclass of QWidget to use for an initial type filter while
walking the tree
test : Callable
A filter function that takes one argument (the current widget being
evaluated) and returns either True or False to determine if the
widget matches the required criteria.
"""
if test is None:
test = lambda widget: True
if isinstance(start, type_):
if test(start):
return start
for child in start.children():
widget = find_qt_widget(child, type_, test=test)
if widget:
return widget
return None
|