2010-11-20 34 views
36

¿Hay alguna manera de iniciar un shell o indicador de IPython cuando mi programa ejecuta una línea que genera una excepción?Lanzar un shell IPython en la excepción

Estoy interesado principalmente en el contexto, las variables, en el alcance (y subámbitos) donde se produjo la excepción. Algo así como la depuración de Visual Studio, cuando se produce una excepción pero nadie la detecta, Visual Studio se detendrá y me dará la pila de llamadas y las variables presentes en cada nivel.

¿Crees que hay una forma de obtener algo similar usando IPython?

EDIT: La opción -pdb cuando no parece lanzar IPython hacer lo que yo quiero (o tal vez no sé cómo usarlo correctamente, lo que es muy posible). Puedo ejecutar el siguiente script:

def func(): 
    z = 2 
    g = 'b' 
    raise NameError("This error will not be caught, but IPython still" 
        "won't summon pdb, and I won't be able to consult" 
        "the z or g variables.") 

x = 1 
y = 'a' 

func() 

Uso del mando:

ipython -pdb exceptionTest.py 

que se detiene la ejecución cuando se eleva el error, pero me lleva un símbolo IPython donde tengo acceso a las variables globales del guión , pero no las variables locales de función func. pdb solo se invoca cuando escribo directamente un comando en ipython que causa un error, es decir, raise NameError("This, sent from the IPython prompt, will trigger pdb.").

No necesariamente necesito usar pdb, solo me gustaría tener acceso a las variables dentro de func.

EDIT 2: Ha pasado un tiempo, la opción -pdb de IPython funciona ahora como yo quiero. Eso significa que cuando presento una excepción, puedo regresar al alcance de func y leer sus variables z y g sin ningún problema. Incluso sin configurar la opción -pdb, se puede ejecutar IPython en modo interactivo y luego llamar a la función mágica %debug después de que el programa haya salido con error, que también lo llevará a un indicador interactivo de ipdb con todos los ámbitos accesibles.

+1

al hacer este tipo de cortes, tenga en cuenta que la secuencia de comandos se puede bloquear lo llama si se trata de una parte de anoth er programa. Mi sugerencia es verificar si sys.stdin.isatty() antes de hacer eso. – d33tah

Respuesta

20

Actualización para IPython v0.13:

import sys 
from IPython.core import ultratb 
sys.excepthook = ultratb.FormattedTB(mode='Verbose', 
    color_scheme='Linux', call_pdb=1) 
2

man page dice que iPython tiene la opción --[no]pdb que se pasará en la línea de comandos para iniciar iPython en busca de excepciones no detectadas. ¿Buscas más?

EDITAR: python -m pdb pythonscript.py puede ejecutar pdb. Sin embargo, no estoy seguro de lo similar con iPython. Si está buscando el seguimiento de la pila y la autopsia general de la salida anormal del programa, esto debería funcionar.

+0

-1 Esto es para excepciones no detectadas cuando algo ya se está ejecutando dentro de ipython, no para iniciar ipython cuando aún no se está ejecutando. – snapshoe

4

se puede hacer algo como lo siguiente:

import sys 
from IPython.Shell import IPShellEmbed 
ipshell = IPShellEmbed() 

def excepthook(type, value, traceback): 
    ipshell() 

sys.excepthook = excepthook 

Ver sys.excepthook y Embedding IPython.

+0

Me encanta esta idea, pero leo [aquí] (http://stackoverflow.com/questions/1261668/cannot-override-sys-excepthook/1262091#1262091) que ipython * no * usa sys.excepthook. – levesque

+0

Intente agregar esas líneas a la parte superior de la secuencia de comandos, luego ejecútelo fuera de ipython y verifique que lo deje caer en una sesión de ipython. Si comenzó la secuencia de comandos con 'ipython

9

ipdb integra funciones de IPython en pdb. Utilizo el siguiente código para lanzar mis aplicaciones al depurador de IPython después de una excepción sin manos.

import sys, ipdb, traceback 

def info(type, value, tb): 
    traceback.print_exception(type, value, tb) 
    ipdb.pm() 

sys.excepthook = info 
+4

ipdb también tiene un administrador de contexto práctico: 'launch_ipdb_on_exception()' – scribu

5

@ respuesta de snapshoe no funciona en las versiones más recientes de IPython.

Esto hace al menos:

import sys 
from IPython import embed 

def excepthook(type, value, traceback): 
    embed() 

sys.excepthook = excepthook 
+0

Este es el que he usado para iniciar el shell en algún punto de un script –

2

@ obras de Adam como un encanto excepto que IPython carga un poco lento (800 ms en mi máquina). Aquí tengo un truco para hacer que la carga sea floja.

class ExceptionHook: 
    instance = None 

    def __call__(self, *args, **kwargs): 
     if self.instance is None: 
      from IPython.core import ultratb 
      self.instance = ultratb.FormattedTB(mode='Verbose', 
       color_scheme='Linux', call_pdb=1) 
     return self.instance(*args, **kwargs) 
sys.excepthook = ExceptionHook() 

Ahora no tenemos que esperar desde el principio. Solo cuando el programa se cuelga provocará la importación de IPython.

1

Si desea obtener tanto el rastreo y abrir una concha IPython con el medio ambiente en el lugar de la excepción:

def exceptHook(*args): 
    '''A routine to be called when an exception occurs. It prints the traceback 
    with fancy formatting and then calls an IPython shell with the environment 
    of the exception location. 
    ''' 
    from IPython.core import ultratb 
    ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args) 
    from IPython.terminal.embed import InteractiveShellEmbed 
    import inspect 
    frame = inspect.getinnerframes(args[2])[-1][0] 
    msg = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame) 
    savehook = sys.excepthook # save the exception hook 
    InteractiveShellEmbed()(msg,local_ns=frame.f_locals,global_ns=frame.f_globals) 
    sys.excepthook = savehook # reset IPython's change to the exception hook 

import sys 
sys.excepthook = exceptHook 

en cuenta que es necesario tirar de la información de espacio de nombres desde el último cuadro que hace referencia el rastreo (arg [2])

+0

Si alguien todavía está usando IPython 0.12 (EPD), la importación debe ser '' 'de IPython.frontend.terminal.embed import InteractiveShellEmbed''' – bht

2

puede probar esto:

from ipdb import launch_ipdb_on_exception 

def main(): 
    with launch_ipdb_on_exception(): 
     # The rest of the code goes here. 
     [...] 
Cuestiones relacionadas