gpt4 book ai didi

带有模块名称的 Python 回溯

转载 作者:太空宇宙 更新时间:2023-11-03 11:07:43 27 4
gpt4 key购买 nike

Python 中的堆栈跟踪显示文件路径。有什么方法可以让它们显示完全限定的函数名称吗?

例子:

class Foo(object):
def bar(self):
raise Exception, "Some error."

def inner():
return Foo().bar()

def outer():
return inner()

我希望我的输出看起来像这样:

In __main__.Foo.bar ("scratchpad.py", line 3)
__main__.inner ("scratchpad.py", line 6)
__main__.outer ("scratchpad.py", line 9)
Exception: Some error.

如果它改变了什么,我使用的是 Python 2.7。


这是我目前所拥有的:

import sys

class Foo(object):
def bar(self):
raise Exception, "Dummy value."

def inner():
"Inner function..."
return Foo().bar()

def outer():
return inner()


try:
outer()
except Exception, error:
traceback = sys.exc_info()[2]
while traceback is not None:
frame = traceback.tb_frame
print 'Name', frame.f_globals['__name__']+'.'+frame.f_code.co_name
docs = frame.f_code.co_consts[0]
if docs and docs != -1: # docs can be None or -1.
print 'Docs "%s"' % docs
print 'Args', frame.f_code.co_argcount
print 'File "%s", line %d' % (frame.f_code.co_filename, frame.f_lineno)
print
traceback = traceback.tb_next

当我运行它时,它会打印

$ python pretty-stack.py
Name __main__.<module>
Args 0
File "pretty-stack.py", line 28

Name __main__.outer
Args 0
File "pretty-stack.py", line 14

Name __main__.inner
Docs "Inner function..."
Args 0
File "pretty-stack.py", line 11

Name __main__.bar
Args 1
File "pretty-stack.py", line 7

快完成了,但我在处理重要用例时遇到了麻烦。例如,我无法为 Foo.bar() 获取类名 Foo

最佳答案

没有直接的方法从回溯中访问符号,因为只有“代码对象”是可访问的,并且,the Python docs on code objects说:

Unlike function objects, code objects are immutable and contain no references (directly or indirectly) to mutable objects.

看来要找回回溯中涉及到的模块、函数、类,还需要搜索一下。


我有一个似乎有效的实验版本。此实现基于遍历代码对象引用的模块以查找引用相关代码对象的函数或方法。

from collections import namedtuple
import inspect
import sys

from nested.external import Foo

def inner(a, b='qux'):
"Inner function..."
return Foo().bar()

def outer(a, *args, **kwds):
return inner(a)

def resolve_signature(function):
"""Get a formatted string that looks like the function's signature."""
prgs, vrgs, kwds, defs = inspect.getargspec(function)
arguments = []
if defs:
for name in prgs[:len(defs)-1]:
arguments.append(name)
for i,name in enumerate(prgs[len(defs)-1]):
arguments.append('%s=%r'%(name,defs[i]))
else:
arguments.extend(prgs)
if vrgs:
arguments.append('*'+vrgs)
if kwds:
arguments.append('**'+kwds)
return '('+', '.join(arguments)+')'


def resolve_scope(module_name, code):
"""Resolve the scope name for a code object provided its module name."""
# Resolve module.
module = sys.modules.get(module_name, None)
if not module:
return '<hidden-module>' + '.' + code.co_name + '(?)'

# Check module's functions.
symbols = inspect.getmembers(module, inspect.isfunction)
for symbol_name,symbol_info in symbols:
if symbol_info.func_code is code:
scope = module_name + '.'
return scope + code.co_name + resolve_signature(symbol_info)

# Check module's classes.
symbols = inspect.getmembers(module, inspect.isclass)
for symbol_name,symbol_info in symbols:
# Check class' methods.
members = inspect.getmembers(symbol_info, inspect.ismethod)
for method_name,method_info in members:
if method_info.__func__.func_code is code:
scope = module_name + '.' + symbol_name + '.'
return scope + code.co_name + resolve_signature(method_info)

# Default to the thing's name. This usually happens
# when resolving the stack frame for module-level code.
return code.co_name

Frame = namedtuple('Frame', ['call', 'file', 'line', 'help'])

def pretty_stack(traceback=None):
"""Returns a simple stack frame."""
frames = []
if traceback is None:
traceback = sys.exc_info()[2]
while traceback is not None:
frame = traceback.tb_frame
call = resolve_scope(frame.f_globals['__name__'], frame.f_code)
path = frame.f_code.co_filename.replace('\\', '/')
line = frame.f_lineno
docs = frame.f_code.co_consts[0]
if docs == -1:
docs = None
frames.append(Frame(call, path, line, docs))
traceback = traceback.tb_next
return frames

try:
outer(1)
except Exception, error:
frames = pretty_stack()
for frame in frames:
print frame.call
print ' -> "%s", line %d.' % (frame.file, frame.line)
if frame.help:
print frame.help
print

当我运行它时,我得到类似的东西:

$ python pretty-stack.py
<module>
-> "pretty-stack.py", line 84.

__main__.outer(a, *args, **kwds)
-> "pretty-stack.py", line 14.

__main__.inner(a='qux')
-> "pretty-stack.py", line 11.
Inner function...

nested.external.Foo.bar(self)
-> "C:/Users/acaron/Desktop/nested/external.py", line 3.

请注意,这甚至会打印函数签名和文档字符串,这可能有助于调试。

在存在描述符和诸如此类的情况下,它可能无法按预期工作,我还没有尝试过非常复杂的用例。如果您发现它不起作用的情况,请告诉我,我会尝试修补它。

关于带有模块名称的 Python 回溯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14817788/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com