Skip to content

Commit

Permalink
[7.4.x] Fix doctest collection of functools.cached_property objects. (
Browse files Browse the repository at this point in the history
#11403)

Co-authored-by: Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>
  • Loading branch information
github-actions[bot] and RonnyPfannschmidt committed Sep 7, 2023
1 parent 79c2012 commit 6e49a74
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -374,6 +374,7 @@ Tony Narlock
Tor Colvin
Trevor Bekolay
Tyler Goodlet
Tyler Smart
Tzu-ping Chung
Vasily Kuznetsov
Victor Maryama
Expand Down
1 change: 1 addition & 0 deletions changelog/11237.bugfix.rst
@@ -0,0 +1 @@
Fix doctest collection of `functools.cached_property` objects.
20 changes: 20 additions & 0 deletions src/_pytest/doctest.py
@@ -1,5 +1,6 @@
"""Discover and run doctests in modules and test files."""
import bdb
import functools
import inspect
import os
import platform
Expand Down Expand Up @@ -536,6 +537,25 @@ def _find(
tests, obj, name, module, source_lines, globs, seen
)

if sys.version_info < (3, 13):

def _from_module(self, module, object):
"""`cached_property` objects are never considered a part
of the 'current module'. As such they are skipped by doctest.
Here we override `_from_module` to check the underlying
function instead. https://github.com/python/cpython/issues/107995
"""
if hasattr(functools, "cached_property") and 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]

else: # pragma: no cover
pass

if self.path.name == "conftest.py":
module = self.config.pluginmanager._importconftest(
self.path,
Expand Down
21 changes: 21 additions & 0 deletions testing/test_doctest.py
Expand Up @@ -482,6 +482,27 @@ def test_doctestmodule(self, pytester: Pytester):
reprec = pytester.inline_run(p, "--doctest-modules")
reprec.assertoutcome(failed=1)

@pytest.mark.skipif(
sys.version_info[:2] <= (3, 7), reason="Only Python 3.7 or less"
)
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(
Expand Down

0 comments on commit 6e49a74

Please sign in to comment.