Есть ли способ предотвратить перехват исключения SystemExit, вызванного из sys.exit()?
-
05-07-2019 - |
Вопрос
В документах говорится, что вызов sys.exit() вызывает исключение SystemExit, которое может быть перехвачено на внешних уровнях.У меня есть ситуация, в которой я хочу окончательно и бесспорно выйти из тестового примера, однако модуль unittest перехватывает SystemExit и предотвращает выход.Обычно это здорово, но конкретная ситуация, с которой я пытаюсь справиться, заключается в том, что наша тестовая платформа обнаружила, что она настроена указывать на нетестовую базу данных.В этом случае я хочу завершить работу и предотвратить запуск любых дальнейших тестов.Конечно, поскольку unittest ловит SystemExit в ловушку и счастливо продолжает свой путь, это мешает мне.
Единственный вариант, о котором я думал до сих пор, - это использование ctypes или чего-то подобного для прямого вызова exit (3), но это кажется довольно сложным взломом для чего-то, что должно быть действительно простым.
Решение
Ты можешь позвонить os._exit()
для прямого выхода, без создания исключения:
import os
os._exit(1)
Это обходит всю логику завершения работы python, такую как atexit
модуль, и не будет выполняться через логику обработки исключений, которой вы пытаетесь избежать в этой ситуации.Аргумент - это код выхода, который будет возвращен процессом.
Другие советы
Как сказал Иеруб, os._exit (1)
- это ваш ответ. Но, учитывая, что он обходит все процедуры очистки, включая блоки finally:
, закрытие файлов и т. Д., И его действительно следует избегать любой ценой, могу ли я представить " более безопасный МОГ & Quot; способ его использования?
Если вы столкнулись с тем, что SystemExit
перехватывается на внешних уровнях (т. е. unittest), тогда будьте сами внешним уровнем! Оберните свой основной код в блоке try / Кроме, поймать SystemExit и вызвать там os._exit, и only там! Таким образом, вы можете вызвать sys.exit
обычно в любом месте кода, позволяя ему всплыть на верхний уровень, изящно закрывая все файлы и выполняя все очистки, и затем вызывая os._exit.
Вы даже можете выбрать, какие выходы являются «аварийными». из них. Код ниже является примером такого подхода:
import sys, os
EMERGENCY = 255 # can be any number actually
try:
# wrap your whole code here ...
# ... some code
if x: sys.exit()
# ... some more code
if y: sys.exit(EMERGENCY) # use only for emergency exits
# ...
except SystemExit as e:
if e.code != EMERGENCY:
raise # normal exit, let unittest catch it
else:
os._exit(EMERGENCY) # try to stop *that*, sucker!