Python中的异常行为\uuuu set\u name__

Python中的异常行为\uuuu set\u name__,python,python-3.x,exception,python-descriptors,Python,Python 3.x,Exception,Python Descriptors,我有一个子类,它使用Python3.6+\uuuuu set\u name\uuuuu来确保拥有的类已经注释了携带子类的字段的类型。如果没有,则会引发异常 但是,Python总是捕获任何引发的异常,并引发运行时错误 例如: class Child: def __set_name__(self, owner, name): raise Exception("OOPS!") class Owner(): child = Child() 结果: Traceback

我有一个子类,它使用Python3.6+
\uuuuu set\u name\uuuuu
来确保拥有的类已经注释了携带子类的字段的类型。如果没有,则会引发异常

但是,Python总是捕获任何引发的异常,并引发
运行时错误

例如:

class Child:
    def __set_name__(self, owner, name):
        raise Exception("OOPS!")

class Owner():
    child = Child()
结果:

Traceback (most recent call last):
  File "<stdin>", line 3, in __set_name__
Exception: OOPS!

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Error calling __set_name__ on 'Child' instance 'child' in 'Owner'
回溯(最近一次呼叫最后一次):
文件“”,第3行,名称为__
例外:哎呀!
上述异常是以下异常的直接原因:
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
RuntimeError:在“所有者”中的“Child”实例“Child”上调用\uuuuu set\u name\uuuuuu时出错
这很可能是预期的行为(找不到对
\uuuuu set\u name\uuuu
异常的特定引用),但也可能表明预期是
\uuuu set\u name\uuuu
从不发生异常

我看到的行为不是问题,只要在正确的条件下发生异常。然而,由于我不能确定引发的异常是否是我的代码引发的异常,所以测试起来很棘手


有没有更好的方法来引发一个适合测试的异常,或者确实有一个简单的方法来检查由
运行时错误包装的异常是否确实是我的代码引发的异常?

因此,既然您得到了整个“上面的异常是下面异常的直接原因”这意味着在
类型
(基本元类)中的某个地方,基本上有以下内容:

try:
    descr.__set_name__(A, 'attr')
except Exception as e:
    raise RuntimeError(msg) from e
也就是说,它正在使用
从原始异常引发新异常
,因此您应该能够使用
\uuuuu原因
属性反思原始异常是什么:

因此,请注意:

In [1]: class Child:
   ...:     def __set_name__(self, owner, name):
   ...:         raise Exception("OOPS!")
   ...: try:
   ...:     class Owner():
   ...:         child = Child()
   ...: except RuntimeError as e:
   ...:     err = e
   ...:

In [2]: err
Out[2]: RuntimeError("Error calling __set_name__ on 'Child' instance 'child' in 'Owner'")

In [3]: err.__cause__
Out[3]: Exception('OOPS!')
同样,我认为这些都没有文档记录,因此您可能依赖于实现细节


这将更详细地解释这一点。

您可以访问包装异常上的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
属性,以检查

try:
    class Child:
        def __set_name__(self, owner, name):
            raise Exception("OOPS!")

    class Owner():
        child = Child()

except RuntimeError as rte:
    assert rte.__cause__.args[0] == "OOPS!"  # or a more appropriate check

我真的认为这是对作为描述符协议一部分的
\uuuuu set\u name\uuuuuu
的滥用。。。可能有更好的方法来确保注释,比如使用静态分析工具,比如mypyNote,我认为这并没有被包装。基本上,我打赌有一个大的
尝试:。。。除了
类型中的异常e:
,如果类创建中的任何内容抛出错误,它只会引发此运行时错误。我找不到任何官方文档,这可能都是实现细节……您应该能够访问运行时错误的除了没有记录在案的例外情况不应该提出。。。我正在寻找一个纯Python的解决方案,所以在这个阶段没有选择采用mypy。