diff options
| author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2021-05-05 11:01:21 -0700 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-05 20:01:21 +0200 | 
| commit | 10d6f6bfd749c0e7da51a96f53ca326c336f7a00 (patch) | |
| tree | ae5dc9e22210b4a6c2d65c2e2556fa9e6ed900be | |
| parent | ce4fee210bb604726e5da0ff15952a60c2098f88 (diff) | |
| download | cpython-git-10d6f6bfd749c0e7da51a96f53ca326c336f7a00.tar.gz | |
bpo-35753: Fix crash in doctest with unwrap-able functions (GH-22981) (#25926)
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.
We simply skip any object that throws this exception.
This should handle the majority of cases.
(cherry picked from commit 565a31804c1139fe7886f38af3b3923653b0c1b3)
Co-authored-by: Alfred Perlstein <alfred@fb.com>
| -rw-r--r-- | Lib/doctest.py | 15 | ||||
| -rw-r--r-- | Lib/test/test_doctest.py | 15 | ||||
| -rw-r--r-- | Misc/NEWS.d/next/Tests/2020-10-25-19-20-26.bpo-35753.2LT-hO.rst | 2 | 
3 files changed, 29 insertions, 3 deletions
| diff --git a/Lib/doctest.py b/Lib/doctest.py index e95c333f48..ba898f6540 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -973,6 +973,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 @@ -995,9 +1006,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) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 6f51b1bc4f..828a0ff567 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -15,6 +15,7 @@ import importlib.util  import unittest  import tempfile  import shutil +import types  import contextlib  # NOTE: There are some additional tests relating to interaction with @@ -443,7 +444,7 @@ We'll simulate a __file__ attr that ends in pyc:      >>> tests = finder.find(sample_func)      >>> print(tests)  # doctest: +ELLIPSIS -    [<DocTest sample_func from ...:27 (1 example)>] +    [<DocTest sample_func from test_doctest.py:28 (1 example)>]  The exact name depends on how test_doctest was invoked, so allow for  leading path components. @@ -698,6 +699,18 @@ and 'int' is a type.  class TestDocTestFinder(unittest.TestCase): +    def test_issue35753(self): +        # This import of `call` should trigger issue35753 when +        # `support.run_doctest` is called due to unwrap failing, +        # however with a patched doctest this should succeed. +        from unittest.mock import call +        dummy_module = types.ModuleType("dummy") +        dummy_module.__dict__['inject_call'] = call +        try: +            support.run_doctest(dummy_module, verbosity=True) +        except ValueError as e: +            raise support.TestFailed("Doctest unwrap failed") from e +      def test_empty_namespace_package(self):          pkg_name = 'doctest_empty_pkg'          with tempfile.TemporaryDirectory() as parent_dir: diff --git a/Misc/NEWS.d/next/Tests/2020-10-25-19-20-26.bpo-35753.2LT-hO.rst b/Misc/NEWS.d/next/Tests/2020-10-25-19-20-26.bpo-35753.2LT-hO.rst new file mode 100644 index 0000000000..eddfc25906 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-10-25-19-20-26.bpo-35753.2LT-hO.rst @@ -0,0 +1,2 @@ +Fix crash in doctest when doctest parses modules that include unwrappable +functions by skipping those functions. | 
