首页 > 解决方案 > CalledProcessError 使用 eventlet 越过 try 块

问题描述

我将 eventlet 用于绿色线程(特别是 wsgi 服务器)。为了轻松将此功能添加到现有代码库,我使用了 eventlet 的 monkey_patch 功能。

因此,我的文件的最顶部是这样的:

import eventlet
eventlet.monkey_patch()

我现在有一个更远的功能:

def ping(host: str) -> bool:
    try:
        ret = subprocess.check_output(["ping", "-c", "4", host], stderr=subprocess.DEVNULL).decode("utf-8")
        for line in ret.splitlines()[1:-3]:
            if host in line:
                return True
        return False
    except subprocess.CalledProcessError:
        return False

如果目标不可达,这个函数的行为让我有点困惑。如果未启用 monkey_patch,则返回False,正如我所料。但是,如果他们的 monkey_patch 已经到位,它会引发一个CalledProcessError.

我不明白这是怎么可能的——应该立即抓住它。这里发生了什么?

编辑 1:这是一个示例解释器会话:

>>> ping("192.168.0.233")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 8, in ping
    ret = subprocess.check_output(["ping", "-c", "4", host], stderr=subprocess.DEVNULL).decode("utf-8")
  File "/usr/lib/python3.6/subprocess.py", line 336, in check_output
    **kwargs).stdout
  File "/usr/lib/python3.6/subprocess.py", line 418, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['ping', '-c', '4', '192.168.0.233']' returned non-zero exit status 1.

编辑2:事实证明,如果我用except Exception甚至是一个bare捕获异常except,异常就会被很好地捕获。我想我会使用它,直到找到更合适的解决方案。然而,我仍然对这种行为感到目瞪口呆。

标签: pythonexceptioneventlet

解决方案


问题是 stdlib 和绿色补丁模块中具有相同名称的两个不同的异常类对象。在代码中它们看起来相同,但try/except它们是不同的类型。

抱歉,目前没有稳定的解决方案。欢迎打补丁!

解决方法:eventlet.monkey_patch()在执行任何其他代码之前调用。

在此处订阅有关此问题的新闻:https ://github.com/eventlet/eventlet/issues/413

根本原因是猴子补丁创建了一个新模块,将已知名称“复制”到其中,同时替换绿色模块的链接并将该模块放在 stdlib 名称下的sys.modules. (与就地修改 stdlib 模块相反,因为 Python C-API 限制,这是不可能的)


推荐阅读