如何在Python中捕获错误的回溯信息以及源代码?

huangapple go评论142阅读模式
英文:

How to capture the traceback for an error in python along with source code?

问题

以下是翻译好的部分:

  1. 当我运行一个vscode笔记本单元格或包含以下内容的python文件时
  1. def foo():
  2. return 4/0 # 这将导致除零异常
  3. foo()
  1. 我会得到以下错误回溯它非常有意义并告诉我在哪一行以及哪一行的代码发生了错误
  1. ---------------------------------------------------------------------------
  2. ZeroDivisionError Traceback (most recent call last)
  3. Cell In[12], line 4
  4. 1 def foo():
  5. 2 return 4/0 # 这将导致除零异常
  6. ----> 4 foo()
  7. Cell In[12], line 2, in foo()
  8. 1 def foo():
  9. ----> 2 return 4/0
  10. ZeroDivisionError: division by zero
  1. 但是当我使用`exec`块运行程序时我无法看到源代码我该如何捕获它
  1. import traceback
  2. import sys
  3. code = """
  4. def foo():
  5. return 4/0 # 这将导致除零异常
  6. foo()
  7. """
  8. try:
  9. exec(code)
  10. except Exception as e:
  11. traceback.print_exc()
  1. 会得到以下输出
  1. Traceback (most recent call last):
  2. File "/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py", line 11, in <module>
  3. exec(code)
  4. File "<string>", line 4, in <module>
  5. File "<string>", line 2, in foo
  6. ZeroDivisionError: division by zero
英文:

When I run a vscode notebook cell or a python file with these contents:

  1. def foo():
  2. return 4/0 # This will cause a division by zero exception
  3. foo()

I get the following error traceback which is very meaningful and tells me at what line along with the line of code that errors:

  1. ---------------------------------------------------------------------------
  2. ZeroDivisionError Traceback (most recent call last)
  3. Cell In[12], line 4
  4. 1 def foo():
  5. 2 return 4/0 # This will cause a division by zero exception
  6. ----&gt; 4 foo()
  7. Cell In[12], line 2, in foo()
  8. 1 def foo():
  9. ----&gt; 2 return 4/0
  10. ZeroDivisionError: division by zero

However when I run the program using a exec block I am unable to see the source code. How do I capture this?

  1. import traceback
  2. import sys
  3. code = &quot;&quot;&quot;def foo():
  4. return 4/0 # This will cause a division by zero exception
  5. foo()
  6. &quot;&quot;&quot;
  7. try:
  8. exec(code)
  9. except Exception as e:
  10. traceback.print_exc()

gives:

  1. Traceback (most recent call last):
  2. File &quot;/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py&quot;, line 11, in &lt;module&gt;
  3. exec(code)
  4. File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
  5. File &quot;&lt;string&gt;&quot;, line 2, in foo
  6. ZeroDivisionError: division by zero

答案1

得分: 2

The traceback printing mechanism relies on being able to read the line from disk (using the linecache module).

For exec'd code, there is no disk (after all, that's why it's saying File "<string>", line 2).

Looking at what traceback is doing you can patch linecache.getline to do a special thing for <string>s:

  1. import traceback
  2. import linecache
  3. import unittest.mock
  4. code = """def foo():
  5. return 4/0 # This will cause a division by zero exception
  6. foo()
  7. """
  8. orig_getline = linecache.getline
  9. def new_getline(filename, lineno, *args, **kwargs):
  10. if filename == "<string>":
  11. return code.splitlines()[lineno - 1]
  12. return orig_getline(filename, lineno, *args, **kwargs)
  13. with unittest.mock.patch("linecache.getline", new_getline):
  14. try:
  15. exec(code)
  16. except Exception as e:
  17. traceback.print_exc()

et voilà:

  1. Traceback (most recent call last):
  2. File "F:\build\so-misc\so76878031.py", line 23, in <module>
  3. exec(code)
  4. File "<string>", line 4, in <module>
  5. foo()
  6. File "<string>", line 2, in foo
  7. return 4/0 # This will cause a division by zero exception
  8. ZeroDivisionError: division by zero
英文:

The traceback printing mechanism relies on being able to read the line from disk (using the linecache module).

For exec'd code, there is no disk (after all, that's why it's saying File &quot;&lt;string&gt;&quot;, line 2).

Looking at what traceback is doing you can patch linecache.getline to do a special thing for &lt;string&gt;s:

  1. import traceback
  2. import linecache
  3. import unittest.mock
  4. code = &quot;&quot;&quot;def foo():
  5. return 4/0 # This will cause a division by zero exception
  6. foo()
  7. &quot;&quot;&quot;
  8. orig_getline = linecache.getline
  9. def new_getline(filename, lineno, *args, **kwargs):
  10. if filename == &quot;&lt;string&gt;&quot;:
  11. return code.splitlines()[lineno - 1]
  12. return orig_getline(filename, lineno, *args, **kwargs)
  13. with unittest.mock.patch(&quot;linecache.getline&quot;, new_getline):
  14. try:
  15. exec(code)
  16. except Exception as e:
  17. traceback.print_exc()

et voilà:

  1. Traceback (most recent call last):
  2. File &quot;F:\build\so-misc\so76878031.py&quot;, line 23, in &lt;module&gt;
  3. exec(code)
  4. File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
  5. foo()
  6. File &quot;&lt;string&gt;&quot;, line 2, in foo
  7. return 4/0 # This will cause a division by zero exception
  8. ZeroDivisionError: division by zero

huangapple
  • 本文由 发表于 2023年8月11日 01:26:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76878031.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定