Commit f1b1cdd5 authored by Zachary Ware's avatar Zachary Ware

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.
parent e6953daa
......@@ -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).
......
......@@ -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)
......
......@@ -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()
......@@ -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"""
......
......@@ -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.
......
......@@ -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 *
......
......@@ -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 *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment