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
|
from functools import partial
from contextlib import contextmanager
import nose
import sys
import traceback
from traits.etsconfig.api import ETSConfig
# ######### Testing tools
@contextmanager
def store_exceptions_on_all_threads():
"""Context manager that captures all exceptions, even those coming from
the UI thread. On exit, the first exception is raised (if any).
"""
exceptions = []
def excepthook(type, value, tb):
exceptions.append(value)
message = 'Uncaught exception:\n'
message += ''.join(traceback.format_exception(type, value, tb))
print message
try:
sys.excepthook = excepthook
yield
finally:
if len(exceptions) > 0:
raise exceptions[0]
sys.excepthook = sys.__excepthook__
def skip_if_not_backend(test_func, backend_name=''):
"""Decorator that skip tests if the backend is not the desired one."""
if ETSConfig.toolkit != backend_name:
# preserve original name so that it appears in the report
orig_name = test_func.__name__
def test_func():
raise nose.SkipTest
test_func.__name__ = orig_name
return test_func
#: Test decorator: Skip test if backend is not 'wx'
skip_if_not_wx = partial(skip_if_not_backend, backend_name='wx')
#: Test decorator: Skip test if backend is not 'qt4'
skip_if_not_qt4 = partial(skip_if_not_backend, backend_name='qt4')
def count_calls(func):
"""Decorator that stores the number of times a function is called.
The counter is stored in func._n_counts.
"""
def wrapped(*args, **kwargs):
wrapped._n_calls += 1
return func(*args, **kwargs)
wrapped._n_calls = 0
return wrapped
# ######### Utility tools to test on both qt4 and wx
def get_children(node):
if ETSConfig.toolkit == 'wx':
return node.GetChildren()
else:
return node.children()
# ######### Debug tools
def apply_on_children(func, node, _level=0):
"""Print the result of applying a function on `node` and its children.
"""
print '-'*_level + str(node)
print ' '*_level + str(func(node)) + '\n'
for child in get_children(node):
apply_on_children(func, child, _level+1)
def wx_print_names(node):
"""Print the name and id of `node` and its children.
"""
apply_on_children(lambda n: (n.GetName(), n.GetId()), node)
def qt_print_names(node):
"""Print the name of `node` and its children.
"""
apply_on_children(lambda n: n.objectName(), node)
def wx_announce_when_destroyed(node):
"""Prints a message when `node` is destroyed.
Use as:
>>> ui = xxx.edit_traits()
>>> apply_on_children(wx_announce_when_destroyed, ui.control)
"""
_destroy_method = node.Destroy
def destroy_wrapped():
print 'Destroying:', node
#print 'Stack is'
#traceback.print_stack()
_destroy_method()
print 'Destroyed:', node
node.Destroy = destroy_wrapped
return 'Node {} decorated'.format(node.GetName())
def wx_find_event_by_number(evt_num):
"""Find all wx event names that correspond to a ceratin event number.
Example:
>>> wx_find_event_by_number(10010)
['wxEVT_COMMAND_MENU_SELECTED', 'wxEVT_COMMAND_TOOL_CLICKED']
"""
import wx
possible = [attr for attr in dir(wx)
if attr.startswith('wxEVT') and getattr(wx, attr) == evt_num]
return possible
|