mirror of
https://github.com/python/cpython
synced 2024-09-05 08:17:45 +00:00
bpo-28249: fix lineno
location for empty DocTest
instances (GH-30498)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
09be18a73d
commit
8db2b3b687
|
@ -1085,19 +1085,21 @@ def _get_test(self, obj, name, module, globs, source_lines):
|
|||
|
||||
def _find_lineno(self, obj, source_lines):
|
||||
"""
|
||||
Return a line number of the given object's docstring. Note:
|
||||
this method assumes that the object has a docstring.
|
||||
Return a line number of the given object's docstring.
|
||||
|
||||
Returns `None` if the given object does not have a docstring.
|
||||
"""
|
||||
lineno = None
|
||||
docstring = getattr(obj, '__doc__', None)
|
||||
|
||||
# Find the line number for modules.
|
||||
if inspect.ismodule(obj):
|
||||
if inspect.ismodule(obj) and docstring is not None:
|
||||
lineno = 0
|
||||
|
||||
# Find the line number for classes.
|
||||
# Note: this could be fooled if a class is defined multiple
|
||||
# times in a single file.
|
||||
if inspect.isclass(obj):
|
||||
if inspect.isclass(obj) and docstring is not None:
|
||||
if source_lines is None:
|
||||
return None
|
||||
pat = re.compile(r'^\s*class\s*%s\b' %
|
||||
|
@ -1109,7 +1111,9 @@ def _find_lineno(self, obj, source_lines):
|
|||
|
||||
# Find the line number for functions & methods.
|
||||
if inspect.ismethod(obj): obj = obj.__func__
|
||||
if inspect.isfunction(obj): obj = obj.__code__
|
||||
if inspect.isfunction(obj) and getattr(obj, '__doc__', None):
|
||||
# We don't use `docstring` var here, because `obj` can be changed.
|
||||
obj = obj.__code__
|
||||
if inspect.istraceback(obj): obj = obj.tb_frame
|
||||
if inspect.isframe(obj): obj = obj.f_code
|
||||
if inspect.iscode(obj):
|
||||
|
|
50
Lib/test/doctest_lineno.py
Normal file
50
Lib/test/doctest_lineno.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# This module is used in `test_doctest`.
|
||||
# It must not have a docstring.
|
||||
|
||||
def func_with_docstring():
|
||||
"""Some unrelated info."""
|
||||
|
||||
|
||||
def func_without_docstring():
|
||||
pass
|
||||
|
||||
|
||||
def func_with_doctest():
|
||||
"""
|
||||
This function really contains a test case.
|
||||
|
||||
>>> func_with_doctest.__name__
|
||||
'func_with_doctest'
|
||||
"""
|
||||
return 3
|
||||
|
||||
|
||||
class ClassWithDocstring:
|
||||
"""Some unrelated class information."""
|
||||
|
||||
|
||||
class ClassWithoutDocstring:
|
||||
pass
|
||||
|
||||
|
||||
class ClassWithDoctest:
|
||||
"""This class really has a test case in it.
|
||||
|
||||
>>> ClassWithDoctest.__name__
|
||||
'ClassWithDoctest'
|
||||
"""
|
||||
|
||||
|
||||
class MethodWrapper:
|
||||
def method_with_docstring(self):
|
||||
"""Method with a docstring."""
|
||||
|
||||
def method_without_docstring(self):
|
||||
pass
|
||||
|
||||
def method_with_doctest(self):
|
||||
"""
|
||||
This has a doctest!
|
||||
>>> MethodWrapper.method_with_doctest.__name__
|
||||
'method_with_doctest'
|
||||
"""
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
# NOTE: There are some additional tests relating to interaction with
|
||||
# zipimport in the test_zipimport_support test module.
|
||||
# There are also related tests in `test_doctest2` module.
|
||||
|
||||
######################################################################
|
||||
## Sample Objects (used by test cases)
|
||||
|
@ -460,7 +461,7 @@ def basics(): r"""
|
|||
>>> tests = finder.find(sample_func)
|
||||
|
||||
>>> print(tests) # doctest: +ELLIPSIS
|
||||
[<DocTest sample_func from test_doctest.py:33 (1 example)>]
|
||||
[<DocTest sample_func from test_doctest.py:34 (1 example)>]
|
||||
|
||||
The exact name depends on how test_doctest was invoked, so allow for
|
||||
leading path components.
|
||||
|
@ -642,6 +643,26 @@ def basics(): r"""
|
|||
1 SampleClass.double
|
||||
1 SampleClass.get
|
||||
|
||||
When used with `exclude_empty=False` we are also interested in line numbers
|
||||
of doctests that are empty.
|
||||
It used to be broken for quite some time until `bpo-28249`.
|
||||
|
||||
>>> from test import doctest_lineno
|
||||
>>> tests = doctest.DocTestFinder(exclude_empty=False).find(doctest_lineno)
|
||||
>>> for t in tests:
|
||||
... print('%5s %s' % (t.lineno, t.name))
|
||||
None test.doctest_lineno
|
||||
22 test.doctest_lineno.ClassWithDocstring
|
||||
30 test.doctest_lineno.ClassWithDoctest
|
||||
None test.doctest_lineno.ClassWithoutDocstring
|
||||
None test.doctest_lineno.MethodWrapper
|
||||
39 test.doctest_lineno.MethodWrapper.method_with_docstring
|
||||
45 test.doctest_lineno.MethodWrapper.method_with_doctest
|
||||
None test.doctest_lineno.MethodWrapper.method_without_docstring
|
||||
4 test.doctest_lineno.func_with_docstring
|
||||
12 test.doctest_lineno.func_with_doctest
|
||||
None test.doctest_lineno.func_without_docstring
|
||||
|
||||
Turning off Recursion
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
DocTestFinder can be told not to look for tests in contained objects
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Set :attr:`doctest.DocTest.lineno` to ``None`` when object does not have
|
||||
:attr:`__doc__`.
|
Loading…
Reference in a new issue