运行 `python -m unittest` 改变了带有覆盖的 `__name__` 的异常在回溯中打印的方式
Running `python -m unittest` changes the way exceptions with overriden `__name__` are printed in the traceback
我有一段动态创建 Exception
s 的代码。以这种方式创建的每个异常 class 都会被其 __name__
覆盖:
def exception_injector(name, parent, module_dict):
class product_exception(parent):
pass
product_exception.__name__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
当我经常使用它时,它可以很好地打印出所有内容:
>>> namespace = {"__name__": "some.module"}
>>> exception_injector("TestError", Exception, namespace)
>>> raise namespace["TestError"]("What's going on?")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
some.module.TestError: What's going on?
但是当我使用 unittest
模块时,原始的 __name__
被打印出来:
>>> import unittest
>>> class DemoTestCase(unittest.TestCase):
... def test_raise(self):
... namespace = {"__name__": "some.module"}
... exception_injector("TestError", Exception, namespace)
... namespace["TestError"]("What's going on?")
...
>>> unittest.main(defaultTest="DemoTestCase", argv=["demo"], exit=False)
E
======================================================================
ERROR: test_raise (__main__.DemoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 3, in test_raise
some.module.exception_injector.<locals>.product_exception: What's going on?
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
<unittest.main.TestProgram object at 0x1017c3eb8>
unittest
模块可以从异常对象的何处获取此原始信息?
单元测试使用 traceback
module 格式化异常。您可以通过执行相同的操作来重现您的输出:
>>> import traceback
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.exception_injector.<locals>.product_exception: What's going on?
正在打印的是对象 __module__
属性值 *,附加了 object.__qualname__
attribute(带有点分隔符),而不是 __module__
加上__name__
:
>>> namespace["TestError"].__qualname__
'exception_injector.<locals>.product_exception'
限定名称包括 full scope where the class was created(此处为函数名称,但也可以包括 class 名称)。
如果您的目标是向模块的全局命名空间添加例外,您可以将其设置为与 name
:
相同的值
>>> namespace["TestError"].__qualname__ = "TestError"
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.TestError: What's going on?
或在您的代码上下文中:
def exception_injector(name, parent, module_dict):
class product_exception(parent, details=args):
pass
product_exception.__name__ = name
product_exception.__qualname__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
* 如果模块名称是 __main__
或 builtins
.
,则回溯模块将忽略异常模块
我有一段动态创建 Exception
s 的代码。以这种方式创建的每个异常 class 都会被其 __name__
覆盖:
def exception_injector(name, parent, module_dict):
class product_exception(parent):
pass
product_exception.__name__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
当我经常使用它时,它可以很好地打印出所有内容:
>>> namespace = {"__name__": "some.module"}
>>> exception_injector("TestError", Exception, namespace)
>>> raise namespace["TestError"]("What's going on?")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
some.module.TestError: What's going on?
但是当我使用 unittest
模块时,原始的 __name__
被打印出来:
>>> import unittest
>>> class DemoTestCase(unittest.TestCase):
... def test_raise(self):
... namespace = {"__name__": "some.module"}
... exception_injector("TestError", Exception, namespace)
... namespace["TestError"]("What's going on?")
...
>>> unittest.main(defaultTest="DemoTestCase", argv=["demo"], exit=False)
E
======================================================================
ERROR: test_raise (__main__.DemoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 3, in test_raise
some.module.exception_injector.<locals>.product_exception: What's going on?
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
<unittest.main.TestProgram object at 0x1017c3eb8>
unittest
模块可以从异常对象的何处获取此原始信息?
单元测试使用 traceback
module 格式化异常。您可以通过执行相同的操作来重现您的输出:
>>> import traceback
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.exception_injector.<locals>.product_exception: What's going on?
正在打印的是对象 __module__
属性值 *,附加了 object.__qualname__
attribute(带有点分隔符),而不是 __module__
加上__name__
:
>>> namespace["TestError"].__qualname__
'exception_injector.<locals>.product_exception'
限定名称包括 full scope where the class was created(此处为函数名称,但也可以包括 class 名称)。
如果您的目标是向模块的全局命名空间添加例外,您可以将其设置为与 name
:
>>> namespace["TestError"].__qualname__ = "TestError"
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.TestError: What's going on?
或在您的代码上下文中:
def exception_injector(name, parent, module_dict):
class product_exception(parent, details=args):
pass
product_exception.__name__ = name
product_exception.__qualname__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
* 如果模块名称是 __main__
或 builtins
.