Skip to content

Doctest incorrectly locates a decorated function #115392

Closed
@chaudhary1337

Description

@chaudhary1337

Bug report

Bug description:

TL;DR: If a function is decorated, the doctest is unable to find the correct location of the function.

Example

Consider two simple files, main.py and decorate.py.

Contents of main.py:

from decorate import decorator


@decorator
def foo():
    """
    >>> foo()
    2
    """
    return 42

Contents of decorate.py:

import functools


def decorator(f):
    @functools.wraps(f)
    def inner():
        return f()

    return inner

If we run a doctest like so: python3 -m doctest main.py, we find the error correctly on the line number 7, the line which says >>> foo(). Traceback is output as follows.

**********************************************************************
File "/codemill/chaudhat/learning/demo/main.py", line 7, in main.foo
Failed example:
    foo()
Expected:
    2
Got:
    42
**********************************************************************
1 items had failures:
   1 of   2 in main.foo
***Test Failed*** 1 failures.

Incorrect Output

However, if we move the decorator definition in the decorate.py file by a few lines, as shown, (the space between could be empty/defining a function, etc.), we see that the doctest is unable to find the location of the decorated function, foo, and just outputs ? as the line number.

import functools







def decorator(f):
    @functools.wraps(f)
    def inner():
        return f()

    return inner

Traceback:

**********************************************************************
File "/codemill/chaudhat/learning/demo/main.py", line ?, in main.foo
Failed example:
    foo()
Expected:
    2
Got:
    42
**********************************************************************
1 items had failures:
   1 of   1 in main.foo
***Test Failed*** 1 failures.

PS: If move the decorator definition by even a line up, it shows that the line, >>> foo() incorrectly lives on line 10 and not line 7.

Why?

The "?" is printed simply because while doctest is able to find the example's lineno, it is unable to understand the test's lineno. I found this after printing out the line numbers in the _failure_header function in doctest.py.

CPython versions tested on:

3.11

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions