mirror of
https://github.com/python/cpython
synced 2024-10-14 09:43:55 +00:00
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:
parent
091167c1ca
commit
a4b7a7548c
|
@ -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 @@ def _from_module(self, module, object):
|
|||
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 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
|
|||
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 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
|
|||
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 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
|
|||
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 @@ def test_baddecorator(self):
|
|||
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 @@ def test_DocTestFinder(): r"""
|
|||
>>> 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 *
|
||||
|
|
Loading…
Reference in a new issue