如果永远不会引发该对象,是否可以收集创建异常对象的文件和行号?
示例:
def compute_score_for_test(test):
# Exceptions can be added to a test explicitly.
if test_is_unscorable(test):
test.add_error(UnscorableTestError('...'))
...
# During certain operations, caught exceptions also get added to a test.
try:
...
except Exception as e:
test.add_error(e)
... much later ...
for test in test_set:
for error in test.errors:
# Using print as a contrived example; we actually store these values in a database.
print '[%s] %s (%s:%d)' % (
error.__class__.__name__,
error.message,
error.file_name, # <- ...somehow
error.line_number, #
)
如果没有别的办法,可以选择将代码添加到test.add_error()
。
答案 0 :(得分:0)
您可以使用inspect
模块获取当前行,如下所示:
import inspect
def lineno():
return inspect.currentframe().f_back.f_lineno
def filename():
return inspect.currentframe().f_back.f_code.co_filename
您可以将这些信息存储在您的错误对象中(顺便说一句,不必是Exception
,并且很可能是任何其他有意义的类型,因为您不会{{1} }它)。
如果您对raise
函数感到好奇,lineno()
给出当前帧,inspect.currentframe()
给出父帧(即,函数被调用的行)和f_back
显然给出了行号。
f_lineno
功能以类似的方式运行。查看filename()
模块文档,了解当前框架可以获得的所有内容。它实际上非常完整。
在你的情况下,我会选择类似的东西:
inspect
和
test.add_error(YourError(frame_info=get_frame_info())
答案 1 :(得分:0)
This SO answer显示了如何获取当前文件和行号,例如:
import sys
def LINE( back = 0 ):
return sys._getframe( back + 1 ).f_lineno
def FILE( back = 0 ):
def foo():
print "this is line number", LINE(), " of file ", FILE()
您可以将该信息放入错误对象中。
答案 2 :(得分:0)
另一种方法是使用Python日志记录模块(为这种东西制作),并使用其格式化选项。 https://docs.python.org/2/library/logging.html#logrecord-attributes
一个例子:
import logging
message_format = '[%(asctime)s] [%(levelname)s] [%(pathname)s:%(funcName)s:%(lineno)s]\n%(message)s\n'
logging.basicConfig(format=message_format)
logger = logging.getLogger('test')
logger.error('Testing 1, 2, 3...')
答案 3 :(得分:0)
这是我们最终采用的解决方案的简化版本。它处理捕获的异常以及将异常对象直接传递给add_error()
。
from inspect import getsourcefile, getfile, getlineno, stack
from sys import exc_info
...
def add_error(self, error):
"""
Adds an error to the test.
:type error: Exception
"""
error.file = None
error.line = None
# Try to guess the file and line number where the error occurred.
exc_tb = exc_info()[2]
try:
if exc_tb:
# If we have traceback info (i.e., from a caught exception), add it to the error.
error.file = (getsourcefile(exc_tb.tb_frame) or getfile(exc_tb.tb_frame))
error.line = getlineno(exc_tb.tb_frame)
else:
#
# Otherwise, find the caller in the current stack.
#
# stack()[1] = (<frame object>, filename, line_number, caller, context_line, pos_in_context_line)
# Note that we pass 0 to `stack()` so that it doesn't return any context lines,
# since we're not interested in that.
#
(error.file, error.line) = stack(0)[1][1:3]
except Exception as e:
# Well, we tried.
error.file = '(unable to determine due to %s %r)' % (e.__class__.__name__, e.message,)
finally:
#
# Very important to make sure `exc_tb` gets deleted to prevent a circular reference. Although Python's GC
# is smart enough to catch this and free the memory anyway, it's better not to create the circular
# reference in the first place.
#
# :see: https://docs.python.org/2/library/sys.html#sys.exc_info
#
del exc_tb
self.errors.append(error)