Skip to content

Commit 33958e7

Browse files
committed
bpo-35753: fix doctest on unwrappables funcs 2/2
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:
1 parent 042d246 commit 33958e7

File tree

2 files changed

+15
-2
lines changed

2 files changed

+15
-2
lines changed

Lib/doctest.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,17 @@ def _from_module(self, module, object):
972972
else:
973973
raise ValueError("object must be a class or function")
974974

975+
def _is_routine(self, obj):
976+
"""
977+
Safely unwrap objects and determine if they are functions.
978+
"""
979+
maybe_routine = obj
980+
try:
981+
maybe_routine = inspect.unwrap(maybe_routine)
982+
except ValueError:
983+
pass
984+
return inspect.isroutine(maybe_routine)
985+
975986
def _find(self, tests, obj, name, module, source_lines, globs, seen):
976987
"""
977988
Find tests for the given object and any contained objects, and
@@ -994,9 +1005,9 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
9941005
if inspect.ismodule(obj) and self._recurse:
9951006
for valname, val in obj.__dict__.items():
9961007
valname = '%s.%s' % (name, valname)
1008+
9971009
# Recurse to functions & classes.
998-
if ((inspect.isroutine(inspect.unwrap(val))
999-
or inspect.isclass(val)) and
1010+
if ((self._is_routine(val) or inspect.isclass(val)) and
10001011
self._from_module(module, val)):
10011012
self._find(tests, val, valname, module, source_lines,
10021013
globs, seen)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash in doctest when doctest parses modules that include unwrappable
2+
functions by skipping those functions.

0 commit comments

Comments
 (0)