简体   繁体   中英

@cached_property doctest is not detected

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM