Есть ли способ предотвратить исключение исключения SystemExit из sys.exit()?
Документы говорят, что вызов sys.exit() вызывает исключение SystemExit, которое может быть обнаружено на внешних уровнях. У меня есть ситуации, в которой я хочу, чтобы окончательно и бесспорно выйти из внутри теста, однако UnitTest модуль ловит SystemExit и препятствует выходу. Обычно это здорово, но конкретная ситуация, которую я пытаюсь обработать, - это та, где наша тестовая среда обнаружила, что она настроена так, чтобы указывать на нетестовую базу данных. В этом случае я хочу выйти и предотвратить запуск каких-либо дополнительных тестов. Конечно, поскольку unittest ловушки SystemExit и продолжает счастливо на этом пути, это мешает мне.
Единственный вариант, о котором я думал до сих пор, - это использовать ctypes или что-то подобное вызову exit (3), но это кажется довольно уродливым взломом для чего-то, что должно быть действительно просто.
Ответы
Ответ 1
Вы можете вызвать os._exit() для прямого выхода без исключения:
import os
os._exit(1)
Это обходит всю логику выключения python, такую как модуль atexit, и не будет работать через логику обработки исключений, которую вы пытаетесь избежать в этой ситуации. Аргумент - это код выхода, который будет возвращен процессом.
Ответ 2
Как сказал Иеруб, os._exit(1)
- ваш ответ. Но, учитывая, что он обходит все процедуры очистки, в том числе finally:
блоки, закрывающие файлы и т.д., И их следует действительно избегать любой ценой, могу ли я представить "безопасный" способ его использования?
Если у вас проблема с SystemExit
, находящейся на внешних уровнях (т.е. unittest), тогда будет внешним уровнем! Оберните свой основной код в блок try/except, поймите SystemExit и вызовите os._exit и только! Таким образом, вы можете называть 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!