2008-10-06 2 views
39

Документы говорят, что вызов sys.exit() вызывает исключение SystemExit, которое может быть обнаружено на внешних уровнях. У меня есть ситуации, в которой я хочу, чтобы окончательно и бесспорно выйти из внутри теста, однако UnitTest модуль ловит SystemExit и препятствует выходу. Обычно это здорово, но конкретная ситуация, которую я пытаюсь обработать, - это та, где наша тестовая среда обнаружила, что она настроена так, чтобы указывать на нетестовую базу данных. В этом случае я хочу выйти и предотвратить запуск каких-либо дополнительных тестов. Конечно, поскольку unittest ловушки SystemExit и продолжает счастливо на своем пути, это мешает мне.Есть ли способ предотвратить появление исключения SystemExit из sys.exit()?

Единственный вариант, о котором я думал до сих пор, - это использовать ctypes или что-то подобное вызову exit (3), но это кажется довольно уродливым взломом для чего-то, что должно быть очень просто.

+0

Это также актуально при попытке выйти из программы из встроенной оболочки IPython. – quazgar 2016-10-10 12:17:12

ответ

54

Вы можете позвонить os._exit() напрямую выйти, не бросать исключение:

import os 
os._exit(1) 

Это обходит всю логику питона отключения, таких как atexit модуль, и не будет работать через логику обработки исключений, что вам «стараюсь избегать в этой ситуации. Аргументом является код выхода, который будет возвращен процессом.

38

Как сказал Jerab, 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! 
+1

Один случай, который мне нужно проверить, - это код 0, который указывает, что мы пытаемся выйти из системы без ошибок/сбоев. Это полезно при использовании OptionParser, когда он передан -h arg, и я не хочу, чтобы SystemExit рассматривался как исключение. Итак, спасибо, вы помогли мне проверить, как получить доступ к коду выхода через исключение. – leetNightshade 2013-06-21 18:54:04

Смежные вопросы