Fix doctest collection of `functools.cached_property` objects.

This commit is contained in:
Tyler Smart 2023-08-16 00:54:38 -06:00
parent 15fadd8c5c
commit d4fb6ac9f7
4 changed files with 37 additions and 1 deletions

View File

@ -379,6 +379,7 @@ Tor Colvin
Trevor Bekolay
Tushar Sadhwani
Tyler Goodlet
Tyler Smart
Tzu-ping Chung
Vasily Kuznetsov
Victor Maryama

View File

@ -0,0 +1 @@
Fix doctest collection of `functools.cached_property` objects.

View File

@ -1,5 +1,6 @@
"""Discover and run doctests in modules and test files."""
import bdb
import functools
import inspect
import os
import platform
@ -536,6 +537,21 @@ class DoctestModule(Module):
tests, obj, name, module, source_lines, globs, seen
)
class CachedPropertyAwareDocTestFinder(MockAwareDocTestFinder):
def _from_module(self, module, object):
"""Doctest code does not take into account `@cached_property`,
this is a hackish way to fix it. https://github.com/python/cpython/issues/107995
Wrap Doctest finder so that when it calls `_from_module` for
a cached_property it uses the underlying function instead of the
wrapped cached_property object.
"""
if isinstance(object, functools.cached_property):
object = object.func
# Type ignored because this is a private function.
return super()._from_module(module, object) # type: ignore[misc]
if self.path.name == "conftest.py":
module = self.config.pluginmanager._importconftest(
self.path,
@ -555,7 +571,7 @@ class DoctestModule(Module):
else:
raise
# Uses internal doctest module parsing mechanism.
finder = MockAwareDocTestFinder()
finder = CachedPropertyAwareDocTestFinder()
optionflags = get_optionflags(self)
runner = _get_runner(
verbose=False,

View File

@ -482,6 +482,24 @@ class TestDoctests:
reprec = pytester.inline_run(p, "--doctest-modules")
reprec.assertoutcome(failed=1)
def test_doctest_cached_property(self, pytester: Pytester):
p = pytester.makepyfile(
"""
import functools
class Foo:
@functools.cached_property
def foo(self):
'''
>>> assert False, "Tacos!"
'''
...
"""
)
result = pytester.runpytest(p, "--doctest-modules")
result.assert_outcomes(failed=1)
assert "Tacos!" in result.stdout.str()
def test_doctestmodule_external_and_issue116(self, pytester: Pytester):
p = pytester.mkpydir("hello")
p.joinpath("__init__.py").write_text(