r""" halt-at-nth-failure.py

See here a concise way to harness doctest to HALT_AT_NTH_FAILURE,
even though that's not yet a doc'ed option like REPORT_ONLY_FIRST_FAILURE.

See also: http://docs.python.org/lib/module-doctest.html

Sorry you'll have to work harder if you need to doctest code
that uses more than the write method of sys.stdout.

An example of an illuminating result:

$ python ./halt-at-nth-failure.py
1
**********************************************************************
File "./halt-at-nth-failure.py", line 47, in __main__
Failed example:
    0 + 1
Expected:
    111
Got:
    1
2
3
**********************************************************************
File "./halt-at-nth-failure.py", line 57, in __main__
Failed example:
    2 + 1
Expected:
    333
Got:
    3
**********************************************************************
1 item interrupted
***Test Failed***
$

appears when this source file contains such input as:

>>> import sys

>>> print 'Hello, doctest world.'
Hello, doctest world.
>>>

>>> print >>sys.stderr, 1
>>> 0 + 1
111
>>>

>>> print >>sys.stderr, 2
>>> 1 + 1
2
>>>

>>> print >>sys.stderr, 3
>>> 2 + 1
333
>>>

>>> print >>sys.stderr, 4
>>> 3 + 1
444
>>>

"""

import sys

class DocTestExit(KeyboardInterrupt):

        """
        Write out the bytes passed to self.write.
        Raise self after self.write called to write the trigger the nth time.
        Derive self from KeyboardInterrupt to exit doctest when raised.
        Count each call containing the trigger, not all exact matches.
        """

        def __init__(self,
                out,
                nth = 1,
                trigger = '\nFailed example:\n'
        ):

                self.triggerings = nth # -1 == don't halt
                self.out = out
                self.trigger = trigger

                self.write = self.writeOut

        def writeOut(self, bytes):

                self.out.write(bytes)

                if 0 <= bytes.find(self.trigger):
                        self.triggerings -= 1
                        if self.triggerings == 0:
                                raise self

if __name__ == '__main__':

        import doctest

        (failings, testings) = (1, None)
        try:

                sys.stdout = DocTestExit(sys.stdout, 2)
                (failings, testings) = doctest.testmod(
                        optionflags = doctest.ELLIPSIS)
        except DocTestExit:
                print '*' * 70
                print '1 item interrupted'
                print '***Test Failed***'
        finally:
                sys.stdout = sys.stdout.out


CategoryFaq

doctest (last edited 2008-11-15 14:00:37 by localhost)

Unable to edit the page? See the FrontPage for instructions.