Я использую eventlet для зеленых потоков (в частности, сервер wsgi). Чтобы легко добавить эту функциональность в существующую базу кода, я использовал функциональные возможности eventkey 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
или даже голого, except
, то поймается отлично. Я полагаю, что буду использовать это, пока не найдется более подходящее решение. Однако я все еще ошеломлен этим поведением.
Проблема состоит в двух различных объектах класса исключения с тем же именем в stdlib и в зеленых исправленных модулях. В коде они выглядят одинаково, но для try/except
они разные.
К сожалению, нет стабильного решения прямо сейчас. Патчи приветствуются!
Обход eventlet.monkey_patch()
: вызовите eventlet.monkey_patch()
перед любым другим выполнением кода.
Подпишитесь на новости по этому вопросу здесь: https://github.com/eventlet/eventlet/issues/413
Коренной причиной является то, что исправление обезьяны создает новый модуль, "копирует" известные им имена, заменяя ссылки на зеленые модули и помещает этот модуль под именем sys.modules
в sys.modules
. (В отличие от модификации модуля stdlib на месте, что невозможно, поскольку ограничения C-API Python)
import eventlet
и eventlet.monkey_path()
. Как я мог сделать monkey_patch раньше?