Issue #3158: doctest can now find doctests in functions and methods

written in C.

As a part of this, a few doctests have been added to the builtins module
(on hex(), oct(), and bin()), a doctest has been fixed (hopefully on all
platforms) on float, and test_builtins now runs doctests in builtins.
This commit is contained in:
Zachary Ware 2013-11-24 01:19:09 -06:00
parent 091167c1ca
commit a4b7a7548c
7 changed files with 65 additions and 28 deletions

View File

@ -278,6 +278,10 @@ strings are treated as if they were docstrings. In output, a key ``K`` in
Any classes found are recursively searched similarly, to test docstrings in
their contained methods and nested classes.
.. impl-detail::
Prior to version 3.4, extension modules written in C were not fully
searched by doctest.
.. _doctest-finding-examples:
@ -1285,9 +1289,8 @@ DocTestFinder objects
A processing class used to extract the :class:`DocTest`\ s that are relevant to
a given object, from its docstring and the docstrings of its contained objects.
:class:`DocTest`\ s can currently be extracted from the following object types:
modules, functions, classes, methods, staticmethods, classmethods, and
properties.
:class:`DocTest`\ s can be extracted from modules, classes, functions,
methods, staticmethods, classmethods, and properties.
The optional argument *verbose* can be used to display the objects searched by
the finder. It defaults to ``False`` (no output).

View File

@ -918,6 +918,8 @@ class DocTestFinder:
return module is inspect.getmodule(object)
elif inspect.isfunction(object):
return module.__dict__ is object.__globals__
elif inspect.ismethoddescriptor(object):
return module.__name__ == object.__objclass__.__module__
elif inspect.isclass(object):
return module.__name__ == object.__module__
elif hasattr(object, '__module__'):
@ -950,7 +952,7 @@ class DocTestFinder:
for valname, val in obj.__dict__.items():
valname = '%s.%s' % (name, valname)
# Recurse to functions & classes.
if ((inspect.isfunction(val) or inspect.isclass(val)) and
if ((inspect.isroutine(val) or inspect.isclass(val)) and
self._from_module(module, val)):
self._find(tests, val, valname, module, source_lines,
globs, seen)
@ -962,9 +964,8 @@ class DocTestFinder:
raise ValueError("DocTestFinder.find: __test__ keys "
"must be strings: %r" %
(type(valname),))
if not (inspect.isfunction(val) or inspect.isclass(val) or
inspect.ismethod(val) or inspect.ismodule(val) or
isinstance(val, str)):
if not (inspect.isroutine(val) or inspect.isclass(val) or
inspect.ismodule(val) or isinstance(val, str)):
raise ValueError("DocTestFinder.find: __test__ values "
"must be strings, functions, methods, "
"classes, or modules: %r" %
@ -983,7 +984,7 @@ class DocTestFinder:
val = getattr(obj, valname).__func__
# Recurse to methods, properties, and nested classes.
if ((inspect.isfunction(val) or inspect.isclass(val) or
if ((inspect.isroutine(val) or inspect.isclass(val) or
isinstance(val, property)) and
self._from_module(module, val)):
valname = '%s.%s' % (name, valname)

View File

@ -1592,21 +1592,10 @@ class TestSorted(unittest.TestCase):
data = 'The quick Brown fox Jumped over The lazy Dog'.split()
self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0)
def test_main(verbose=None):
test_classes = (BuiltinTest, TestSorted)
run_unittest(*test_classes)
# verify reference counting
if verbose and hasattr(sys, "gettotalrefcount"):
import gc
counts = [None] * 5
for i in range(len(counts)):
run_unittest(*test_classes)
gc.collect()
counts[i] = sys.gettotalrefcount()
print(counts)
def load_tests(loader, tests, pattern):
from doctest import DocTestSuite
tests.addTest(DocTestSuite(builtins))
return tests
if __name__ == "__main__":
test_main(verbose=True)
unittest.main()

View File

@ -644,6 +644,35 @@ DocTestFinder finds the line number of each example:
>>> test = doctest.DocTestFinder().find(f)[0]
>>> [e.lineno for e in test.examples]
[1, 9, 12]
Finding Doctests in Modules Not Written in Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DocTestFinder can also find doctests in most modules not written in Python.
We'll use builtins as an example, since it almost certainly isn't written in
plain ol' Python and is guaranteed to be available.
>>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins)
>>> len(tests) # how many objects checked for doctests
794
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # how many objects actually have doctests
8
>>> for t in real_tests:
... print('{} {}'.format(len(t.examples), t.name))
...
1 builtins.bin
3 builtins.float.as_integer_ratio
2 builtins.float.fromhex
2 builtins.float.hex
1 builtins.hex
1 builtins.int
2 builtins.int.bit_length
1 builtins.oct
Note here that 'bin', 'oct', and 'hex' are functions; 'float.as_integer_ratio',
'float.hex', and 'int.bit_length' are methods; 'float.fromhex' is a classmethod,
and 'int' is a type.
"""
def test_DocTestParser(): r"""

View File

@ -68,6 +68,9 @@ Core and Builtins
Library
-------
- Issue #3158: doctest can now find doctests in functions and methods
written in C.
- Issue #13477: Added command line interface to the tarfile module.
Original patch by Berker Peksag.

View File

@ -1417,7 +1417,7 @@ Create a floating-point number from a hexadecimal string.\n\
>>> float.fromhex('0x1.ffffp10')\n\
2047.984375\n\
>>> float.fromhex('-0x1p-1074')\n\
-4.9406564584124654e-324");
-5e-324");
static PyObject *

View File

@ -350,7 +350,11 @@ builtin_bin(PyObject *self, PyObject *v)
PyDoc_STRVAR(bin_doc,
"bin(number) -> string\n\
\n\
Return the binary representation of an integer.");
Return the binary representation of an integer.\n\
\n\
>>> bin(2796202)\n\
'0b1010101010101010101010'\n\
");
static PyObject *
@ -1276,7 +1280,11 @@ builtin_hex(PyObject *self, PyObject *v)
PyDoc_STRVAR(hex_doc,
"hex(number) -> string\n\
\n\
Return the hexadecimal representation of an integer.");
Return the hexadecimal representation of an integer.\n\
\n\
>>> hex(3735928559)\n\
'0xdeadbeef'\n\
");
static PyObject *
@ -1476,7 +1484,11 @@ builtin_oct(PyObject *self, PyObject *v)
PyDoc_STRVAR(oct_doc,
"oct(number) -> string\n\
\n\
Return the octal representation of an integer.");
Return the octal representation of an integer.\n\
\n\
>>> oct(342391)\n\
'0o1234567'\n\
");
static PyObject *