繁体   English   中英

捕获模块已捕获的 Python 异常

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM