I have a code. a.py
from functools import cached_property, cache
import doctest
class C1:
def test_1(self):
"""
>>> C1().test_1()
'f'
"""
return "f"
@property
def test_2(self):
"""
>>> C1().test_2
'p'
"""
return "p"
@cached_property
def test_3(self):
"""
>>> C1().test_3
'cp'
"""
return "cp"
@cache
def test_4(self):
"""
>>> C1().test_4()
'c'
"""
return "c"
doctest.testmod()
test_3
is a function decorated by @cached_property
.
It has a doctest. but that was not executed.
$ python3 a.py -v
Trying:
C1().test_1()
Expecting:
'f'
ok
Trying:
C1().test_2
Expecting:
'p'
ok
Trying:
C1().test_4()
Expecting:
'c'
ok
2 items had no tests:
__main__
__main__.C1
3 items passed all tests:
1 tests in __main__.C1.test_1
1 tests in __main__.C1.test_2
1 tests in __main__.C1.test_4
3 tests in 5 items.
3 passed and 0 failed.
Test passed.
How can I run test_3 doctest?
Environment
$ python3 --version
Python 3.9.6
$ uname
Darwin
The problem is likely caused by a difference in the implementation of cache
and cached_property
. Namely, cache
sets __module__
whereas cached_property
does not:
>>> from functools import cache, cached_property
>>> @cache
... def f(): pass
...
>>> @cached_property
... def g(): pass
...
>>> f.__module__
'__main__'
>>> g.__module__
'functools'
Functions that are not defined in the current __module__
are ignored by doctesting. This is intentional since otherwise all the doctests of the methods that you import at the top of the file would run. However, in this case, this seems like a bug to me.
One can explicitly add a method (or class) to the doctests for a module by adding it to __test__
, so in your case this should do the trick:
__test__= { "C1.test_3": C1.test_3 }
To fix this in Python, one should probably add self.__module__ = func.__module__
to this initializer and maybe all the others that update_wrapper()
sets for @cache
. But maybe this has unintended side effects and that's why this was not set in the first place.