This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Compiler errors that happen before syntax errors are not reported first
Type: behavior Stage: resolved
Components: Parser Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: jfine2358, lys.nikolaou, pablogsal
Priority: normal Keywords:

Created on 2022-03-03 11:22 by jfine2358, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
funny_break_error.py jfine2358, 2022-03-03 11:22
funny_break_error_fix.py jfine2358, 2022-03-04 11:45
Messages (6)
msg414424 - (view) Author: Jonathan Fine (jfine2358) * Date: 2022-03-03 11:22
This arises from a request for help made by Nguyễn Ngọc Tiến to the visually impaired programmers lists, see https://www.freelists.org/post/program-l/python,48. Please keep this in mind.

Nguyễn asked for help with the syntax error created by
===
count = 0
while count < 1:
 count = count + 1
 print(count)
break
 else:
 print("no break")
===

When I saved this to a file and ran it I got:
===
$ python3.8 funny_break_error.py 
  File "funny_break_error.py", line 6
    else:
    ^
IndentationError: unexpected indent
===

However, remove the last two lines and you get the more helpful error
===
$ python3.8 funny_break_error.py 
  File "funny_break_error.py", line 5
    break
    ^
SyntaxError: 'break' outside loop
===

Python3.6 and 3.7 also behave as above.

Note. I've heard that blind Python programmers prefer a single space to denote indent. I think this is because they hear the leading spaces via a screen reader, rather than see the indent with their eyes.
msg414451 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-03-03 15:27
Unfortunately, we cannot do much here. The reason is that the parser allows break and continue outside loops as they count as statements. As these are associated with control flow, is the compiler the one that will show the Syntax warning once it tries to make sense of the abstract syntax tree that the parser generates.

The error you are getting happens because for the parser, the unindented else *is* a syntax error so it fails much sooner and prevents the compiler to complain about the break.

This means that in the presence of two syntax errors, one being a parser error and the other a compiler error, the parser will always be first, no matter if the other one appears before in the code.

Given this, I am afraid we need to close this issue as "won't fix" :(

Bing said that, if someone devises some easy way to do this without major changes everywhere, I am happy to reopen it
msg414518 - (view) Author: Jonathan Fine (jfine2358) * Date: 2022-03-04 11:45
Many thanks Pablo for the clear explanation. I'd prefer that the issue remain open, as there's an important user experience issue here. I suspect there are other similar examples of how the compiler error messages could be improved.

Here's a change that doesn't seem to be too hard, that could fix the problem at hand.

The IndentationError occurred at a known location in the input string. So as part of error reporting truncate the input string and try to compile that. In other words, make a good faith attempt to find an earlier error.

I've attached a funny_break_error_fix.py which is a first draft implementation of this idea. 

Here's the output:
===
$ python3 funny_break_error_fix.py funny_break_error.py
unexpected indent (funny_break_error.py, line 6)
Traceback (most recent call last):
  File "funny_break_error_fix.py", line 3, in compile_fix
    compile(source, filename, 'exec')
  File "funny_break_error.py", line 6
    else:
    ^
IndentationError: unexpected indent

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "funny_break_error_fix.py", line 18, in <module>
    compile_fix(src.read(), filename, 'exec')
  File "funny_break_error_fix.py", line 9, in compile_fix
    compile(new_source, filename, 'exec')
  File "funny_break_error.py", line 5
    break
    ^
SyntaxError: 'break' outside loop
===

And in this case we've got hold of the first error (at the cost of compiling part of the source file twice). Many thanks again for the clear explanation, which I found most helpful when formulating the above fix.
msg414521 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-03-04 12:28
Unfortunately that's not how the parser works. I insist, for the compiler to raise the propper error the parser needs to succeed first. That would require us to modify the input string in arbitrary ways (many times we don't know exactly what went wrong) and recompile an arbitrary number of times.

I'm very sorry, but I will leave this issue closed as "won't fix" as the complexity of this solution is too much for the given benefit.
msg414663 - (view) Author: Jonathan Fine (jfine2358) * Date: 2022-03-07 12:37
My main concern is that the door not be closed on improving the user experience relating to this behaviour of the compiler.

This issue was raised as a bug for the compiler (which is C-coded). I'd be very happy for this issue to be closed as 'not a bug' for the compiler, provided the door is left open for Python-coded improvements for the user experience. 

I suggest that the issue title be changed to: The two-pass compile(bad_src, ...) sometimes does not report first error in bad_src

These two changes to the details of closure would be sufficient to meet my concern. I hope they can be accepted.

By the way, I see these improvements being done as a third-party pure-Python module outside Python's Standard Library, at least until they've reached a wide measure of community acceptance.
msg414664 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-03-07 12:48
> My main concern is that the door not be closed on improving the user experience relating to this behaviour of the compiler.

Is not closed, if someone has a good idea they can reopen this issue (the issue is not deleted).

> By the way, I see these improvements being done as a third-party pure-Python module outside Python's Standard Library, at least until they've reached a wide measure of community acceptance.


You can reach to André Roberge, the author of "friendly" and "friendly-traceback" (https://github.com/friendly-traceback/friendly-traceback) which is a fantastic 3rd party package in these lines.
History
Date User Action Args
2022-04-11 14:59:56adminsetgithub: 91066
2022-03-07 12:48:52pablogsalsetresolution: wont fix -> not a bug
messages: + msg414664
title: Expect IndentationError, get SyntaxError: 'break' outside loop -> Compiler errors that happen before syntax errors are not reported first
2022-03-07 12:37:51jfine2358setmessages: + msg414663
2022-03-04 12:28:24pablogsalsetmessages: + msg414521
2022-03-04 11:45:18jfine2358setfiles: + funny_break_error_fix.py

messages: + msg414518
2022-03-03 15:27:54pablogsalsetstatus: open -> closed
resolution: wont fix
messages: + msg414451

stage: resolved
2022-03-03 11:22:08jfine2358create