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

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

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

问题

以下是翻译好的部分:

当我运行一个vscode笔记本单元格或包含以下内容的python文件时
def foo():
    return 4/0  # 这将导致除零异常

foo()
我会得到以下错误回溯它非常有意义并告诉我在哪一行以及哪一行的代码发生了错误
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[12], line 4
      1 def foo():
      2     return 4/0  # 这将导致除零异常
----> 4 foo()

Cell In[12], line 2, in foo()
      1 def foo():
----> 2     return 4/0

ZeroDivisionError: division by zero
但是当我使用`exec`块运行程序时我无法看到源代码我该如何捕获它
import traceback
import sys

code = """
def foo():
    return 4/0  # 这将导致除零异常

foo()
"""

try:
    exec(code)
except Exception as e:
    traceback.print_exc() 
会得到以下输出
Traceback (most recent call last):
  File "/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py", line 11, in <module>
    exec(code)
  File "<string>", line 4, in <module>
  File "<string>", line 2, in foo
ZeroDivisionError: division by zero
英文:

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

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

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:

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

Cell In[12], line 2, in foo()
      1 def foo():
----&gt; 2     return 4/0

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?

import traceback
import sys

code = &quot;&quot;&quot;def foo():
    return 4/0  # This will cause a division by zero exception

foo()
&quot;&quot;&quot;

try:
    exec(code)
except Exception as e:
    traceback.print_exc() 

gives:

Traceback (most recent call last):
  File &quot;/var/folders/fd/f7mj1ws56pq6xvyzj4zv1r_m0000gn/T/ipykernel_39670/712868849.py&quot;, line 11, in &lt;module&gt;
    exec(code)
  File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
  File &quot;&lt;string&gt;&quot;, line 2, in foo
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:

import traceback
import linecache
import unittest.mock

code = """def foo():
    return 4/0  # This will cause a division by zero exception

foo()
"""

orig_getline = linecache.getline

def new_getline(filename, lineno, *args, **kwargs):
    if filename == "<string>":
        return code.splitlines()[lineno - 1]
    return orig_getline(filename, lineno, *args, **kwargs)

with unittest.mock.patch("linecache.getline", new_getline):
    try:
        exec(code)
    except Exception as e:
        traceback.print_exc()

et voilà:

Traceback (most recent call last):
  File "F:\build\so-misc\so76878031.py", line 23, in <module>
    exec(code)
  File "<string>", line 4, in <module>
    foo()
  File "<string>", line 2, in foo
    return 4/0  # This will cause a division by zero exception
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:

import traceback
import linecache
import unittest.mock

code = &quot;&quot;&quot;def foo():
    return 4/0  # This will cause a division by zero exception

foo()
&quot;&quot;&quot;

orig_getline = linecache.getline


def new_getline(filename, lineno, *args, **kwargs):
    if filename == &quot;&lt;string&gt;&quot;:
        return code.splitlines()[lineno - 1]
    return orig_getline(filename, lineno, *args, **kwargs)


with unittest.mock.patch(&quot;linecache.getline&quot;, new_getline):
    try:
        exec(code)
    except Exception as e:
        traceback.print_exc()

et voilà:

Traceback (most recent call last):
  File &quot;F:\build\so-misc\so76878031.py&quot;, line 23, in &lt;module&gt;
    exec(code)
  File &quot;&lt;string&gt;&quot;, line 4, in &lt;module&gt;
    foo()
  File &quot;&lt;string&gt;&quot;, line 2, in foo
    return 4/0  # This will cause a division by zero exception
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:

确定