|
# -*- coding: utf-8 -*- |
|
""" |
|
Test script for doctest. |
|
""" |
|
|
|
import sys |
|
from test import test_support |
|
import doctest |
|
|
|
# NOTE: There are some additional tests relating to interaction with |
|
# zipimport in the test_zipimport_support test module. |
|
|
|
###################################################################### |
|
## Sample Objects (used by test cases) |
|
###################################################################### |
|
|
|
def sample_func(v): |
|
""" |
|
Blah blah |
|
|
|
>>> print sample_func(22) |
|
44 |
|
|
|
Yee ha! |
|
""" |
|
return v+v |
|
|
|
class SampleClass: |
|
""" |
|
>>> print 1 |
|
1 |
|
|
|
>>> # comments get ignored. so are empty PS1 and PS2 prompts: |
|
>>> |
|
... |
|
|
|
Multiline example: |
|
>>> sc = SampleClass(3) |
|
>>> for i in range(10): |
|
... sc = sc.double() |
|
... print sc.get(), |
|
6 12 24 48 96 192 384 768 1536 3072 |
|
""" |
|
def __init__(self, val): |
|
""" |
|
>>> print SampleClass(12).get() |
|
12 |
|
""" |
|
self.val = val |
|
|
|
def double(self): |
|
""" |
|
>>> print SampleClass(12).double().get() |
|
24 |
|
""" |
|
return SampleClass(self.val + self.val) |
|
|
|
def get(self): |
|
""" |
|
>>> print SampleClass(-5).get() |
|
-5 |
|
""" |
|
return self.val |
|
|
|
def a_staticmethod(v): |
|
""" |
|
>>> print SampleClass.a_staticmethod(10) |
|
11 |
|
""" |
|
return v+1 |
|
a_staticmethod = staticmethod(a_staticmethod) |
|
|
|
def a_classmethod(cls, v): |
|
""" |
|
>>> print SampleClass.a_classmethod(10) |
|
12 |
|
>>> print SampleClass(0).a_classmethod(10) |
|
12 |
|
""" |
|
return v+2 |
|
a_classmethod = classmethod(a_classmethod) |
|
|
|
a_property = property(get, doc=""" |
|
>>> print SampleClass(22).a_property |
|
22 |
|
""") |
|
|
|
class NestedClass: |
|
""" |
|
>>> x = SampleClass.NestedClass(5) |
|
>>> y = x.square() |
|
>>> print y.get() |
|
25 |
|
""" |
|
def __init__(self, val=0): |
|
""" |
|
>>> print SampleClass.NestedClass().get() |
|
0 |
|
""" |
|
self.val = val |
|
def square(self): |
|
return SampleClass.NestedClass(self.val*self.val) |
|
def get(self): |
|
return self.val |
|
|
|
class SampleNewStyleClass(object): |
|
r""" |
|
>>> print '1\n2\n3' |
|
1 |
|
2 |
|
3 |
|
""" |
|
def __init__(self, val): |
|
""" |
|
>>> print SampleNewStyleClass(12).get() |
|
12 |
|
""" |
|
self.val = val |
|
|
|
def double(self): |
|
""" |
|
>>> print SampleNewStyleClass(12).double().get() |
|
24 |
|
""" |
|
return SampleNewStyleClass(self.val + self.val) |
|
|
|
def get(self): |
|
""" |
|
>>> print SampleNewStyleClass(-5).get() |
|
-5 |
|
""" |
|
return self.val |
|
|
|
###################################################################### |
|
## Fake stdin (for testing interactive debugging) |
|
###################################################################### |
|
|
|
class _FakeInput: |
|
""" |
|
A fake input stream for pdb's interactive debugger. Whenever a |
|
line is read, print it (to simulate the user typing it), and then |
|
return it. The set of lines to return is specified in the |
|
constructor; they should not have trailing newlines. |
|
""" |
|
def __init__(self, lines): |
|
self.lines = lines |
|
|
|
def readline(self): |
|
line = self.lines.pop(0) |
|
print line |
|
return line+'\n' |
|
|
|
###################################################################### |
|
## Test Cases |
|
###################################################################### |
|
|
|
def test_Example(): r""" |
|
Unit tests for the `Example` class. |
|
|
|
Example is a simple container class that holds: |
|
- `source`: A source string. |
|
- `want`: An expected output string. |
|
- `exc_msg`: An expected exception message string (or None if no |
|
exception is expected). |
|
- `lineno`: A line number (within the docstring). |
|
- `indent`: The example's indentation in the input string. |
|
- `options`: An option dictionary, mapping option flags to True or |
|
False. |
|
|
|
These attributes are set by the constructor. `source` and `want` are |
|
required; the other attributes all have default values: |
|
|
|
>>> example = doctest.Example('print 1', '1\n') |
|
>>> (example.source, example.want, example.exc_msg, |
|
... example.lineno, example.indent, example.options) |
|
('print 1\n', '1\n', None, 0, 0, {}) |
|
|
|
The first three attributes (`source`, `want`, and `exc_msg`) may be |
|
specified positionally; the remaining arguments should be specified as |
|
keyword arguments: |
|
|
|
>>> exc_msg = 'IndexError: pop from an empty list' |
|
>>> example = doctest.Example('[].pop()', '', exc_msg, |
|
... lineno=5, indent=4, |
|
... options={doctest.ELLIPSIS: True}) |
|
>>> (example.source, example.want, example.exc_msg, |
|
... example.lineno, example.indent, example.options) |
|
('[].pop()\n', '', 'IndexError: pop from an empty list\n', 5, 4, {8: True}) |
|
|
|
The constructor normalizes the `source` string to end in a newline: |
|
|
|
Source spans a single line: no terminating newline. |
|
>>> e = doctest.Example('print 1', '1\n') |
|
>>> e.source, e.want |
|
('print 1\n', '1\n') |
|
|
|
>>> e = doctest.Example('print 1\n', '1\n') |
|
>>> e.source, e.want |
|
('print 1\n', '1\n') |
|
|
|
Source spans multiple lines: require terminating newline. |
|
>>> e = doctest.Example('print 1;\nprint 2\n', '1\n2\n') |
|
>>> e.source, e.want |
|
('print 1;\nprint 2\n', '1\n2\n') |
|
|
|
>>> e = doctest.Example('print 1;\nprint 2', '1\n2\n') |
|
>>> e.source, e.want |
|
('print 1;\nprint 2\n', '1\n2\n') |
|
|
|
Empty source string (which should never appear in real examples) |
|
>>> e = doctest.Example('', '') |
|
>>> e.source, e.want |
|
('\n', '') |
|
|
|
The constructor normalizes the `want` string to end in a newline, |
|
unless it's the empty string: |
|
|
|
>>> e = doctest.Example('print 1', '1\n') |
|
>>> e.source, e.want |
|
('print 1\n', '1\n') |
|
|
|
>>> e = doctest.Example('print 1', '1') |
|
>>> e.source, e.want |
|
('print 1\n', '1\n') |
|
|
|
>>> e = doctest.Example('print', '') |
|
>>> e.source, e.want |
|
('print\n', '') |
|
|
|
The constructor normalizes the `exc_msg` string to end in a newline, |
|
unless it's `None`: |
|
|
|
Message spans one line |
|
>>> exc_msg = 'IndexError: pop from an empty list' |
|
>>> e = doctest.Example('[].pop()', '', exc_msg) |
|
>>> e.exc_msg |
|
'IndexError: pop from an empty list\n' |
|
|
|
>>> exc_msg = 'IndexError: pop from an empty list\n' |
|
>>> e = doctest.Example('[].pop()', '', exc_msg) |
|
>>> e.exc_msg |
|
'IndexError: pop from an empty list\n' |
|
|
|
Message spans multiple lines |
|
>>> exc_msg = 'ValueError: 1\n 2' |
|
>>> e = doctest.Example('raise ValueError("1\n 2")', '', exc_msg) |
|
>>> e.exc_msg |
|
'ValueError: 1\n 2\n' |
|
|
|
>>> exc_msg = 'ValueError: 1\n 2\n' |
|
>>> e = doctest.Example('raise ValueError("1\n 2")', '', exc_msg) |
|
>>> e.exc_msg |
|
'ValueError: 1\n 2\n' |
|
|
|
Empty (but non-None) exception message (which should never appear |
|
in real examples) |
|
>>> exc_msg = '' |
|
>>> e = doctest.Example('raise X()', '', exc_msg) |
|
>>> e.exc_msg |
|
'\n' |
|
|
|
Compare `Example`: |
|
>>> example = doctest.Example('print 1', '1\n') |
|
>>> same_example = doctest.Example('print 1', '1\n') |
|
>>> other_example = doctest.Example('print 42', '42\n') |
|
>>> example == same_example |
|
True |
|
>>> example != same_example |
|
False |
|
>>> hash(example) == hash(same_example) |
|
True |
|
>>> example == other_example |
|
False |
|
>>> example != other_example |
|
True |
|
""" |
|
|
|
def test_DocTest(): r""" |
|
Unit tests for the `DocTest` class. |
|
|
|
DocTest is a collection of examples, extracted from a docstring, along |
|
with information about where the docstring comes from (a name, |
|
filename, and line number). The docstring is parsed by the `DocTest` |
|
constructor: |
|
|
|
>>> docstring = ''' |
|
... >>> print 12 |
|
... 12 |
|
... |
|
... Non-example text. |
|
... |
|
... >>> print 'another\example' |
|
... another |
|
... example |
|
... ''' |
|
>>> globs = {} # globals to run the test in. |
|
>>> parser = doctest.DocTestParser() |
|
>>> test = parser.get_doctest(docstring, globs, 'some_test', |
|
... 'some_file', 20) |
|
>>> print test |
|
<DocTest some_test from some_file:20 (2 examples)> |
|
>>> len(test.examples) |
|
2 |
|
>>> e1, e2 = test.examples |
|
>>> (e1.source, e1.want, e1.lineno) |
|
('print 12\n', '12\n', 1) |
|
>>> (e2.source, e2.want, e2.lineno) |
|
("print 'another\\example'\n", 'another\nexample\n', 6) |
|
|
|
Source information (name, filename, and line number) is available as |
|
attributes on the doctest object: |
|
|
|
>>> (test.name, test.filename, test.lineno) |
|
('some_test', 'some_file', 20) |
|
|
|
The line number of an example within its containing file is found by |
|
adding the line number of the example and the line number of its |
|
containing test: |
|
|
|
>>> test.lineno + e1.lineno |
|
21 |
|
>>> test.lineno + e2.lineno |
|
26 |
|
|
|
If the docstring contains inconsistent leading whitespace in the |
|
expected output of an example, then `DocTest` will raise a ValueError: |
|
|
|
>>> docstring = r''' |
|
... >>> print 'bad\nindentation' |
|
... bad |
|
... indentation |
|
... ''' |
|
>>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 4 of the docstring for some_test has inconsistent leading whitespace: 'indentation' |
|
|
|
If the docstring contains inconsistent leading whitespace on |
|
continuation lines, then `DocTest` will raise a ValueError: |
|
|
|
>>> docstring = r''' |
|
... >>> print ('bad indentation', |
|
... ... 2) |
|
... ('bad', 'indentation') |
|
... ''' |
|
>>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 2 of the docstring for some_test has inconsistent leading whitespace: '... 2)' |
|
|
|
If there's no blank space after a PS1 prompt ('>>>'), then `DocTest` |
|
will raise a ValueError: |
|
|
|
>>> docstring = '>>>print 1\n1' |
|
>>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 1 of the docstring for some_test lacks blank after >>>: '>>>print 1' |
|
|
|
If there's no blank space after a PS2 prompt ('...'), then `DocTest` |
|
will raise a ValueError: |
|
|
|
>>> docstring = '>>> if 1:\n...print 1\n1' |
|
>>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 2 of the docstring for some_test lacks blank after ...: '...print 1' |
|
|
|
Compare `DocTest`: |
|
|
|
>>> docstring = ''' |
|
... >>> print 12 |
|
... 12 |
|
... ''' |
|
>>> test = parser.get_doctest(docstring, globs, 'some_test', |
|
... 'some_test', 20) |
|
>>> same_test = parser.get_doctest(docstring, globs, 'some_test', |
|
... 'some_test', 20) |
|
>>> test == same_test |
|
True |
|
>>> test != same_test |
|
False |
|
>>> hash(test) == hash(same_test) |
|
True |
|
>>> docstring = ''' |
|
... >>> print 42 |
|
... 42 |
|
... ''' |
|
>>> other_test = parser.get_doctest(docstring, globs, 'other_test', |
|
... 'other_file', 10) |
|
>>> test == other_test |
|
False |
|
>>> test != other_test |
|
True |
|
|
|
Compare `DocTestCase`: |
|
|
|
>>> DocTestCase = doctest.DocTestCase |
|
>>> test_case = DocTestCase(test) |
|
>>> same_test_case = DocTestCase(same_test) |
|
>>> other_test_case = DocTestCase(other_test) |
|
>>> test_case == same_test_case |
|
True |
|
>>> test_case != same_test_case |
|
False |
|
>>> hash(test_case) == hash(same_test_case) |
|
True |
|
>>> test == other_test_case |
|
False |
|
>>> test != other_test_case |
|
True |
|
|
|
""" |
|
|
|
def test_DocTestFinder(): r""" |
|
Unit tests for the `DocTestFinder` class. |
|
|
|
DocTestFinder is used to extract DocTests from an object's docstring |
|
and the docstrings of its contained objects. It can be used with |
|
modules, functions, classes, methods, staticmethods, classmethods, and |
|
properties. |
|
|
|
Finding Tests in Functions |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
For a function whose docstring contains examples, DocTestFinder.find() |
|
will return a single test (for that function's docstring): |
|
|
|
>>> finder = doctest.DocTestFinder() |
|
|
|
We'll simulate a __file__ attr that ends in pyc: |
|
|
|
>>> import test.test_doctest |
|
>>> old = test.test_doctest.__file__ |
|
>>> test.test_doctest.__file__ = 'test_doctest.pyc' |
|
|
|
>>> tests = finder.find(sample_func) |
|
|
|
>>> print tests # doctest: +ELLIPSIS |
|
[<DocTest sample_func from ...:17 (1 example)>] |
|
|
|
The exact name depends on how test_doctest was invoked, so allow for |
|
leading path components. |
|
|
|
>>> tests[0].filename # doctest: +ELLIPSIS |
|
'...test_doctest.py' |
|
|
|
>>> test.test_doctest.__file__ = old |
|
|
|
|
|
>>> e = tests[0].examples[0] |
|
>>> (e.source, e.want, e.lineno) |
|
('print sample_func(22)\n', '44\n', 3) |
|
|
|
By default, tests are created for objects with no docstring: |
|
|
|
>>> def no_docstring(v): |
|
... pass |
|
>>> finder.find(no_docstring) |
|
[] |
|
|
|
However, the optional argument `exclude_empty` to the DocTestFinder |
|
constructor can be used to exclude tests for objects with empty |
|
docstrings: |
|
|
|
>>> def no_docstring(v): |
|
... pass |
|
>>> excl_empty_finder = doctest.DocTestFinder(exclude_empty=True) |
|
>>> excl_empty_finder.find(no_docstring) |
|
[] |
|
|
|
If the function has a docstring with no examples, then a test with no |
|
examples is returned. (This lets `DocTestRunner` collect statistics |
|
about which functions have no tests -- but is that useful? And should |
|
an empty test also be created when there's no docstring?) |
|
|
|
>>> def no_examples(v): |
|
... ''' no doctest examples ''' |
|
>>> finder.find(no_examples) # doctest: +ELLIPSIS |
|
[<DocTest no_examples from ...:1 (no examples)>] |
|
|
|
Finding Tests in Classes |
|
~~~~~~~~~~~~~~~~~~~~~~~~ |
|
For a class, DocTestFinder will create a test for the class's |
|
docstring, and will recursively explore its contents, including |
|
methods, classmethods, staticmethods, properties, and nested classes. |
|
|
|
>>> finder = doctest.DocTestFinder() |
|
>>> tests = finder.find(SampleClass) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
3 SampleClass |
|
3 SampleClass.NestedClass |
|
1 SampleClass.NestedClass.__init__ |
|
1 SampleClass.__init__ |
|
2 SampleClass.a_classmethod |
|
1 SampleClass.a_property |
|
1 SampleClass.a_staticmethod |
|
1 SampleClass.double |
|
1 SampleClass.get |
|
|
|
New-style classes are also supported: |
|
|
|
>>> tests = finder.find(SampleNewStyleClass) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
1 SampleNewStyleClass |
|
1 SampleNewStyleClass.__init__ |
|
1 SampleNewStyleClass.double |
|
1 SampleNewStyleClass.get |
|
|
|
Finding Tests in Modules |
|
~~~~~~~~~~~~~~~~~~~~~~~~ |
|
For a module, DocTestFinder will create a test for the class's |
|
docstring, and will recursively explore its contents, including |
|
functions, classes, and the `__test__` dictionary, if it exists: |
|
|
|
>>> # A module |
|
>>> import types |
|
>>> m = types.ModuleType('some_module') |
|
>>> def triple(val): |
|
... ''' |
|
... >>> print triple(11) |
|
... 33 |
|
... ''' |
|
... return val*3 |
|
>>> m.__dict__.update({ |
|
... 'sample_func': sample_func, |
|
... 'SampleClass': SampleClass, |
|
... '__doc__': ''' |
|
... Module docstring. |
|
... >>> print 'module' |
|
... module |
|
... ''', |
|
... '__test__': { |
|
... 'd': '>>> print 6\n6\n>>> print 7\n7\n', |
|
... 'c': triple}}) |
|
|
|
>>> finder = doctest.DocTestFinder() |
|
>>> # Use module=test.test_doctest, to prevent doctest from |
|
>>> # ignoring the objects since they weren't defined in m. |
|
>>> import test.test_doctest |
|
>>> tests = finder.find(m, module=test.test_doctest) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
1 some_module |
|
3 some_module.SampleClass |
|
3 some_module.SampleClass.NestedClass |
|
1 some_module.SampleClass.NestedClass.__init__ |
|
1 some_module.SampleClass.__init__ |
|
2 some_module.SampleClass.a_classmethod |
|
1 some_module.SampleClass.a_property |
|
1 some_module.SampleClass.a_staticmethod |
|
1 some_module.SampleClass.double |
|
1 some_module.SampleClass.get |
|
1 some_module.__test__.c |
|
2 some_module.__test__.d |
|
1 some_module.sample_func |
|
|
|
Duplicate Removal |
|
~~~~~~~~~~~~~~~~~ |
|
If a single object is listed twice (under different names), then tests |
|
will only be generated for it once: |
|
|
|
>>> from test import doctest_aliases |
|
>>> assert doctest_aliases.TwoNames.f |
|
>>> assert doctest_aliases.TwoNames.g |
|
>>> tests = excl_empty_finder.find(doctest_aliases) |
|
>>> print len(tests) |
|
2 |
|
>>> print tests[0].name |
|
test.doctest_aliases.TwoNames |
|
|
|
TwoNames.f and TwoNames.g are bound to the same object. |
|
We can't guess which will be found in doctest's traversal of |
|
TwoNames.__dict__ first, so we have to allow for either. |
|
|
|
>>> tests[1].name.split('.')[-1] in ['f', 'g'] |
|
True |
|
|
|
Empty Tests |
|
~~~~~~~~~~~ |
|
By default, an object with no doctests doesn't create any tests: |
|
|
|
>>> tests = doctest.DocTestFinder().find(SampleClass) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
3 SampleClass |
|
3 SampleClass.NestedClass |
|
1 SampleClass.NestedClass.__init__ |
|
1 SampleClass.__init__ |
|
2 SampleClass.a_classmethod |
|
1 SampleClass.a_property |
|
1 SampleClass.a_staticmethod |
|
1 SampleClass.double |
|
1 SampleClass.get |
|
|
|
By default, that excluded objects with no doctests. exclude_empty=False |
|
tells it to include (empty) tests for objects with no doctests. This feature |
|
is really to support backward compatibility in what doctest.master.summarize() |
|
displays. |
|
|
|
>>> tests = doctest.DocTestFinder(exclude_empty=False).find(SampleClass) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
3 SampleClass |
|
3 SampleClass.NestedClass |
|
1 SampleClass.NestedClass.__init__ |
|
0 SampleClass.NestedClass.get |
|
0 SampleClass.NestedClass.square |
|
1 SampleClass.__init__ |
|
2 SampleClass.a_classmethod |
|
1 SampleClass.a_property |
|
1 SampleClass.a_staticmethod |
|
1 SampleClass.double |
|
1 SampleClass.get |
|
|
|
Turning off Recursion |
|
~~~~~~~~~~~~~~~~~~~~~ |
|
DocTestFinder can be told not to look for tests in contained objects |
|
using the `recurse` flag: |
|
|
|
>>> tests = doctest.DocTestFinder(recurse=False).find(SampleClass) |
|
>>> for t in tests: |
|
... print '%2s %s' % (len(t.examples), t.name) |
|
3 SampleClass |
|
|
|
Line numbers |
|
~~~~~~~~~~~~ |
|
DocTestFinder finds the line number of each example: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... |
|
... some text |
|
... |
|
... >>> # examples are not created for comments & bare prompts. |
|
... >>> |
|
... ... |
|
... |
|
... >>> for x in range(10): |
|
... ... print x, |
|
... 0 1 2 3 4 5 6 7 8 9 |
|
... >>> x//2 |
|
... 6 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> [e.lineno for e in test.examples] |
|
[1, 9, 12] |
|
""" |
|
|
|
def test_DocTestParser(): r""" |
|
Unit tests for the `DocTestParser` class. |
|
|
|
DocTestParser is used to parse docstrings containing doctest examples. |
|
|
|
The `parse` method divides a docstring into examples and intervening |
|
text: |
|
|
|
>>> s = ''' |
|
... >>> x, y = 2, 3 # no output expected |
|
... >>> if 1: |
|
... ... print x |
|
... ... print y |
|
... 2 |
|
... 3 |
|
... |
|
... Some text. |
|
... >>> x+y |
|
... 5 |
|
... ''' |
|
>>> parser = doctest.DocTestParser() |
|
>>> for piece in parser.parse(s): |
|
... if isinstance(piece, doctest.Example): |
|
... print 'Example:', (piece.source, piece.want, piece.lineno) |
|
... else: |
|
... print ' Text:', `piece` |
|
Text: '\n' |
|
Example: ('x, y = 2, 3 # no output expected\n', '', 1) |
|
Text: '' |
|
Example: ('if 1:\n print x\n print y\n', '2\n3\n', 2) |
|
Text: '\nSome text.\n' |
|
Example: ('x+y\n', '5\n', 9) |
|
Text: '' |
|
|
|
The `get_examples` method returns just the examples: |
|
|
|
>>> for piece in parser.get_examples(s): |
|
... print (piece.source, piece.want, piece.lineno) |
|
('x, y = 2, 3 # no output expected\n', '', 1) |
|
('if 1:\n print x\n print y\n', '2\n3\n', 2) |
|
('x+y\n', '5\n', 9) |
|
|
|
The `get_doctest` method creates a Test from the examples, along with the |
|
given arguments: |
|
|
|
>>> test = parser.get_doctest(s, {}, 'name', 'filename', lineno=5) |
|
>>> (test.name, test.filename, test.lineno) |
|
('name', 'filename', 5) |
|
>>> for piece in test.examples: |
|
... print (piece.source, piece.want, piece.lineno) |
|
('x, y = 2, 3 # no output expected\n', '', 1) |
|
('if 1:\n print x\n print y\n', '2\n3\n', 2) |
|
('x+y\n', '5\n', 9) |
|
""" |
|
|
|
class test_DocTestRunner: |
|
def basics(): r""" |
|
Unit tests for the `DocTestRunner` class. |
|
|
|
DocTestRunner is used to run DocTest test cases, and to accumulate |
|
statistics. Here's a simple DocTest case we can use: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... >>> print x |
|
... 12 |
|
... >>> x//2 |
|
... 6 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
|
|
The main DocTestRunner interface is the `run` method, which runs a |
|
given DocTest case in a given namespace (globs). It returns a tuple |
|
`(f,t)`, where `f` is the number of failed tests and `t` is the number |
|
of tried tests. |
|
|
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=3) |
|
|
|
If any example produces incorrect output, then the test runner reports |
|
the failure and proceeds to the next example: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... >>> print x |
|
... 14 |
|
... >>> x//2 |
|
... 6 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=True).run(test) |
|
... # doctest: +ELLIPSIS |
|
Trying: |
|
x = 12 |
|
Expecting nothing |
|
ok |
|
Trying: |
|
print x |
|
Expecting: |
|
14 |
|
********************************************************************** |
|
File ..., line 4, in f |
|
Failed example: |
|
print x |
|
Expected: |
|
14 |
|
Got: |
|
12 |
|
Trying: |
|
x//2 |
|
Expecting: |
|
6 |
|
ok |
|
TestResults(failed=1, attempted=3) |
|
""" |
|
def verbose_flag(): r""" |
|
The `verbose` flag makes the test runner generate more detailed |
|
output: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... >>> print x |
|
... 12 |
|
... >>> x//2 |
|
... 6 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
|
|
>>> doctest.DocTestRunner(verbose=True).run(test) |
|
Trying: |
|
x = 12 |
|
Expecting nothing |
|
ok |
|
Trying: |
|
print x |
|
Expecting: |
|
12 |
|
ok |
|
Trying: |
|
x//2 |
|
Expecting: |
|
6 |
|
ok |
|
TestResults(failed=0, attempted=3) |
|
|
|
If the `verbose` flag is unspecified, then the output will be verbose |
|
iff `-v` appears in sys.argv: |
|
|
|
>>> # Save the real sys.argv list. |
|
>>> old_argv = sys.argv |
|
|
|
>>> # If -v does not appear in sys.argv, then output isn't verbose. |
|
>>> sys.argv = ['test'] |
|
>>> doctest.DocTestRunner().run(test) |
|
TestResults(failed=0, attempted=3) |
|
|
|
>>> # If -v does appear in sys.argv, then output is verbose. |
|
>>> sys.argv = ['test', '-v'] |
|
>>> doctest.DocTestRunner().run(test) |
|
Trying: |
|
x = 12 |
|
Expecting nothing |
|
ok |
|
Trying: |
|
print x |
|
Expecting: |
|
12 |
|
ok |
|
Trying: |
|
x//2 |
|
Expecting: |
|
6 |
|
ok |
|
TestResults(failed=0, attempted=3) |
|
|
|
>>> # Restore sys.argv |
|
>>> sys.argv = old_argv |
|
|
|
In the remaining examples, the test runner's verbosity will be |
|
explicitly set, to ensure that the test behavior is consistent. |
|
""" |
|
def exceptions(): r""" |
|
Tests of `DocTestRunner`'s exception handling. |
|
|
|
An expected exception is specified with a traceback message. The |
|
lines between the first line and the type/value may be omitted or |
|
replaced with any other string: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... >>> print x//0 |
|
... Traceback (most recent call last): |
|
... ZeroDivisionError: integer division or modulo by zero |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
An example may not generate output before it raises an exception; if |
|
it does, then the traceback message will not be recognized as |
|
signaling an expected exception, so the example will be reported as an |
|
unexpected exception: |
|
|
|
>>> def f(x): |
|
... ''' |
|
... >>> x = 12 |
|
... >>> print 'pre-exception output', x//0 |
|
... pre-exception output |
|
... Traceback (most recent call last): |
|
... ZeroDivisionError: integer division or modulo by zero |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 4, in f |
|
Failed example: |
|
print 'pre-exception output', x//0 |
|
Exception raised: |
|
... |
|
ZeroDivisionError: integer division or modulo by zero |
|
TestResults(failed=1, attempted=2) |
|
|
|
Exception messages may contain newlines: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> raise ValueError, 'multi\nline\nmessage' |
|
... Traceback (most recent call last): |
|
... ValueError: multi |
|
... line |
|
... message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
If an exception is expected, but an exception with the wrong type or |
|
message is raised, then it is reported as a failure: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> raise ValueError, 'message' |
|
... Traceback (most recent call last): |
|
... ValueError: wrong message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
raise ValueError, 'message' |
|
Expected: |
|
Traceback (most recent call last): |
|
ValueError: wrong message |
|
Got: |
|
Traceback (most recent call last): |
|
... |
|
ValueError: message |
|
TestResults(failed=1, attempted=1) |
|
|
|
However, IGNORE_EXCEPTION_DETAIL can be used to allow a mismatch in the |
|
detail: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... ValueError: wrong message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
IGNORE_EXCEPTION_DETAIL also ignores difference in exception formatting |
|
between Python versions. For example, in Python 3.x, the module path of |
|
the exception is in the output, but this will fail under Python 2: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from httplib import HTTPException |
|
... >>> raise HTTPException('message') |
|
... Traceback (most recent call last): |
|
... httplib.HTTPException: message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 4, in f |
|
Failed example: |
|
raise HTTPException('message') |
|
Expected: |
|
Traceback (most recent call last): |
|
httplib.HTTPException: message |
|
Got: |
|
Traceback (most recent call last): |
|
... |
|
HTTPException: message |
|
TestResults(failed=1, attempted=2) |
|
|
|
But in Python 2 the module path is not included, and therefore a test must look |
|
like the following test to succeed in Python 2. But that test will fail under |
|
Python 3. |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from httplib import HTTPException |
|
... >>> raise HTTPException('message') |
|
... Traceback (most recent call last): |
|
... HTTPException: message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
However, with IGNORE_EXCEPTION_DETAIL, the module name of the exception |
|
(if any) will be ignored: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from httplib import HTTPException |
|
... >>> raise HTTPException('message') #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... HTTPException: message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
The module path will be completely ignored, so two different module paths will |
|
still pass if IGNORE_EXCEPTION_DETAIL is given. This is intentional, so it can |
|
be used when exceptions have changed module. |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from httplib import HTTPException |
|
... >>> raise HTTPException('message') #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... foo.bar.HTTPException: message |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... TypeError: wrong type |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL |
|
Expected: |
|
Traceback (most recent call last): |
|
TypeError: wrong type |
|
Got: |
|
Traceback (most recent call last): |
|
... |
|
ValueError: message |
|
TestResults(failed=1, attempted=1) |
|
|
|
If the exception does not have a message, you can still use |
|
IGNORE_EXCEPTION_DETAIL to normalize the modules between Python 2 and 3: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from Queue import Empty |
|
... >>> raise Empty() #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... foo.bar.Empty |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
Note that a trailing colon doesn't matter either: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> from Queue import Empty |
|
... >>> raise Empty() #doctest: +IGNORE_EXCEPTION_DETAIL |
|
... Traceback (most recent call last): |
|
... foo.bar.Empty: |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
If an exception is raised but not expected, then it is reported as an |
|
unexpected exception: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> 1//0 |
|
... 0 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
1//0 |
|
Exception raised: |
|
Traceback (most recent call last): |
|
... |
|
ZeroDivisionError: integer division or modulo by zero |
|
TestResults(failed=1, attempted=1) |
|
""" |
|
def displayhook(): r""" |
|
Test that changing sys.displayhook doesn't matter for doctest. |
|
|
|
>>> import sys |
|
>>> orig_displayhook = sys.displayhook |
|
>>> def my_displayhook(x): |
|
... print('hi!') |
|
>>> sys.displayhook = my_displayhook |
|
>>> def f(): |
|
... ''' |
|
... >>> 3 |
|
... 3 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> r = doctest.DocTestRunner(verbose=False).run(test) |
|
>>> post_displayhook = sys.displayhook |
|
|
|
We need to restore sys.displayhook now, so that we'll be able to test |
|
results. |
|
|
|
>>> sys.displayhook = orig_displayhook |
|
|
|
Ok, now we can check that everything is ok. |
|
|
|
>>> r |
|
TestResults(failed=0, attempted=1) |
|
>>> post_displayhook is my_displayhook |
|
True |
|
""" |
|
def optionflags(): r""" |
|
Tests of `DocTestRunner`'s option flag handling. |
|
|
|
Several option flags can be used to customize the behavior of the test |
|
runner. These are defined as module constants in doctest, and passed |
|
to the DocTestRunner constructor (multiple constants should be ORed |
|
together). |
|
|
|
The DONT_ACCEPT_TRUE_FOR_1 flag disables matches between True/False |
|
and 1/0: |
|
|
|
>>> def f(x): |
|
... '>>> True\n1\n' |
|
|
|
>>> # Without the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
>>> # With the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.DONT_ACCEPT_TRUE_FOR_1 |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
True |
|
Expected: |
|
1 |
|
Got: |
|
True |
|
TestResults(failed=1, attempted=1) |
|
|
|
The DONT_ACCEPT_BLANKLINE flag disables the match between blank lines |
|
and the '<BLANKLINE>' marker: |
|
|
|
>>> def f(x): |
|
... '>>> print "a\\n\\nb"\na\n<BLANKLINE>\nb\n' |
|
|
|
>>> # Without the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
>>> # With the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.DONT_ACCEPT_BLANKLINE |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print "a\n\nb" |
|
Expected: |
|
a |
|
<BLANKLINE> |
|
b |
|
Got: |
|
a |
|
<BLANKLINE> |
|
b |
|
TestResults(failed=1, attempted=1) |
|
|
|
The NORMALIZE_WHITESPACE flag causes all sequences of whitespace to be |
|
treated as equal: |
|
|
|
>>> def f(x): |
|
... '>>> print 1, 2, 3\n 1 2\n 3' |
|
|
|
>>> # Without the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print 1, 2, 3 |
|
Expected: |
|
1 2 |
|
3 |
|
Got: |
|
1 2 3 |
|
TestResults(failed=1, attempted=1) |
|
|
|
>>> # With the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.NORMALIZE_WHITESPACE |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
An example from the docs: |
|
>>> print range(20) #doctest: +NORMALIZE_WHITESPACE |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19] |
|
|
|
The ELLIPSIS flag causes ellipsis marker ("...") in the expected |
|
output to match any substring in the actual output: |
|
|
|
>>> def f(x): |
|
... '>>> print range(15)\n[0, 1, 2, ..., 14]\n' |
|
|
|
>>> # Without the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(15) |
|
Expected: |
|
[0, 1, 2, ..., 14] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] |
|
TestResults(failed=1, attempted=1) |
|
|
|
>>> # With the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.ELLIPSIS |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
... also matches nothing: |
|
|
|
>>> for i in range(100): |
|
... print i**2, #doctest: +ELLIPSIS |
|
0 1...4...9 16 ... 36 49 64 ... 9801 |
|
|
|
... can be surprising; e.g., this test passes: |
|
|
|
>>> for i in range(21): #doctest: +ELLIPSIS |
|
... print i, |
|
0 1 2 ...1...2...0 |
|
|
|
Examples from the docs: |
|
|
|
>>> print range(20) # doctest:+ELLIPSIS |
|
[0, 1, ..., 18, 19] |
|
|
|
>>> print range(20) # doctest: +ELLIPSIS |
|
... # doctest: +NORMALIZE_WHITESPACE |
|
[0, 1, ..., 18, 19] |
|
|
|
The SKIP flag causes an example to be skipped entirely. I.e., the |
|
example is not run. It can be useful in contexts where doctest |
|
examples serve as both documentation and test cases, and an example |
|
should be included for documentation purposes, but should not be |
|
checked (e.g., because its output is random, or depends on resources |
|
which would be unavailable.) The SKIP flag can also be used for |
|
'commenting out' broken examples. |
|
|
|
>>> import unavailable_resource # doctest: +SKIP |
|
>>> unavailable_resource.do_something() # doctest: +SKIP |
|
>>> unavailable_resource.blow_up() # doctest: +SKIP |
|
Traceback (most recent call last): |
|
... |
|
UncheckedBlowUpError: Nobody checks me. |
|
|
|
>>> import random |
|
>>> print random.random() # doctest: +SKIP |
|
0.721216923889 |
|
|
|
The REPORT_UDIFF flag causes failures that involve multi-line expected |
|
and actual outputs to be displayed using a unified diff: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> print '\n'.join('abcdefg') |
|
... a |
|
... B |
|
... c |
|
... d |
|
... f |
|
... g |
|
... h |
|
... ''' |
|
|
|
>>> # Without the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
print '\n'.join('abcdefg') |
|
Expected: |
|
a |
|
B |
|
c |
|
d |
|
f |
|
g |
|
h |
|
Got: |
|
a |
|
b |
|
c |
|
d |
|
e |
|
f |
|
g |
|
TestResults(failed=1, attempted=1) |
|
|
|
>>> # With the flag: |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.REPORT_UDIFF |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
print '\n'.join('abcdefg') |
|
Differences (unified diff with -expected +actual): |
|
@@ -1,7 +1,7 @@ |
|
a |
|
-B |
|
+b |
|
c |
|
d |
|
+e |
|
f |
|
g |
|
-h |
|
TestResults(failed=1, attempted=1) |
|
|
|
The REPORT_CDIFF flag causes failures that involve multi-line expected |
|
and actual outputs to be displayed using a context diff: |
|
|
|
>>> # Reuse f() from the REPORT_UDIFF example, above. |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.REPORT_CDIFF |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
print '\n'.join('abcdefg') |
|
Differences (context diff with expected followed by actual): |
|
*************** |
|
*** 1,7 **** |
|
a |
|
! B |
|
c |
|
d |
|
f |
|
g |
|
- h |
|
--- 1,7 ---- |
|
a |
|
! b |
|
c |
|
d |
|
+ e |
|
f |
|
g |
|
TestResults(failed=1, attempted=1) |
|
|
|
|
|
The REPORT_NDIFF flag causes failures to use the difflib.Differ algorithm |
|
used by the popular ndiff.py utility. This does intraline difference |
|
marking, as well as interline differences. |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> print "a b c d e f g h i j k l m" |
|
... a b c d e f g h i j k 1 m |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.REPORT_NDIFF |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 3, in f |
|
Failed example: |
|
print "a b c d e f g h i j k l m" |
|
Differences (ndiff with -expected +actual): |
|
- a b c d e f g h i j k 1 m |
|
? ^ |
|
+ a b c d e f g h i j k l m |
|
? + ++ ^ |
|
TestResults(failed=1, attempted=1) |
|
|
|
The REPORT_ONLY_FIRST_FAILURE suppresses result output after the first |
|
failing example: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> print 1 # first success |
|
... 1 |
|
... >>> print 2 # first failure |
|
... 200 |
|
... >>> print 3 # second failure |
|
... 300 |
|
... >>> print 4 # second success |
|
... 4 |
|
... >>> print 5 # third failure |
|
... 500 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.REPORT_ONLY_FIRST_FAILURE |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 5, in f |
|
Failed example: |
|
print 2 # first failure |
|
Expected: |
|
200 |
|
Got: |
|
2 |
|
TestResults(failed=3, attempted=5) |
|
|
|
However, output from `report_start` is not suppressed: |
|
|
|
>>> doctest.DocTestRunner(verbose=True, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
Trying: |
|
print 1 # first success |
|
Expecting: |
|
1 |
|
ok |
|
Trying: |
|
print 2 # first failure |
|
Expecting: |
|
200 |
|
********************************************************************** |
|
File ..., line 5, in f |
|
Failed example: |
|
print 2 # first failure |
|
Expected: |
|
200 |
|
Got: |
|
2 |
|
TestResults(failed=3, attempted=5) |
|
|
|
For the purposes of REPORT_ONLY_FIRST_FAILURE, unexpected exceptions |
|
count as failures: |
|
|
|
>>> def f(x): |
|
... r''' |
|
... >>> print 1 # first success |
|
... 1 |
|
... >>> raise ValueError(2) # first failure |
|
... 200 |
|
... >>> print 3 # second failure |
|
... 300 |
|
... >>> print 4 # second success |
|
... 4 |
|
... >>> print 5 # third failure |
|
... 500 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> flags = doctest.REPORT_ONLY_FIRST_FAILURE |
|
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 5, in f |
|
Failed example: |
|
raise ValueError(2) # first failure |
|
Exception raised: |
|
... |
|
ValueError: 2 |
|
TestResults(failed=3, attempted=5) |
|
|
|
New option flags can also be registered, via register_optionflag(). Here |
|
we reach into doctest's internals a bit. |
|
|
|
>>> unlikely = "UNLIKELY_OPTION_NAME" |
|
>>> unlikely in doctest.OPTIONFLAGS_BY_NAME |
|
False |
|
>>> new_flag_value = doctest.register_optionflag(unlikely) |
|
>>> unlikely in doctest.OPTIONFLAGS_BY_NAME |
|
True |
|
|
|
Before 2.4.4/2.5, registering a name more than once erroneously created |
|
more than one flag value. Here we verify that's fixed: |
|
|
|
>>> redundant_flag_value = doctest.register_optionflag(unlikely) |
|
>>> redundant_flag_value == new_flag_value |
|
True |
|
|
|
Clean up. |
|
>>> del doctest.OPTIONFLAGS_BY_NAME[unlikely] |
|
|
|
""" |
|
|
|
def option_directives(): r""" |
|
Tests of `DocTestRunner`'s option directive mechanism. |
|
|
|
Option directives can be used to turn option flags on or off for a |
|
single example. To turn an option on for an example, follow that |
|
example with a comment of the form ``# doctest: +OPTION``: |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) # should fail: no ellipsis |
|
... [0, 1, ..., 9] |
|
... |
|
... >>> print range(10) # doctest: +ELLIPSIS |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(10) # should fail: no ellipsis |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=1, attempted=2) |
|
|
|
To turn an option off for an example, follow that example with a |
|
comment of the form ``# doctest: -OPTION``: |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) |
|
... [0, 1, ..., 9] |
|
... |
|
... >>> # should fail: no ellipsis |
|
... >>> print range(10) # doctest: -ELLIPSIS |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False, |
|
... optionflags=doctest.ELLIPSIS).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 6, in f |
|
Failed example: |
|
print range(10) # doctest: -ELLIPSIS |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=1, attempted=2) |
|
|
|
Option directives affect only the example that they appear with; they |
|
do not change the options for surrounding examples: |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) # Should fail: no ellipsis |
|
... [0, 1, ..., 9] |
|
... |
|
... >>> print range(10) # doctest: +ELLIPSIS |
|
... [0, 1, ..., 9] |
|
... |
|
... >>> print range(10) # Should fail: no ellipsis |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(10) # Should fail: no ellipsis |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
********************************************************************** |
|
File ..., line 8, in f |
|
Failed example: |
|
print range(10) # Should fail: no ellipsis |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=2, attempted=3) |
|
|
|
Multiple options may be modified by a single option directive. They |
|
may be separated by whitespace, commas, or both: |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) # Should fail |
|
... [0, 1, ..., 9] |
|
... >>> print range(10) # Should succeed |
|
... ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(10) # Should fail |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=1, attempted=2) |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) # Should fail |
|
... [0, 1, ..., 9] |
|
... >>> print range(10) # Should succeed |
|
... ... # doctest: +ELLIPSIS,+NORMALIZE_WHITESPACE |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(10) # Should fail |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=1, attempted=2) |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) # Should fail |
|
... [0, 1, ..., 9] |
|
... >>> print range(10) # Should succeed |
|
... ... # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File ..., line 2, in f |
|
Failed example: |
|
print range(10) # Should fail |
|
Expected: |
|
[0, 1, ..., 9] |
|
Got: |
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
TestResults(failed=1, attempted=2) |
|
|
|
The option directive may be put on the line following the source, as |
|
long as a continuation prompt is used: |
|
|
|
>>> def f(x): r''' |
|
... >>> print range(10) |
|
... ... # doctest: +ELLIPSIS |
|
... [0, 1, ..., 9] |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
For examples with multi-line source, the option directive may appear |
|
at the end of any line: |
|
|
|
>>> def f(x): r''' |
|
... >>> for x in range(10): # doctest: +ELLIPSIS |
|
... ... print x, |
|
... 0 1 2 ... 9 |
|
... |
|
... >>> for x in range(10): |
|
... ... print x, # doctest: +ELLIPSIS |
|
... 0 1 2 ... 9 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=2) |
|
|
|
If more than one line of an example with multi-line source has an |
|
option directive, then they are combined: |
|
|
|
>>> def f(x): r''' |
|
... Should fail (option directive not on the last line): |
|
... >>> for x in range(10): # doctest: +ELLIPSIS |
|
... ... print x, # doctest: +NORMALIZE_WHITESPACE |
|
... 0 1 2...9 |
|
... ''' |
|
>>> test = doctest.DocTestFinder().find(f)[0] |
|
>>> doctest.DocTestRunner(verbose=False).run(test) |
|
TestResults(failed=0, attempted=1) |
|
|
|
It is an error to have a comment of the form ``# doctest:`` that is |
|
*not* followed by words of the form ``+OPTION`` or ``-OPTION``, where |
|
``OPTION`` is an option that has been registered with |
|
`register_option`: |
|
|
|
>>> # Error: Option not registered |
|
>>> s = '>>> print 12 #doctest: +BADOPTION' |
|
>>> test = doctest.DocTestParser().get_doctest(s, {}, 's', 's.py', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 1 of the doctest for s has an invalid option: '+BADOPTION' |
|
|
|
>>> # Error: No + or - prefix |
|
>>> s = '>>> print 12 #doctest: ELLIPSIS' |
|
>>> test = doctest.DocTestParser().get_doctest(s, {}, 's', 's.py', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 1 of the doctest for s has an invalid option: 'ELLIPSIS' |
|
|
|
It is an error to use an option directive on a line that contains no |
|
source: |
|
|
|
>>> s = '>>> # doctest: +ELLIPSIS' |
|
>>> test = doctest.DocTestParser().get_doctest(s, {}, 's', 's.py', 0) |
|
Traceback (most recent call last): |
|
ValueError: line 0 of the doctest for s has an option directive on a line with no example: '# doctest: +ELLIPSIS' |
|
|
|
""" |
|
|
|
def test_unicode_output(self): r""" |
|
|
|
Check that unicode output works: |
|
|
|
>>> u'\xe9' |
|
u'\xe9' |
|
|
|
If we return unicode, SpoofOut's buf variable becomes automagically |
|
converted to unicode. This means all subsequent output becomes converted |
|
to unicode, and if the output contains non-ascii characters that failed. |
|
It used to be that this state change carried on between tests, meaning |
|
tests would fail if unicode has been output previously in the testrun. |
|
This test tests that this is no longer so: |
|
|
|
>>> print u'abc' |
|
abc |
|
|
|
And then return a string with non-ascii characters: |
|
|
|
>>> print u'\xe9'.encode('utf-8') |
|
é |
|
|
|
""" |
|
|
|
|
|
def test_testsource(): r""" |
|
Unit tests for `testsource()`. |
|
|
|
The testsource() function takes a module and a name, finds the (first) |
|
test with that name in that module, and converts it to a script. The |
|
example code is converted to regular Python code. The surrounding |
|
words and expected output are converted to comments: |
|
|
|
>>> import test.test_doctest |
|
>>> name = 'test.test_doctest.sample_func' |
|
>>> print doctest.testsource(test.test_doctest, name) |
|
# Blah blah |
|
# |
|
print sample_func(22) |
|
# Expected: |
|
## 44 |
|
# |
|
# Yee ha! |
|
<BLANKLINE> |
|
|
|
>>> name = 'test.test_doctest.SampleNewStyleClass' |
|
>>> print doctest.testsource(test.test_doctest, name) |
|
print '1\n2\n3' |
|
# Expected: |
|
## 1 |
|
## 2 |
|
## 3 |
|
<BLANKLINE> |
|
|
|
>>> name = 'test.test_doctest.SampleClass.a_classmethod' |
|
>>> print doctest.testsource(test.test_doctest, name) |
|
print SampleClass.a_classmethod(10) |
|
# Expected: |
|
## 12 |
|
print SampleClass(0).a_classmethod(10) |
|
# Expected: |
|
## 12 |
|
<BLANKLINE> |
|
""" |
|
|
|
def test_debug(): r""" |
|
|
|
Create a docstring that we want to debug: |
|
|
|
>>> s = ''' |
|
... >>> x = 12 |
|
... >>> print x |
|
... 12 |
|
... ''' |
|
|
|
Create some fake stdin input, to feed to the debugger: |
|
|
|
>>> import tempfile |
|
>>> real_stdin = sys.stdin |
|
>>> sys.stdin = _FakeInput(['next', 'print x', 'continue']) |
|
|
|
Run the debugger on the docstring, and then restore sys.stdin. |
|
|
|
>>> try: doctest.debug_src(s) |
|
... finally: sys.stdin = real_stdin |
|
> <string>(1)<module>() |
|
(Pdb) next |
|
12 |
|
--Return-- |
|
> <string>(1)<module>()->None |
|
(Pdb) print x |
|
12 |
|
(Pdb) continue |
|
|
|
""" |
|
|
|
def test_pdb_set_trace(): |
|
"""Using pdb.set_trace from a doctest. |
|
|
|
You can use pdb.set_trace from a doctest. To do so, you must |
|
retrieve the set_trace function from the pdb module at the time |
|
you use it. The doctest module changes sys.stdout so that it can |
|
capture program output. It also temporarily replaces pdb.set_trace |
|
with a version that restores stdout. This is necessary for you to |
|
see debugger output. |
|
|
|
>>> doc = ''' |
|
... >>> x = 42 |
|
... >>> raise Exception('clé') |
|
... Traceback (most recent call last): |
|
... Exception: clé |
|
... >>> import pdb; pdb.set_trace() |
|
... ''' |
|
>>> parser = doctest.DocTestParser() |
|
>>> test = parser.get_doctest(doc, {}, "foo-bär@baz", "foo-bär@baz.py", 0) |
|
>>> runner = doctest.DocTestRunner(verbose=False) |
|
|
|
To demonstrate this, we'll create a fake standard input that |
|
captures our debugger input: |
|
|
|
>>> import tempfile |
|
>>> real_stdin = sys.stdin |
|
>>> sys.stdin = _FakeInput([ |
|
... 'print x', # print data defined by the example |
|
... 'continue', # stop debugging |
|
... '']) |
|
|
|
>>> try: runner.run(test) |
|
... finally: sys.stdin = real_stdin |
|
--Return-- |
|
> <doctest foo-bär@baz[2]>(1)<module>()->None |
|
-> import pdb; pdb.set_trace() |
|
(Pdb) print x |
|
42 |
|
(Pdb) continue |
|
TestResults(failed=0, attempted=3) |
|
|
|
You can also put pdb.set_trace in a function called from a test: |
|
|
|
>>> def calls_set_trace(): |
|
... y=2 |
|
... import pdb; pdb.set_trace() |
|
|
|
>>> doc = ''' |
|
... >>> x=1 |
|
... >>> calls_set_trace() |
|
... ''' |
|
>>> test = parser.get_doctest(doc, globals(), "foo-bär@baz", "foo-bär@baz.py", 0) |
|
>>> real_stdin = sys.stdin |
|
>>> sys.stdin = _FakeInput([ |
|
... 'print y', # print data defined in the function |
|
... 'up', # out of function |
|
... 'print x', # print data defined by the example |
|
... 'continue', # stop debugging |
|
... '']) |
|
|
|
>>> try: |
|
... runner.run(test) |
|
... finally: |
|
... sys.stdin = real_stdin |
|
--Return-- |
|
> <doctest test.test_doctest.test_pdb_set_trace[8]>(3)calls_set_trace()->None |
|
-> import pdb; pdb.set_trace() |
|
(Pdb) print y |
|
2 |
|
(Pdb) up |
|
> <doctest foo-bär@baz[1]>(1)<module>() |
|
-> calls_set_trace() |
|
(Pdb) print x |
|
1 |
|
(Pdb) continue |
|
TestResults(failed=0, attempted=2) |
|
|
|
During interactive debugging, source code is shown, even for |
|
doctest examples: |
|
|
|
>>> doc = ''' |
|
... >>> def f(x): |
|
... ... g(x*2) |
|
... >>> def g(x): |
|
... ... print x+3 |
|
... ... import pdb; pdb.set_trace() |
|
... >>> f(3) |
|
... ''' |
|
>>> test = parser.get_doctest(doc, globals(), "foo-bär@baz", "foo-bär@baz.py", 0) |
|
>>> real_stdin = sys.stdin |
|
>>> sys.stdin = _FakeInput([ |
|
... 'list', # list source from example 2 |
|
... 'next', # return from g() |
|
... 'list', # list source from example 1 |
|
... 'next', # return from f() |
|
... 'list', # list source from example 3 |
|
... 'continue', # stop debugging |
|
... '']) |
|
>>> try: runner.run(test) |
|
... finally: sys.stdin = real_stdin |
|
... # doctest: +NORMALIZE_WHITESPACE |
|
--Return-- |
|
> <doctest foo-bär@baz[1]>(3)g()->None |
|
-> import pdb; pdb.set_trace() |
|
(Pdb) list |
|
1 def g(x): |
|
2 print x+3 |
|
3 -> import pdb; pdb.set_trace() |
|
[EOF] |
|
(Pdb) next |
|
--Return-- |
|
> <doctest foo-bär@baz[0]>(2)f()->None |
|
-> g(x*2) |
|
(Pdb) list |
|
1 def f(x): |
|
2 -> g(x*2) |
|
[EOF] |
|
(Pdb) next |
|
--Return-- |
|
> <doctest foo-bär@baz[2]>(1)<module>()->None |
|
-> f(3) |
|
(Pdb) list |
|
1 -> f(3) |
|
[EOF] |
|
(Pdb) continue |
|
********************************************************************** |
|
File "foo-bär@baz.py", line 7, in foo-bär@baz |
|
Failed example: |
|
f(3) |
|
Expected nothing |
|
Got: |
|
9 |
|
TestResults(failed=1, attempted=3) |
|
""" |
|
|
|
def test_pdb_set_trace_nested(): |
|
"""This illustrates more-demanding use of set_trace with nested functions. |
|
|
|
>>> class C(object): |
|
... def calls_set_trace(self): |
|
... y = 1 |
|
... import pdb; pdb.set_trace() |
|
... self.f1() |
|
... y = 2 |
|
... def f1(self): |
|
... x = 1 |
|
... self.f2() |
|
... x = 2 |
|
... def f2(self): |
|
... z = 1 |
|
... z = 2 |
|
|
|
>>> calls_set_trace = C().calls_set_trace |
|
|
|
>>> doc = ''' |
|
... >>> a = 1 |
|
... >>> calls_set_trace() |
|
... ''' |
|
>>> parser = doctest.DocTestParser() |
|
>>> runner = doctest.DocTestRunner(verbose=False) |
|
>>> test = parser.get_doctest(doc, globals(), "foo-bär@baz", "foo-bär@baz.py", 0) |
|
>>> real_stdin = sys.stdin |
|
>>> sys.stdin = _FakeInput([ |
|
... 'print y', # print data defined in the function |
|
... 'step', 'step', 'step', 'step', 'step', 'step', 'print z', |
|
... 'up', 'print x', |
|
... 'up', 'print y', |
|
... 'up', 'print foo', |
|
... 'continue', # stop debugging |
|
... '']) |
|
|
|
>>> try: |
|
... runner.run(test) |
|
... finally: |
|
... sys.stdin = real_stdin |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(5)calls_set_trace() |
|
-> self.f1() |
|
(Pdb) print y |
|
1 |
|
(Pdb) step |
|
--Call-- |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(7)f1() |
|
-> def f1(self): |
|
(Pdb) step |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(8)f1() |
|
-> x = 1 |
|
(Pdb) step |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(9)f1() |
|
-> self.f2() |
|
(Pdb) step |
|
--Call-- |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(11)f2() |
|
-> def f2(self): |
|
(Pdb) step |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(12)f2() |
|
-> z = 1 |
|
(Pdb) step |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(13)f2() |
|
-> z = 2 |
|
(Pdb) print z |
|
1 |
|
(Pdb) up |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(9)f1() |
|
-> self.f2() |
|
(Pdb) print x |
|
1 |
|
(Pdb) up |
|
> <doctest test.test_doctest.test_pdb_set_trace_nested[0]>(5)calls_set_trace() |
|
-> self.f1() |
|
(Pdb) print y |
|
1 |
|
(Pdb) up |
|
> <doctest foo-bär@baz[1]>(1)<module>() |
|
-> calls_set_trace() |
|
(Pdb) print foo |
|
*** NameError: name 'foo' is not defined |
|
(Pdb) continue |
|
TestResults(failed=0, attempted=2) |
|
""" |
|
|
|
def test_DocTestSuite(): |
|
"""DocTestSuite creates a unittest test suite from a doctest. |
|
|
|
We create a Suite by providing a module. A module can be provided |
|
by passing a module object: |
|
|
|
>>> import unittest |
|
>>> import test.sample_doctest |
|
>>> suite = doctest.DocTestSuite(test.sample_doctest) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=4> |
|
|
|
We can also supply the module by name: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=4> |
|
|
|
The module need not contain any doctest examples: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest_no_doctests') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=0 errors=0 failures=0> |
|
|
|
However, if DocTestSuite finds no docstrings, it raises an error: |
|
|
|
>>> try: |
|
... doctest.DocTestSuite('test.sample_doctest_no_docstrings') |
|
... except ValueError as e: |
|
... error = e |
|
|
|
>>> print(error.args[1]) |
|
has no docstrings |
|
|
|
You can prevent this error by passing a DocTestFinder instance with |
|
the `exclude_empty` keyword argument set to False: |
|
|
|
>>> finder = doctest.DocTestFinder(exclude_empty=False) |
|
>>> suite = doctest.DocTestSuite('test.sample_doctest_no_docstrings', |
|
... test_finder=finder) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=0 errors=0 failures=0> |
|
|
|
We can use the current module: |
|
|
|
>>> suite = test.sample_doctest.test_suite() |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=4> |
|
|
|
We can supply global variables. If we pass globs, they will be |
|
used instead of the module globals. Here we'll pass an empty |
|
globals, triggering an extra error: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest', globs={}) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=5> |
|
|
|
Alternatively, we can provide extra globals. Here we'll make an |
|
error go away by providing an extra global variable: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest', |
|
... extraglobs={'y': 1}) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=3> |
|
|
|
You can pass option flags. Here we'll cause an extra error |
|
by disabling the blank-line feature: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest', |
|
... optionflags=doctest.DONT_ACCEPT_BLANKLINE) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=5> |
|
|
|
You can supply setUp and tearDown functions: |
|
|
|
>>> def setUp(t): |
|
... import test.test_doctest |
|
... test.test_doctest.sillySetup = True |
|
|
|
>>> def tearDown(t): |
|
... import test.test_doctest |
|
... del test.test_doctest.sillySetup |
|
|
|
Here, we installed a silly variable that the test expects: |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest', |
|
... setUp=setUp, tearDown=tearDown) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=3> |
|
|
|
But the tearDown restores sanity: |
|
|
|
>>> import test.test_doctest |
|
>>> test.test_doctest.sillySetup |
|
Traceback (most recent call last): |
|
... |
|
AttributeError: 'module' object has no attribute 'sillySetup' |
|
|
|
The setUp and tearDown functions are passed test objects. Here |
|
we'll use the setUp function to supply the missing variable y: |
|
|
|
>>> def setUp(test): |
|
... test.globs['y'] = 1 |
|
|
|
>>> suite = doctest.DocTestSuite('test.sample_doctest', setUp=setUp) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=9 errors=0 failures=3> |
|
|
|
Here, we didn't need to use a tearDown function because we |
|
modified the test globals, which are a copy of the |
|
sample_doctest module dictionary. The test globals are |
|
automatically cleared for us after a test. |
|
""" |
|
|
|
def test_DocFileSuite(): |
|
"""We can test tests found in text files using a DocFileSuite. |
|
|
|
We create a suite by providing the names of one or more text |
|
files that include examples: |
|
|
|
>>> import unittest |
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=3> |
|
|
|
The test files are looked for in the directory containing the |
|
calling module. A package keyword argument can be provided to |
|
specify a different relative location. |
|
|
|
>>> import unittest |
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... package='test') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=3> |
|
|
|
Support for using a package's __loader__.get_data() is also |
|
provided. |
|
|
|
>>> import unittest, pkgutil, test |
|
>>> added_loader = False |
|
>>> if not hasattr(test, '__loader__'): |
|
... test.__loader__ = pkgutil.get_loader(test) |
|
... added_loader = True |
|
>>> try: |
|
... suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... package='test') |
|
... suite.run(unittest.TestResult()) |
|
... finally: |
|
... if added_loader: |
|
... del test.__loader__ |
|
<unittest.result.TestResult run=3 errors=0 failures=3> |
|
|
|
'/' should be used as a path separator. It will be converted |
|
to a native separator at run time: |
|
|
|
>>> suite = doctest.DocFileSuite('../test/test_doctest.txt') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=1 errors=0 failures=1> |
|
|
|
If DocFileSuite is used from an interactive session, then files |
|
are resolved relative to the directory of sys.argv[0]: |
|
|
|
>>> import types, os.path, test.test_doctest |
|
>>> save_argv = sys.argv |
|
>>> sys.argv = [test.test_doctest.__file__] |
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... package=types.ModuleType('__main__')) |
|
>>> sys.argv = save_argv |
|
|
|
By setting `module_relative=False`, os-specific paths may be |
|
used (including absolute paths and paths relative to the |
|
working directory): |
|
|
|
>>> # Get the absolute path of the test package. |
|
>>> test_doctest_path = os.path.abspath(test.test_doctest.__file__) |
|
>>> test_pkg_path = os.path.split(test_doctest_path)[0] |
|
|
|
>>> # Use it to find the absolute path of test_doctest.txt. |
|
>>> test_file = os.path.join(test_pkg_path, 'test_doctest.txt') |
|
|
|
>>> suite = doctest.DocFileSuite(test_file, module_relative=False) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=1 errors=0 failures=1> |
|
|
|
It is an error to specify `package` when `module_relative=False`: |
|
|
|
>>> suite = doctest.DocFileSuite(test_file, module_relative=False, |
|
... package='test') |
|
Traceback (most recent call last): |
|
ValueError: Package may only be specified for module-relative paths. |
|
|
|
You can specify initial global variables: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... globs={'favorite_color': 'blue'}) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=2> |
|
|
|
In this case, we supplied a missing favorite color. You can |
|
provide doctest options: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... optionflags=doctest.DONT_ACCEPT_BLANKLINE, |
|
... globs={'favorite_color': 'blue'}) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=3> |
|
|
|
And, you can provide setUp and tearDown functions: |
|
|
|
>>> def setUp(t): |
|
... import test.test_doctest |
|
... test.test_doctest.sillySetup = True |
|
|
|
>>> def tearDown(t): |
|
... import test.test_doctest |
|
... del test.test_doctest.sillySetup |
|
|
|
Here, we installed a silly variable that the test expects: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... setUp=setUp, tearDown=tearDown) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=2> |
|
|
|
But the tearDown restores sanity: |
|
|
|
>>> import test.test_doctest |
|
>>> test.test_doctest.sillySetup |
|
Traceback (most recent call last): |
|
... |
|
AttributeError: 'module' object has no attribute 'sillySetup' |
|
|
|
The setUp and tearDown functions are passed test objects. |
|
Here, we'll use a setUp function to set the favorite color in |
|
test_doctest.txt: |
|
|
|
>>> def setUp(test): |
|
... test.globs['favorite_color'] = 'blue' |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', setUp=setUp) |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=1 errors=0 failures=0> |
|
|
|
Here, we didn't need to use a tearDown function because we |
|
modified the test globals. The test globals are |
|
automatically cleared for us after a test. |
|
|
|
Tests in a file run using `DocFileSuite` can also access the |
|
`__file__` global, which is set to the name of the file |
|
containing the tests: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest3.txt') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=1 errors=0 failures=0> |
|
|
|
If the tests contain non-ASCII characters, we have to specify which |
|
encoding the file is encoded with. We do so by using the `encoding` |
|
parameter: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... 'test_doctest2.txt', |
|
... 'test_doctest4.txt', |
|
... encoding='utf-8') |
|
>>> suite.run(unittest.TestResult()) |
|
<unittest.result.TestResult run=3 errors=0 failures=2> |
|
|
|
""" |
|
|
|
def test_trailing_space_in_test(): |
|
""" |
|
Trailing spaces in expected output are significant: |
|
|
|
>>> x, y = 'foo', '' |
|
>>> print x, y |
|
foo \n |
|
""" |
|
|
|
|
|
def test_unittest_reportflags(): |
|
"""Default unittest reporting flags can be set to control reporting |
|
|
|
Here, we'll set the REPORT_ONLY_FIRST_FAILURE option so we see |
|
only the first failure of each test. First, we'll look at the |
|
output without the flag. The file test_doctest.txt file has two |
|
tests. They both fail if blank lines are disabled: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... optionflags=doctest.DONT_ACCEPT_BLANKLINE) |
|
>>> import unittest |
|
>>> result = suite.run(unittest.TestResult()) |
|
>>> print result.failures[0][1] # doctest: +ELLIPSIS |
|
Traceback ... |
|
Failed example: |
|
favorite_color |
|
... |
|
Failed example: |
|
if 1: |
|
... |
|
|
|
Note that we see both failures displayed. |
|
|
|
>>> old = doctest.set_unittest_reportflags( |
|
... doctest.REPORT_ONLY_FIRST_FAILURE) |
|
|
|
Now, when we run the test: |
|
|
|
>>> result = suite.run(unittest.TestResult()) |
|
>>> print result.failures[0][1] # doctest: +ELLIPSIS |
|
Traceback ... |
|
Failed example: |
|
favorite_color |
|
Exception raised: |
|
... |
|
NameError: name 'favorite_color' is not defined |
|
<BLANKLINE> |
|
<BLANKLINE> |
|
|
|
We get only the first failure. |
|
|
|
If we give any reporting options when we set up the tests, |
|
however: |
|
|
|
>>> suite = doctest.DocFileSuite('test_doctest.txt', |
|
... optionflags=doctest.DONT_ACCEPT_BLANKLINE | doctest.REPORT_NDIFF) |
|
|
|
Then the default eporting options are ignored: |
|
|
|
>>> result = suite.run(unittest.TestResult()) |
|
>>> print result.failures[0][1] # doctest: +ELLIPSIS |
|
Traceback ... |
|
Failed example: |
|
favorite_color |
|
... |
|
Failed example: |
|
if 1: |
|
print 'a' |
|
print |
|
print 'b' |
|
Differences (ndiff with -expected +actual): |
|
a |
|
- <BLANKLINE> |
|
+ |
|
b |
|
<BLANKLINE> |
|
<BLANKLINE> |
|
|
|
|
|
Test runners can restore the formatting flags after they run: |
|
|
|
>>> ignored = doctest.set_unittest_reportflags(old) |
|
|
|
""" |
|
|
|
def test_testfile(): r""" |
|
Tests for the `testfile()` function. This function runs all the |
|
doctest examples in a given file. In its simple invokation, it is |
|
called with the name of a file, which is taken to be relative to the |
|
calling module. The return value is (#failures, #tests). |
|
|
|
We don't want `-v` in sys.argv for these tests. |
|
|
|
>>> save_argv = sys.argv |
|
>>> if '-v' in sys.argv: |
|
... sys.argv = [arg for arg in save_argv if arg != '-v'] |
|
|
|
|
|
>>> doctest.testfile('test_doctest.txt') # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File "...", line 6, in test_doctest.txt |
|
Failed example: |
|
favorite_color |
|
Exception raised: |
|
... |
|
NameError: name 'favorite_color' is not defined |
|
********************************************************************** |
|
1 items had failures: |
|
1 of 2 in test_doctest.txt |
|
***Test Failed*** 1 failures. |
|
TestResults(failed=1, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
(Note: we'll be clearing doctest.master after each call to |
|
`doctest.testfile`, to suppress warnings about multiple tests with the |
|
same name.) |
|
|
|
Globals may be specified with the `globs` and `extraglobs` parameters: |
|
|
|
>>> globs = {'favorite_color': 'blue'} |
|
>>> doctest.testfile('test_doctest.txt', globs=globs) |
|
TestResults(failed=0, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
>>> extraglobs = {'favorite_color': 'red'} |
|
>>> doctest.testfile('test_doctest.txt', globs=globs, |
|
... extraglobs=extraglobs) # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File "...", line 6, in test_doctest.txt |
|
Failed example: |
|
favorite_color |
|
Expected: |
|
'blue' |
|
Got: |
|
'red' |
|
********************************************************************** |
|
1 items had failures: |
|
1 of 2 in test_doctest.txt |
|
***Test Failed*** 1 failures. |
|
TestResults(failed=1, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
The file may be made relative to a given module or package, using the |
|
optional `module_relative` parameter: |
|
|
|
>>> doctest.testfile('test_doctest.txt', globs=globs, |
|
... module_relative='test') |
|
TestResults(failed=0, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
Verbosity can be increased with the optional `verbose` parameter: |
|
|
|
>>> doctest.testfile('test_doctest.txt', globs=globs, verbose=True) |
|
Trying: |
|
favorite_color |
|
Expecting: |
|
'blue' |
|
ok |
|
Trying: |
|
if 1: |
|
print 'a' |
|
print |
|
print 'b' |
|
Expecting: |
|
a |
|
<BLANKLINE> |
|
b |
|
ok |
|
1 items passed all tests: |
|
2 tests in test_doctest.txt |
|
2 tests in 1 items. |
|
2 passed and 0 failed. |
|
Test passed. |
|
TestResults(failed=0, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
The name of the test may be specified with the optional `name` |
|
parameter: |
|
|
|
>>> doctest.testfile('test_doctest.txt', name='newname') |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File "...", line 6, in newname |
|
... |
|
TestResults(failed=1, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
The summary report may be suppressed with the optional `report` |
|
parameter: |
|
|
|
>>> doctest.testfile('test_doctest.txt', report=False) |
|
... # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File "...", line 6, in test_doctest.txt |
|
Failed example: |
|
favorite_color |
|
Exception raised: |
|
... |
|
NameError: name 'favorite_color' is not defined |
|
TestResults(failed=1, attempted=2) |
|
>>> doctest.master = None # Reset master. |
|
|
|
The optional keyword argument `raise_on_error` can be used to raise an |
|
exception on the first error (which may be useful for postmortem |
|
debugging): |
|
|
|
>>> doctest.testfile('test_doctest.txt', raise_on_error=True) |
|
... # doctest: +ELLIPSIS |
|
Traceback (most recent call last): |
|
UnexpectedException: ... |
|
>>> doctest.master = None # Reset master. |
|
|
|
If the tests contain non-ASCII characters, the tests might fail, since |
|
it's unknown which encoding is used. The encoding can be specified |
|
using the optional keyword argument `encoding`: |
|
|
|
>>> doctest.testfile('test_doctest4.txt') # doctest: +ELLIPSIS |
|
********************************************************************** |
|
File "...", line 7, in test_doctest4.txt |
|
Failed example: |
|
u'...' |
|
Expected: |
|
u'f\xf6\xf6' |
|
Got: |
|
u'f\xc3\xb6\xc3\xb6' |
|
********************************************************************** |
|
... |
|
********************************************************************** |
|
1 items had failures: |
|
2 of 4 in test_doctest4.txt |
|
***Test Failed*** 2 failures. |
|
TestResults(failed=2, attempted=4) |
|
>>> doctest.master = None # Reset master. |
|
|
|
>>> doctest.testfile('test_doctest4.txt', encoding='utf-8') |
|
TestResults(failed=0, attempted=4) |
|
>>> doctest.master = None # Reset master. |
|
|
|
Switch the module encoding to 'utf-8' to test the verbose output without |
|
bothering with the current sys.stdout encoding. |
|
|
|
>>> doctest._encoding, saved_encoding = 'utf-8', doctest._encoding |
|
>>> doctest.testfile('test_doctest4.txt', encoding='utf-8', verbose=True) |
|
Trying: |
|
u'föö' |
|
Expecting: |
|
u'f\xf6\xf6' |
|
ok |
|
Trying: |
|
u'bąr' |
|
Expecting: |
|
u'b\u0105r' |
|
ok |
|
Trying: |
|
'föö' |
|
Expecting: |
|
'f\xc3\xb6\xc3\xb6' |
|
ok |
|
Trying: |
|
'bąr' |
|
Expecting: |
|
'b\xc4\x85r' |
|
ok |
|
1 items passed all tests: |
|
4 tests in test_doctest4.txt |
|
4 tests in 1 items. |
|
4 passed and 0 failed. |
|
Test passed. |
|
TestResults(failed=0, attempted=4) |
|
>>> doctest._encoding = saved_encoding |
|
>>> doctest.master = None # Reset master. |
|
>>> sys.argv = save_argv |
|
""" |
|
|
|
def test_lineendings(): r""" |
|
*nix systems use \n line endings, while Windows systems use \r\n. Python |
|
handles this using universal newline mode for reading files. Let's make |
|
sure doctest does so (issue 8473) by creating temporary test files using each |
|
of the two line disciplines. One of the two will be the "wrong" one for the |
|
platform the test is run on. |
|
|
|
Windows line endings first: |
|
|
|
>>> import tempfile, os |
|
>>> fn = tempfile.mktemp() |
|
>>> with open(fn, 'wb') as f: |
|
... f.write('Test:\r\n\r\n >>> x = 1 + 1\r\n\r\nDone.\r\n') |
|
>>> doctest.testfile(fn, module_relative=False, verbose=False) |
|
TestResults(failed=0, attempted=1) |
|
>>> os.remove(fn) |
|
|
|
And now *nix line endings: |
|
|
|
>>> fn = tempfile.mktemp() |
|
>>> with open(fn, 'wb') as f: |
|
... f.write('Test:\n\n >>> x = 1 + 1\n\nDone.\n') |
|
>>> doctest.testfile(fn, module_relative=False, verbose=False) |
|
TestResults(failed=0, attempted=1) |
|
>>> os.remove(fn) |
|
|
|
""" |
|
|
|
# old_test1, ... used to live in doctest.py, but cluttered it. Note |
|
# that these use the deprecated doctest.Tester, so should go away (or |
|
# be rewritten) someday. |
|
|
|
def old_test1(): r""" |
|
>>> from doctest import Tester |
|
>>> t = Tester(globs={'x': 42}, verbose=0) |
|
>>> t.runstring(r''' |
|
... >>> x = x * 2 |
|
... >>> print x |
|
... 42 |
|
... ''', 'XYZ') |
|
********************************************************************** |
|
Line 3, in XYZ |
|
Failed example: |
|
print x |
|
Expected: |
|
42 |
|
Got: |
|
84 |
|
TestResults(failed=1, attempted=2) |
|
>>> t.runstring(">>> x = x * 2\n>>> print x\n84\n", 'example2') |
|
TestResults(failed=0, attempted=2) |
|
>>> t.summarize() |
|
********************************************************************** |
|
1 items had failures: |
|
1 of 2 in XYZ |
|
***Test Failed*** 1 failures. |
|
TestResults(failed=1, attempted=4) |
|
>>> t.summarize(verbose=1) |
|
1 items passed all tests: |
|
2 tests in example2 |
|
********************************************************************** |
|
1 items had failures: |
|
1 of 2 in XYZ |
|
4 tests in 2 items. |
|
3 passed and 1 failed. |
|
***Test Failed*** 1 failures. |
|
TestResults(failed=1, attempted=4) |
|
""" |
|
|
|
def old_test2(): r""" |
|
>>> from doctest import Tester |
|
>>> t = Tester(globs={}, verbose=1) |
|
>>> test = r''' |
|
... # just an example |
|
... >>> x = 1 + 2 |
|
... >>> x |
|
... 3 |
|
... ''' |
|
>>> t.runstring(test, "Example") |
|
Running string Example |
|
Trying: |
|
x = 1 + 2 |
|
Expecting nothing |
|
ok |
|
Trying: |
|
x |
|
Expecting: |
|
3 |
|
ok |
|
0 of 2 examples failed in string Example |
|
TestResults(failed=0, attempted=2) |
|
""" |
|
|
|
def old_test3(): r""" |
|
>>> from doctest import Tester |
|
>>> t = Tester(globs={}, verbose=0) |
|
>>> def _f(): |
|
... '''Trivial docstring example. |
|
... >>> assert 2 == 2 |
|
... ''' |
|
... return 32 |
|
... |
|
>>> t.rundoc(_f) # expect 0 failures in 1 example |
|
TestResults(failed=0, attempted=1) |
|
""" |
|
|
|
def old_test4(): """ |
|
>>> import types |
|
>>> m1 = types.ModuleType('_m1') |
|
>>> m2 = types.ModuleType('_m2') |
|
>>> test_data = \""" |
|
... def _f(): |
|
... '''>>> assert 1 == 1 |
|
... ''' |
|
... def g(): |
|
... '''>>> assert 2 != 1 |
|
... ''' |
|
... class H: |
|
... '''>>> assert 2 > 1 |
|
... ''' |
|
... def bar(self): |
|
... '''>>> assert 1 < 2 |
|
... ''' |
|
... \""" |
|
>>> exec test_data in m1.__dict__ |
|
>>> exec test_data in m2.__dict__ |
|
>>> m1.__dict__.update({"f2": m2._f, "g2": m2.g, "h2": m2.H}) |
|
|
|
Tests that objects outside m1 are excluded: |
|
|
|
>>> from doctest import Tester |
|
>>> t = Tester(globs={}, verbose=0) |
|
>>> t.rundict(m1.__dict__, "rundict_test", m1) # f2 and g2 and h2 skipped |
|
TestResults(failed=0, attempted=4) |
|
|
|
Once more, not excluding stuff outside m1: |
|
|
|
>>> t = Tester(globs={}, verbose=0) |
|
>>> t.rundict(m1.__dict__, "rundict_test_pvt") # None are skipped. |
|
TestResults(failed=0, attempted=8) |
|
|
|
The exclusion of objects from outside the designated module is |
|
meant to be invoked automagically by testmod. |
|
|
|
>>> doctest.testmod(m1, verbose=False) |
|
TestResults(failed=0, attempted=4) |
|
""" |
|
|
|
###################################################################### |
|
## Main |
|
###################################################################### |
|
|
|
def test_main(): |
|
# Check the doctest cases in doctest itself: |
|
test_support.run_doctest(doctest, verbosity=True) |
|
|
|
from test import test_doctest |
|
|
|
# Ignore all warnings about the use of class Tester in this module. |
|
deprecations = [] |
|
if __debug__: |
|
deprecations.append(("class Tester is deprecated", DeprecationWarning)) |
|
if sys.py3kwarning: |
|
deprecations += [("backquote not supported", SyntaxWarning), |
|
("execfile.. not supported", DeprecationWarning)] |
|
with test_support.check_warnings(*deprecations): |
|
# Check the doctest cases defined here: |
|
test_support.run_doctest(test_doctest, verbosity=True) |
|
|
|
import sys |
|
def test_coverage(coverdir): |
|
trace = test_support.import_module('trace') |
|
tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix,], |
|
trace=0, count=1) |
|
tracer.run('reload(doctest); test_main()') |
|
r = tracer.results() |
|
print 'Writing coverage results...' |
|
r.write_results(show_missing=True, summary=True, |
|
coverdir=coverdir) |
|
|
|
if __name__ == '__main__': |
|
if '-c' in sys.argv: |
|
test_coverage('/tmp/doctest.cover') |
|
else: |
|
test_main() |