bpo-35753: fix doctest on unwrappables funcs 3/3

Summary:

Ignore objects that inspect.unwrap throws due to
too many wrappers.  This is a very rare case, however
it can easily be surfaced when a module under doctest
imports unitest.mock.call into its namespace.

This commit adds the fix to the module.

We simply skip any object that throws this exception.

This should handle the majority of cases.

Future thoughts:
1. Should catching this be optional defaulting to true,
but allowing for folks to rethrow the exception to insist
on truly clean code?
2. Should we break out _find() into more sub functions sp
that we can more easily derive our own versions for each
sub function that _find does making it easier to fix
future issues?
3. Should we include a way to denylist by `id` some
objects so that future objects that cause problems
with doctest can be passed in to ignore?

Test Plan:

Reviewers:
This commit is contained in:
Alfred Perlstein 2020-10-20 10:27:46 -07:00 committed by Alfred Perlstein
parent 5b83576376
commit 81e0d99c6d
2 changed files with 15 additions and 2 deletions

View File

@ -976,6 +976,17 @@ class DocTestFinder:
else:
raise ValueError("object must be a class or function")
def _is_routine(self, obj):
"""
Safely unwrap objects and determine if they are functions.
"""
maybe_routine = obj
try:
maybe_routine = inspect.unwrap(maybe_routine)
except ValueError:
pass
return inspect.isroutine(maybe_routine)
def _find(self, tests, obj, name, module, source_lines, globs, seen):
"""
Find tests for the given object and any contained objects, and
@ -998,9 +1009,9 @@ class DocTestFinder:
if inspect.ismodule(obj) and self._recurse:
for valname, val in obj.__dict__.items():
valname = '%s.%s' % (name, valname)
# Recurse to functions & classes.
if ((inspect.isroutine(inspect.unwrap(val))
or inspect.isclass(val)) and
if ((self._is_routine(val) or inspect.isclass(val)) and
self._from_module(module, val)):
self._find(tests, val, valname, module, source_lines,
globs, seen)

View File

@ -0,0 +1,2 @@
Fix crash in doctest when doctest parses modules that include unwrappable
functions by skipping those functions.