Skip to content

DocTests for functools.cache()-decorated functions have no line number #136914

Description

@dlax

Bug report

Bug description:

(edited to reflect discussion comments)

doctests of functions decorated with functools.cache (or lru_cache()) do not get their line number retrieved, e.g.:

# file /tmp/t.py
import functools

@functools.cache
def f(x):
   """cached

   >>> f(1)
   -2
   """
   return -x
$ python -m doctest /tmp/t.py
**********************************************************************
File "/tmp/t.py", line ?, in t.f
Failed example:
    f(1)
Expected:
    -2
Got:
    -1
**********************************************************************
1 item had failures:
   1 of   1 in t.f
***Test Failed*** 1 failure.

where we can see that the File "..." line is missing the line number of the example.
Also:

>>> import doctest
>>> import t
>>> dt, = doctest.DocTestFinder().find(t)
>>> dt
<DocTest t.f from /home/denis/src/cpython/t.py:None (1 example)>
>>> print(dt.lineno)
None

This is because DocTest._find_lineno() relies on inspect.isfunction() to possibly inspect function's code and get line numbers; but inspect.isfunction() returns False for a function decorated with functools.cache because only plain types.FunctionType is considered.

Original question: Should such cached functions be considered as well in inspect.isfunction()?

I would be happy to work on a fix in case this change is acceptable.

CPython versions tested on:

CPython main branch, 3.13

Operating systems tested on:

No response

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Jul 21, 2025
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Jul 21, 2025
  3. picnixz commented on Jul 21, 2025

    @picnixz
    Member

    inspect.isfunction has very strict constraints and after being decorated by functools.cache, the object is no longer a function at runtime. So I don't think we should change anything in inspect. However we should change something in doctest.

    EDIT: Also, it might not necessarily be the case that the decorator is called at the same place where the function has been defined (sometimes, people write it in two steps).

    cc @serhiy-storchaka

  4. brianschubert commented on Jul 21, 2025

    @brianschubert
    Contributor

    For context, the was foreseen as being a possible issue in #115440 (review), but at the time it wasn't known whether a class wrapper using functools.wraps/functools.update_wrapper was a realistic use case. Evidently it is :-)

  5. serhiy-storchaka commented on Jul 21, 2025

    @serhiy-storchaka
    Member

    inspect.isroutine() is already used in some places of doctest. It should be used instead of inspect.isfunction() in other places as well.

  6. changed the title [-]functools.cache decorated functions not handled by inspect.isfunction()[/-] [+]DocTests for functools.cache()-decorated functions have no line number[/+] on Jul 22, 2025
  7. added a commit that references this issue on Jul 25, 2025
  8. added a commit that references this issue on Aug 4, 2025
  9. added 2 commits that reference this issue on Aug 10, 2025
  10. added a commit that references this issue on Aug 10, 2025
  11. added a commit that references this issue on Aug 19, 2025
  12. added a commit that references this issue on Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions