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

Incorrect code collapse while prompting where the error is. #128327

Open
PC-Killer opened this issue Dec 29, 2024 · 3 comments
Open

Incorrect code collapse while prompting where the error is. #128327

PC-Killer opened this issue Dec 29, 2024 · 3 comments
Labels
stdlib Python modules in the Lib dir topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error

Comments

@PC-Killer
Copy link

PC-Killer commented Dec 29, 2024

Bug report

Bug description:

Read the following code:

# incorrect_collapse.py
def fib(number: int) -> int:
    assert number > 0
    if number == 1:
        return 1

    return fib(number - 1) + fib(number - 2)  # Notice here


print(fib(2))

There is a mistake in the code above, so if you try to run it, you will get the following traceback:

PC-Killer@ArchLinuxPC ~/p/bugs> python incorrect_collapse.py
Traceback (most recent call last):
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 9, in <module>
    print(fib(2))
          ~~~^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
                             ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 2, in fib
    assert number > 0
           ^^^^^^^^^^
AssertionError

Notice that the error happened while running the code fib(number - 2).
However, if the number is 5, the duplicate code will be automatically collapsed:

# incorrect_collapse.py
def fib(number: int) -> int:
    assert number > 0
    if number == 1:
        return 1

    return fib(number - 1) + fib(number - 2)  # Notice here


print(fib(5))
PC-Killer@ArchLinuxPC ~/p/bugs [1]> python incorrect_collapse.py
Traceback (most recent call last):
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 9, in <module>
    print(fib(5))
          ~~~^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  [Previous line repeated 1 more time]
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 2, in fib
    assert number > 0
           ^^^^^^^^^^
AssertionError

The error happened in fib(number - 2). However, in the traceback above, I can only suppose the error happened while running fib(number - 1), which increases the time to find where the real bug is.

CPython versions tested on:

3.13, 3.14

Operating systems tested on:

Linux

@PC-Killer PC-Killer added the type-bug An unexpected behavior, bug, or error label Dec 29, 2024
@picnixz
Copy link
Member

picnixz commented Dec 29, 2024

This the the expected behaviour. Because we are running fib(4) before fib(3), we'll see fib(4) raising. If you write fib(2) you execute fib(1) and fib(0). but it's fib(0) that is having an issue, not fib(1) (it immediately returns).

If you unroll the calls you have:

fib(2) -> fib(1) + fib(0)
fib(1) -> 1
fib(0) -> assertion error

So it's normal that fib(n-2) is the error location. For fib(5), if you unroll the call you have:

fib(5) -> fib(4) + fib(3)
----
fib(4) -> fib(3) + fib(2)
fib(3) -> fib(2) + fib(1) 
fib(2) -> fib(1) + fib(0)  # f(0) will error
----
fib(3) -> fib(2) + fib(1)
fib(2) -> fib(1) + fib(0)  # f(0) will error

So the error happened in the n-2 inner branch of the top n-1 branch. It would also fail on the n-2 inner branch of the top n-2 branch but this n-2 branch wouldn't be even executed yet.

This can be verified as follows:

def fib(number: int, s='') -> int:
    print("called with:", number, s)
    assert number > 0, (number, s)
    if number == 1: return 1
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")

fib(5)

This wil print:

called with: 5
called with: 4 l
called with: 3 ll
called with: 2 lll
called with: 1 llll
called with: 0 lllr
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    fib(5)
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 1 more time]
  File "test.py", line 3, in fib
    assert number > 0, (number, s)
           ^^^^^^^^^^
AssertionError: (0, 'lllr')

@picnixz picnixz added the pending The issue will be closed if no feedback is provided label Dec 29, 2024
@PC-Killer
Copy link
Author

Thanks for reading my issue! I am sorry that I may have not explained myself clearly.
Please notice your output above:

-- skip --
called with: 1 llll
called with: 0 lllr
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    fib(5)
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 1 more time]
  File "test.py", line 3, in fib
    assert number > 0, (number, s)
           ^^^^^^^^^^
AssertionError: (0, 'lllr')

That is to say, while calculating fib(2), the former, fib(number - 1) has been calculated successfully, and the mistake happened while calculating fib(number - 2), which refers to fib(0)
Therefore, in my opinion, the traceback should be like the following:

Traceback (most recent call last):
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 9, in <module>
    print(fib(5))
          ~~~^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
           ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
                             ~~~^^^^^^^^^^^^
  File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 2, in fib
    assert number > 0
           ^^^^^^^^^^
AssertionError

@picnixz
Copy link
Member

picnixz commented Dec 29, 2024

File "/home/PC-Killer/python_work/bugs/incorrect_collapse.py", line 6, in fib
    return fib(number - 1) + fib(number - 2)  # Notice here
                             ~~~^^^^^^^^^^^^

Ah I see what you mean. I think the issue is that we are considering the traceback to be identical because we haven't yet added the markers (^). I'm not on my dev session so it's a bit hard to investigate, but we should decide if the rendered lines are the same by also checking where the carrets would be rendered before hiding them.

For instance, fib(4) shows:

called with: 4
called with: 3 l
called with: 2 ll
called with: 1 lll
called with: 0 llr
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    fib(3)
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 5, in fib
    return fib(number - 1, s + 'l') + fib(number - 2, s + "r")
                                      ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test.py", line 3, in fib
    assert number > 0, (number, s)
           ^^^^^^^^^^
AssertionError: (0, 'llr')

cc @pablogsal

@picnixz picnixz added stdlib Python modules in the Lib dir topic-repl Related to the interactive shell and removed pending The issue will be closed if no feedback is provided labels Dec 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants