Possible faults in try-except

Hi coders,

Usually, whenever you use a try-except block in your code, the common assumption is that your can type whatever the flip you want in the try block, point out the error raised by the incorrect line of code in the except block, then get just the except block to execute.

Well, this DOES work for almost any error in Python…almost any.

Apparently, if you make a SyntaxError in the try block and point out SyntaxError in the except block, you still get a SyntaxError.

I propose that this is changed by 3.15. It just feels kinda irritating to see the error every time.

Thank you.

Contrary to common belief, Python (an “interpreted” language) does have a “compile time”, in which it reads the source and transforms it into bytecode. The bytecode is then executed at “run time”.

“Compile time” involves tokenizing the code and building an abstract syntax tree, so if there is a syntax error in your code, it is impossible to catch, since error handling occurs at “run time”.

Oh, I never knew that. Thank you so much!

The only case where you can catch SyntaxError at run time is when calling the exec() or eval() builtins, which run code dynamically.

Well even in that case, apparently it doesn’t work??

Unfortunately that won’t work, because syntax errors come from actually figuring out where that except block even is. For example:

try:
    print("""This is a string.
This is more of the string.
          The string should end here, right?")
except:
    print("Are we still in the string or can we catch that error?")

How would this be parsed? Could you find that except clause?

It does work.

>>> import traceback
>>> try:
...     exec('this causes a SyntaxError')
... except SyntaxError as se:
...     traceback.print_exception(se)
...     print('still here!')
...
Traceback (most recent call last):
  File "<python-input-1>", line 2, in <module>
    exec('this causes a SyntaxError')
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1
    this causes a SyntaxError
         ^^^^^^
SyntaxError: invalid syntax
still here!

Note the “still here!” line in the output, indicating we are in the except block. traceback.print_exception() writes the output to the console as if the exception was not caught.

no i meant exec(whatever you wanna type, WITHOUT quotes)

True. I understand that you never closed the quotes, and I love it.

That’s still an error outside the exec block.

what?

and which error is it?

Moving to general help as this ultimately is a question about how and when Python parses code, rather than something that could or will change in Python.

2 Likes

The argument to a function call (even exec) has to be a value. The compiler will generate code to create that value, then some code to call the function with that value as an argument.

The stuff between the brackets in exec(whatever you wanna type) doesn’t specify a value: it can’t be compiled. So it is a syntax error, and it occurs during the compilation of your main code.

In this case, the argument to exec ought to be a value that is a string, but you could call it with something else (in which case exec would complain) but your program to try that has to be compiled.

That is the thing! Isn’t the try block supposed to pass it to the except block if the try block is faulty? If the logic is wrong, I take my words back.

Have you tried running your script with Ruby or Perl or PHP? Would you be surprised if they didn’t run your script at all and instead just told you it’s not a valid script? The same thing happens here. It’s not valid Python code, so Python doesn’t even try running it at all.

I don’t learn Ruby or Perl or PHP. I hardly learned even JavaScript and C++ and HTML.

In general yes but the issue here is that if the syntax is incorrect it’s not in general possible for python to even determine that there is an except block, even less where it starts and what exception it should accept.

In your case above the error may be simple enough with the indentation and block-structure intact enough that it could be feasible to guess what you meant but look at the example by @Rosuav where it can’t even know if there is an except block or it’s a string it shouldn’t try to execute.

When passed as string to exec there is a clear delineation between what is the code we’re trying to evaluate and what is the try/except block and it’s possible to catch it.

The other place you can also catch it is when importing

try:
    import faulty_module
except SyntaxError:
    print("Something was wrong in that module")

And exec is a regular function, though implemented in C. It is not a statement. It cannot take a block of code as argument.

You’re thinking about what happens when the code runs. What you’re missing (really I’m just repeating others now) is that it never runs. Python reads it, tries to make sense of it, and can’t. Then it does its best to tell you about that.

If you put code in the try: that looks ok, but goes wrong when it runs, then you visit the except:. But this never gets to “looks ok”.

If you put “whatever you wanna type” in quotes, Python looks at it as a valid string, and exec is a name it will assume is a function, and so it is able to compile and run it. Your program only goes wrong when exec reads the string and the string turns out not to contain valid code. Then you will visit the except:.