[英]Catch a Python exception that a module already caught
我正在使用requests
Python 模块通过 SOCKS4 代理连接到网站。 在尝试连接到网站时,该程序甚至无法连接到 SOCKS4。 因此, PySocks模块抛出一个TimeoutError
异常,该异常被捕获并作为ProxyConnectionError
异常重新抛出。
如果这就是故事的结尾,我本可以直接捕获ProxyConnectionError
。 但是,底层urllib3
模块会捕获异常并重新引发NewConnectionError
。 你可以在官方源代码中看到这一点。
这是我从我的程序中得到的最终回溯(为简洁起见删掉了很多行):
Traceback (most recent call last):
TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
socks.ProxyConnectionError: Error connecting to SOCKS4 proxy ...
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
urllib3.exceptions.NewConnectionError: <urllib3.contrib.socks.SOCKSHTTPSConnection object at 0x0000025DA70CCDC0>: Failed to establish a new connection: ...
During handling of the above exception, another exception occurred:
... (eventually raises requests.exceptions.ConnectionError, then terminates the program)
我的目标是捕获所有 PySocks 错误(例如本示例中引发的ProxyConnectionError
),这可以通过捕获基本异常 class socks.ProxyError
来完成。
由于requests
库是下载的模块,我没有编辑底层代码的自由(如果我直接编辑源代码,那么如果其他人下载我的代码并安装 requests 库,这些更改将不会更新皮)。
有什么方法可以捕获已经在另一个模块中捕获的错误吗?
在做了一些挖掘之后,我发现PEP 负责添加__context__
,这是异常对象的一个属性,它允许隐式链接异常。
这意味着对于每个异常,都有一个__context__
属性指向先前捕获的异常。 使用一点节点迭代,我们可以到达这条链的底部,它包含一个None
(如果它是第一个抛出的异常)。
将所有这些放在一起作为代码,我写了一个 function ,它使用sys.exc_info()
获取当前抛出的异常,然后迭代直到它命中None
。 如果它发现先前抛出的异常是我们要捕获的异常的子类,则它返回True
:
def contains_exception(target_exc: Type[BaseException]) -> bool:
# Extract current exception
exception_obj: Type[BaseException] = sys.exc_info()[1]
# The final exception will be None
while exception_obj:
if issubclass(exception_obj.__class__, target_exc):
return True
# Iterate to next exception in the "During handling" chain
exception_obj: Optional[BaseException] = exception_obj.__context__
# Target exception wasn't found
return False
这是我在代码中使用它的方式:
try:
...
except BaseException:
if contains_exception(socks.ProxyError):
# We caught the ProxyConnectionError
...
else:
# Send the error back up, it's not relevant to the proxy
raise
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.