schrodinger.test.hypothesis.stateful module

class schrodinger.test.hypothesis.stateful.RuleBasedStateMachineMetaClass(name, bases, dct)[source]

Bases: hypothesis.stateful.StateMachineMeta

A metaclass that makes it easy to create simple rules for a RuleBasedStateMachine.

‘Simple’ in this context means that the rule we want to create
  1. calls a method that takes no argument, and then

  2. doesn’t check any results

The only thing that we’re testing with a rule like this is that calling the method never results in an unhandled exception. Ideally, we would check the results of calling methods, but even the lazy route is surprisingly useful in a state machine test. Advice: begin by adding as many of these simple rules as possible and then gradually replace them with richer rules and checks as the tests develop and experience indicates which checks are most valuable.

Suppose that we are testing self.panel in our state machine and want to call the methods ‘foo’ on self.panel.bar and ‘gar’ on self.panel.mar. We could write this:

class PanelMachine(stateful.RuleBaseStateMachine):
    def __init__(self):
        super(PanelMachine, self).__init__()
        self.panel = MyPanel()

    @stateful.rule()
    def foo(self):
        self.panel.bar.foo()

    @stateful.rule()
    def gar(self):
        self.panel.mar.gar()

But this quickly becomes tedious if we want to test a large number of such methods. Our metaclass will allow us to generate the desired rules for our state machine by adding strings to the SIMPLE_RULES tuple defined on the class:

@six.add_metaclass(RuleBasedStateMachineMetaClass)
class PanelMachine(stateful.RuleBaseStateMachine):
    SIMPLE_RULES = ('panel.bar.foo', 'panel.bar.gar')

def __init__(self):
    super(PanelMachine, self).__init__()
    self.panel = MyPanel()
__init__(*args, **kwargs)
mro()

Return a type’s method resolution order.

class schrodinger.test.hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine(trap_errors=True)[source]

Bases: hypothesis.stateful.RuleBasedStateMachine

A RuleBasedStateMachine that fails if any Qt warnings or errors are reported or if any exceptions are raised in a slot. Without this class:

  • Qt warnings and errors are ignored.

  • Exceptions that are raised in a slot cause the test to fail with a “Exceptions caught outside of main thread:” message, but Hypothesis doesn’t report the steps required to reproduce the exception.

Note

The error checkers in this class are implemented in two parts. _recordException and _recordQtWarningsAndErrors record any problems that happen during a step, and the invariant checkErrors makes sure that no problems were recorded at the end of each step. Any exception raised in one of the _record wouldn’t be recognized by Hypothesis and would instead go directly to the top-level error handler, so the two step approach is required.

Variables
  • FAIL_ON_QT_MSGS (tuple or list or set) – What Qt message types should trigger a test failure. By default warnings, criticals, and fatals lead to a test failure while debug and info messages are ignored. This can be modified in subclasses if desired.

  • QT_MSG_NAMES (dict(int, str)) – A mapping from QtMsgType values to a textual description.

  • IGNORE_WARN_PREFIXES (iterable(str)) – Any Qt warning message that starts with a string listed here will be ignored. Warning messages filtered by qt_message_handler.filter_qt_msg will be ignored regardless of this var.

FAIL_ON_QT_MSGS = (1, 2, 3)
QT_MSG_NAMES = {0: 'debug', 1: 'warning', 2: 'critical', 3: 'fatal', 4: 'info'}
IGNORE_WARN_PREFIXES = ()
__init__(trap_errors=True)[source]
Parameters

trap_errors (bool) – Whether to override the top-level exception handler and catch all Qt warnings and errors. Setting this to False is only useful for interactive use of this object, i.e. instantiating one in a REPL. Otherwise, all REPL tracebacks would be swallowed by the excepthook.

teardown()[source]

Reset the top-level exception handler and Qt’s message handler once the test is done.

checkErrors()[source]

Fail if the current trial raised an unhandled exception or triggered a Qt warning or error.

TestCase

alias of hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine.TestCase

bundle(name)
check_invariants()
classmethod initialize_rules()
classmethod invariants()
classmethod rules()
class schrodinger.test.hypothesis.stateful.PanelRuleBasedStateMachine(*args, **kwargs)[source]

Bases: schrodinger.test.hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine

A RuleBasedStateMachine for use with a Qt-based panel. Subclasses must define PANEL_CLASS, and the panel instance will be available as self.panel. Without this class:

  • QTimers may not fire when they are supposed to

  • Errors that occur during painting will not be caught

  • Errors in stateful decorator arguments may cause pytest to segfault

Variables

PANEL_CLASS (QtWidgets.QWidget) – The class of the panel to test.

PANEL_CLASS = None
__init__(*args, **kwargs)[source]
Parameters

trap_errors (bool) – Whether to override the top-level exception handler and catch all Qt warnings and errors. Setting this to False is only useful for interactive use of this object, i.e. instantiating one in a REPL. Otherwise, all REPL tracebacks would be swallowed by the excepthook.

teardown()[source]

Reset the top-level exception handler and Qt’s message handler once the test is done.

check_invariants()[source]

Make sure we process events after each step so that any QTimers with timeouts of 0 will fire when they’re supposed to.

FAIL_ON_QT_MSGS = (1, 2, 3)
IGNORE_WARN_PREFIXES = ()
QT_MSG_NAMES = {0: 'debug', 1: 'warning', 2: 'critical', 3: 'fatal', 4: 'info'}
TestCase

alias of hypothesis.stateful.PanelRuleBasedStateMachine.TestCase

bundle(name)
checkErrors()

Fail if the current trial raised an unhandled exception or triggered a Qt warning or error.

classmethod initialize_rules()
classmethod invariants()
classmethod rules()
bundles: Dict[str, list]
names_to_values: Dict[str, Any]