2

I have a few lines of code that I need to execute via exec() and I would like to know which line is rising ZeroDivisionError.

Here an example:

code = \
'''
a = 9
b = 0
c = a/b
print(c)
'''
>>>exec(code)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-3-00bada8e7a44> in <module>()
      5 print(c)
      6 '''
----> 7 exec(code)

<string> in <module>()

ZeroDivisionError: division by zero

This is fine, but I would like to have c = a/b instead of exec(code) as argument of the exception as it occurs for other types of error:

code = \
'''
a = 9
b = 0
c === b
print(c)
'''
>>>exec(code)
  File "<string>", line 4
    c === b
        ^
SyntaxError: invalid syntax

In this case, SyntaxError is pointing directly to the line responsible for the error.

Why this difference? How can I get ZeroDivisionError pointed correctly?

UPDATE

I have tried the "compile() solution" suggested by Schore but it did not work as expected in my case:

code = \
'''
a = 9
b = 0
c = a/b
print(c)
'''
z = compile(code, "", "exec")
>>>exec(z)
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-8-857f94e79b67> in <module>()
      6 '''
      7 z = compile(code, "", "exec")
----> 8 exec(z)

? in <module>()

ZeroDivisionError: division by zero 
alec_djinn
  • 10,104
  • 8
  • 46
  • 71
  • I assume that you fully understand that `exec` (and `eval`) can be a [security risk](http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html), and that you have some way to prevent dangerous code from being `exec`ed... – PM 2Ring May 04 '16 at 14:22
  • Yes I know, I do have security check on the code and up to now it is only for code snippets I have written so it should be fine. – alec_djinn May 04 '16 at 14:25

2 Answers2

2

The reason is that the zero division error is a runtime error and the === is a 'compiler' kind of error (well, for Python it is found when the === is being converted into computer instructions, it has not really a compiler).

What you can do to get the proper line of the error is to split the code in separate lines and execute them one by one (with a loop), and printing the line which causes the exception.

Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119
  • 1
    I have thought about such a solution. I wanted to check if a better way is possible since I don't need to split the code into lines but for this very special case. Of course, if there is no other option I will do so. – alec_djinn May 04 '16 at 14:14
  • 1
    FWIW, although the standard CPython interpreter doesn't compile the Python source code to the machine code of your CPU it _does_ compile it into Python bytecode, which is effectively the machine code of a virtual Python machine. And it does have a `compile` function that can be used to explicitly compile code that you wish to pass to `exec`. See http://stackoverflow.com/questions/2220699/whats-the-difference-between-eval-exec-and-compile-in-python for some interesting info. – PM 2Ring May 04 '16 at 14:17
1

You could use compile:

>>> code = \
... '''
... a = 9
... b = 0
... c = a/b
... print(c)
... '''
>>> c = compile(code, "", "exec")
>>> exec(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "", line 4, in <module>

ZeroDivisionError: integer division or modulo by zero

That way you get the line number without splitting your code.

Schore
  • 885
  • 6
  • 16
  • Might be that this behavior is specific to your python environment. You should try Michel Keijzers answer, as his approach will work anywhere. Splitting your code and executing it line by line is not that ugly... – Schore May 04 '16 at 15:06
  • I'll wait until tomorrow then I will go for that if nothing else is available. I was thinking about refactoring the ZeroDivisionError class or make a specific one to handle this kind of cases. But I have no will to do it right now... – alec_djinn May 04 '16 at 15:12