2008-10-06 11 views
39

Los documentos dicen que al llamar a sys.exit() se genera una excepción SystemExit que se puede atrapar en niveles externos. Tengo una situación en la que quiero salir definitiva e incuestionablemente desde el interior de un caso de prueba; sin embargo, el módulo unittest detecta SystemExit e impide la salida. Esto normalmente es genial, pero la situación específica que trato de manejar es una en la que nuestro marco de prueba ha detectado que está configurado para apuntar a una base de datos que no es de prueba. En este caso, quiero salir e impedir que se ejecuten más pruebas. Por supuesto, dado que Unittest atrapa el SystemExit y continúa felizmente en su camino, me está frustrando.¿Hay alguna forma de evitar que una excepción SystemExit generada a partir de sys.exit() quede atrapada?

La única opción en la que he pensado hasta ahora es usar ctypes o algo similar para llamar a exit (3) directamente, pero esto parece ser un truco muy fugly para algo que debería ser realmente simple.

+0

Esto también es relevante cuando se trata de salir de un programa desde un shell de IPython incrustado. – quazgar

Respuesta

54

Puede llamar os._exit() para salir directamente, sin lanzar una excepción:

import os 
os._exit(1) 

Esto no pasa por toda la lógica pitón de cierre, tales como el módulo atexit, y no se ejecutará a través de la lógica de control de excepciones que usted estamos tratando de evitar en esta situación. El argumento es el código de salida que será devuelto por el proceso.

38

Como dijo Jerub, os._exit(1) es su respuesta. Pero, considerando que pasa por alto todos los procedimientos de limpieza, incluidos los bloques finally:, el cierre de archivos, etc., y realmente debe evitarse a toda costa, ¿puedo presentar una forma "más segura" de usarlo?

Si su problema es SystemExit atrapado en los niveles exteriores (es decir, unittest), entonces ¡sea el nivel exterior usted mismo! Envuelva su código principal en un bloque try/except, atrape SystemExit y llame a os._exit allí, y ¡allí solo! De esta manera, puede llamar al sys.exit normalmente en cualquier parte del código, dejarlo pasar al nivel superior, cerrando con gracia todos los archivos y ejecutar todas las limpiezas, y luego llamando a os._exit.

Incluso puede elegir qué salidas son las de "emergencia". El siguiente código es un ejemplo de dicho enfoque:

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

Un caso que necesitaba verificar es si el código es 0, lo que indica que estamos tratando de salir normalmente sin error/colisión. Esto es útil cuando se usa OptionParser cuando se pasa el -h arg y no quiero que se trate a SystemExit como una excepción. Entonces, gracias, me ayudaste a verificar cómo acceder al código de salida a través de la excepción. – leetNightshade

+0

Lo mismo aquí. Necesitaba verificar el código 0, y esto ayudó. – BuvinJ

Cuestiones relacionadas