Abrir un shell de IPython en cualquier excepción (no detectada)

He definido el siguiente shell (incrustado) en Python:

from IPython.config.loader import Config cfg = Config() prompt_config = cfg.PromptManager prompt_config.in_template = 'N.In : ' prompt_config.in2_template = ' .\\D.: ' prompt_config.out_template = 'N.Out: ' banner_msg = ("\n**Nested Interpreter:\n" "Hit Ctrl-D to exit interpreter and continue program.\n" "Note that if you use %kill_embedded, you can fully deactivate\n" "This embedded instance so it will never turn on again") exit_msg = '**Leaving Nested interpreter' from IPython.frontend.terminal.embed import InteractiveShellEmbed ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg) 

Me gustaría que mi progtwig me coloque automáticamente en ese shell cuando haya una excepción, en el ámbito en el que se produce la excepción.

Lo he intentado con:

 def excepthook(type, value, traceback): ipshell(msg) sys.excepthook = excepthook 

Pero esto no parece funcionar (solo obtengo el rastreo estándar). Además, idealmente sería mejor si:

  1. IPython imprime el rastreo regular
  2. y luego me deja en una shell IPython

Si el código que escribí anteriormente funcionó, simplemente me dejaría caer en un shell de IPython y no imprimiría el rastreo.

Actualización 1:

He leído aquí que cuando se ejecuta el código de IPython, IPython se encarga de detectar todas las excepciones y es posible que no sea posible anular directamente sys.excepthook() . Si este es el caso, ¿cómo puedo hacer que IPython ejecute otros ganchos de excepción (por ejemplo, mi ipshell() ) en el ámbito donde se produce la excepción y después de que se imprime el rastreo?

Actualización 2:

Parece que hay un hilo en la lista de desarrolladores que discute esto: un comportamiento similar al de la excepción en ipython . Aparentemente hay una función set_custom_exc que se encarga de esto, pero no estoy seguro de cómo podría conectar eso a mi ipshell() .

Creo que es casi imposible dejar pasar la excepción a través de la stack de llamadas para averiguar si alguien lo atraparía o no al final, y luego volver al ámbito donde se planteó por primera vez. Ese scope original se ha ido, cuando la excepción salió de él.

Su mejor apuesta puede ser envolver todas las partes en las que desea que su shell aparezca para manejar una excepción con un try ... except dedicado try ... except bloque, como se muestra a continuación:

 try: pass # stuff that may raise an exception except KeyboardInterrupt: # some exception you want to handle raise except SystemExit: # another exception you want to handle raise except: # get a hand on any unhandled exception ipshell(traceback.format_exc()) 

(No estoy seguro de si esto se puede implementar de manera más elegante. ¡También me interesaría mucho una mejor solución!)

Definir lo siguiente en mi shell ipython parece hacer lo que quieres:

 def custom_exc(shell, etype, evalue, tb, tb_offset=None): shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset) ipshell() get_ipython().set_custom_exc((Exception,), custom_exc)