5

The code given to exec below will pass without compile errors, but will result in an run-time error at "error" statement:

globs = {}

exec('''
def main():
    print('Hello Python')
    error  # Makes run-time error
''', globs)

globs['main']()

The error message is:

    Traceback (most recent call last):

      File "C:\work\sandbox.py", line 11, in 
        globs['main']()
      File "<string>", line 4, in main
    NameError: name 'error' is not defined

The location information of only File "<string>", line 4, in main is not very useful, for example when trying the locate the origin of the code which can be from a file.

Note that the above is a simplified example to show the issue. In the actual program the code defines several functions that are executed at different locations in the main program.

Is there some way to provide the code from exec with another location than "<string>", so this other location is shown if an exception occurs in the exec code?

EquipDev
  • 5,573
  • 10
  • 37
  • 63
  • If someone can give me a use case for `exec(...)` in Python, I would appreciate it. – ElmoVanKielmo Mar 04 '15 at 13:53
  • 1
    I'm not sure the duplicate actually answers this question, which seems to be about passing something more useful than "" as source for the code executed by `exec`. – André Laszlo Mar 04 '15 at 13:56
  • 2
    I reopened because the duplicate question is not the same (it asks how to get the "line 4" in code). – interjay Mar 04 '15 at 13:57
  • @interjay (and AndreLaszlo comment): Thanks for reopening, since the duplicate handles the case where `exec` itself causes the exception, but this is not the case in this question, since the exception does not occur until later when a function in the `exec` code is called – EquipDev Mar 04 '15 at 14:00
  • Related question: [python - File "" traceback with line preview - Stack Overflow](https://stackoverflow.com/questions/47183305/file-string-traceback-with-line-preview). If the code does come from a physical *source file* then it helps, but otherwise not really. – user202729 May 20 '23 at 01:30
  • Does this answer your question? [How do I set the filename of a module in Python so that exceptions that occur in the module use that filename?](https://stackoverflow.com/questions/12977578/how-do-i-set-the-filename-of-a-module-in-python-so-that-exceptions-that-occur-in) – user202729 May 20 '23 at 01:33

2 Answers2

6

You can first compile your code and give it a filename argument:

code = compile('error', 'foo.py', 'exec')
exec(code)

Output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo.py", line 1, in <module>
NameError: name 'error' is not defined
André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • Thanks, that did it :-) Btw. is there some way to specify a line-number offset, for use if the compiled code does not start at line 1 in the source file ? – EquipDev Mar 04 '15 at 14:15
  • 1
    The only way I could come up with is quite an ugly hack: `code = compile(('\n' * 99) + 'error', 'foo.py', 'exec')`. That would give you the same error but on line 100 :) I tried setting the `co_firstlineno` property of the code but it's read-only just like `co_filename`. – André Laszlo Mar 04 '15 at 15:44
  • Not pretty, but I think it will do the job and is robust. Thanks :-D – EquipDev Mar 04 '15 at 15:54
0

Write the code you're execing to a file, and run it.

Or better still, accept code input from a file in the first place. This is potentially more secure and makes the code more easily auditable. It also makes it easier for the user to change it later, if that feature is desired.

You should avoid using exec for code you don't control - it's extremely dangerous. Unless you're writing procedurally generated code, there's no reason for using it.

loopbackbee
  • 21,962
  • 10
  • 62
  • 97
  • The code defines a number of functions that can be called later, and allows users to easily extend a main Python program. The code given to `exec` is no different from the main Python program; just gives a way to extend the program in a easy way, so I don't think this make the use of `exec` "dangerous". – EquipDev Mar 04 '15 at 14:03
  • Thanks for the update, and good point about not using `exec` to let in 3rd party uncontrolled code. – EquipDev Mar 04 '15 at 14:12
  • @EquipDev You're absolutely right. If you're absolutely sure that you're executing code provided by the user, `exec` is safe. The problem is not as much with `exec` as it is in getting code from the user; that's the part that's different from your main python program - the mechanism for obtaining the code. This is also why using files is a better idea. – loopbackbee Mar 04 '15 at 14:12
  • Another reason is to read the code from a file, and then preprocess the code; one type of preprocessing might even analyze the code for dangerous behavior, but a more common type of preprocessing would be macro expansion, another would be decompression. – Victoria Jan 16 '19 at 09:01