Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested functions can't be tested by doctest #10837

Open
nkstonks opened this issue Oct 23, 2023 · 7 comments
Open

Nested functions can't be tested by doctest #10837

nkstonks opened this issue Oct 23, 2023 · 7 comments
Labels
enhancement This PR modified some existing files

Comments

@nkstonks
Copy link
Contributor

Feature description

#9943

So I was adding doctests to a nested function in fibonacci.py, however doctest doesn't seem to be testing that function.

The function in this case is fib_recursive_term(), that's nested inside fib_recursive, as seen below:
image
Note: the 5 doctests for fib_recursive_term() is what I added.

If I run the doctests, I get this output below.
As per the output below, 5 tests for fib_recursive() runs, but the 5 tests for fib_recursive_term() doesn't.
image

So I want to propose taking the fib_recursive_term() function out of the fib_recursive() function and have it defined above it, so doctests actually goes through it. Would there be any issues there?

@nkstonks nkstonks added the enhancement This PR modified some existing files label Oct 23, 2023
@nkstonks nkstonks reopened this Oct 23, 2023
@nkstonks
Copy link
Contributor Author

misclicked and accidentally closed the issue, sorry...

@AasheeshLikePanner
Copy link
Contributor

AasheeshLikePanner commented Oct 23, 2023

Why not just write the code just Like this? It is difficult in photo to know what is the issue and unable to copy code.

@nkstonks
Copy link
Contributor Author

nkstonks commented Oct 23, 2023

Oh yeah my bad, I forgot that was a thing

What I wanted to show with those screenshots was just that I really just that there is indeed doctests for fib_recursive_term (first screenshot) but when I run the doctests it doesn’t say that the function as tested (second screenshot)

Below is the relavant part of the code, if you want the whole file then here’s the link to it: https://github.com/nkstonks/Python/blob/master/maths/fibonacci.py

def fib_recursive(n: int) -> list[int]:
    """
    Calculates the first n (0-indexed) Fibonacci numbers using recursion
    >>> fib_iterative(0)
    [0]
    >>> fib_iterative(1)
    [0, 1]
    >>> fib_iterative(5)
    [0, 1, 1, 2, 3, 5]
    >>> fib_iterative(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    >>> fib_iterative(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """

    def fib_recursive_term(i: int) -> int:
        """
        Calculates the i-th (0-indexed) Fibonacci number using recursion
        >>> fib_recursive_term(0)
        0
        >>> fib_recursive_term(1)
        1
        >>> fib_recursive_term(5)
        5
        >>> fib_recursive_term(10)
        55
        >>> fib_recursive_term(-1)
        Traceback (most recent call last):
            ...
        Exception: n is negative
        """
        if i < 0:
            raise Exception("n is negative")
        if i < 2:
            return i
        return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

    if n < 0:
        raise Exception("n is negative")
    return [fib_recursive_term(i) for i in range(n + 1)]

@AasheeshLikePanner
Copy link
Contributor

AasheeshLikePanner commented Oct 24, 2023

I don't know why but When I run the code. The error doesn't come in my computer. I am using the online python compiler (Interpreter)

@nkstonks
Copy link
Contributor Author

nkstonks commented Oct 24, 2023

Yeah the program runs just fine, it's just that if you look at the output of it, towards the end of it it says this:

2 items had no tests:
    __main__
    __main__.time_func
5 items passed all tests:
   6 tests in __main__.fib_binet
   5 tests in __main__.fib_iterative
   5 tests in __main__.fib_memoization
   5 tests in __main__.fib_recursive
   5 tests in __main__.fib_recursive_cached
26 tests in 7 items.
26 passed and 0 failed.
Test passed.

The thing with this is that it's not testing the tests in the fib_recursive_term function, as it doesn't mention that function in the output.

But if I take the fib_recursive_term function outside of the fib_recursive function, something like this:

def fib_recursive_term(i: int) -> int:
        """
        Calculates the i-th (0-indexed) Fibonacci number using recursion
        >>> fib_recursive_term(0)
        0
        >>> fib_recursive_term(1)
        1
        >>> fib_recursive_term(5)
        5
        >>> fib_recursive_term(10)
        55
        >>> fib_recursive_term(-1)
        Traceback (most recent call last):
            ...
        Exception: n is negative
        """
        if i < 0:
            raise Exception("n is negative")
        if i < 2:
            return i
        return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

def fib_recursive(n: int) -> list[int]:
    """
    Calculates the first n (0-indexed) Fibonacci numbers using recursion
    >>> fib_iterative(0)
    [0]
    >>> fib_iterative(1)
    [0, 1]
    >>> fib_iterative(5)
    [0, 1, 1, 2, 3, 5]
    >>> fib_iterative(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    >>> fib_iterative(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """

    if n < 0:
        raise Exception("n is negative")
    return [fib_recursive_term(i) for i in range(n + 1)]

notice how the fib_recursive_term function is above the fib_recursive function now.

If I run this, the program runs fine and the fib_recursive_term function gets tested as well. (relavant output below)

2 items had no tests:
    __main__
    __main__.time_func
6 items passed all tests:
   6 tests in __main__.fib_binet
   5 tests in __main__.fib_iterative
   5 tests in __main__.fib_memoization
   5 tests in __main__.fib_recursive
   5 tests in __main__.fib_recursive_cached
   5 tests in __main__.fib_recursive_term
31 tests in 8 items.
31 passed and 0 failed.
Test passed.

So that's why I'm proposing to take the fib_recursive_term function out of the fib_recursive function and have it as a global function instead of a nested (local) function.

@Khany123

This comment was marked as spam.

@MilindSaini
Copy link

MilindSaini commented Jan 1, 2024

def fib_recursive(n: int) -> list[int]:
"""
Calculates the first n (0-indexed) Fibonacci numbers using recursion
>>> fib_iterative(0)
[0]
>>> fib_iterative(1)
[0, 1]
>>> fib_iterative(5)
[0, 1, 1, 2, 3, 5]
>>> fib_iterative(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib_iterative(-1)
Traceback (most recent call last):
...
Exception: n is negative
"""

def fib_recursive_term(i: int) -> int:
    """
    Calculates the i-th (0-indexed) Fibonacci number using recursion
    >>> fib_recursive_term(0)
    0
    >>> fib_recursive_term(1)
    1
    >>> fib_recursive_term(5)
    5
    >>> fib_recursive_term(10)
    55
    >>> fib_recursive_term(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """
    if i < 0:
        raise Exception("n is negative")
    if i < 2:
        return i
    return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

if n < 0:
    raise Exception("n is negative")
memo = [0] * (n + 1)
for i in range(2, n + 1):
    memo[i] = fib_recursive_term(i)
return memo

This corrected code properly implements memoization and stores the computed Fibonacci numbers in the memo list. It also eliminates the redundant computations in the original code, which makes it more efficient.

Hope this is the right way I am understanding your problem

MannCode added a commit to MannCode/Python that referenced this issue Feb 25, 2024
…cursive() for proper doctest coverage and improved code organization.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This PR modified some existing files
Projects
None yet
Development

No branches or pull requests

4 participants