Usando IPython como un depurador efectivo

¿Cómo puedo incrustar un shell IPython en mi código y hacer que muestre automáticamente el número de línea y la función en la que se invocó?

Actualmente tengo la siguiente configuración para incrustar shells IPython en mi código:

from IPython.frontend.terminal.embed import InteractiveShellEmbed from IPython.config.loader import Config # Configure the prompt so that I know I am in a nested (embedded) shell cfg = Config() prompt_config = cfg.PromptManager prompt_config.in_template = 'N.In : ' prompt_config.in2_template = ' .\\D.: ' prompt_config.out_template = 'N.Out: ' # Messages displayed when I drop into and exit the shell. 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' # Put ipshell() anywhere in your code where you want it to open. ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg) 

Esto me permite iniciar un shell completo de IPython en cualquier parte de mi código simplemente usando ipshell() . Por ejemplo, el siguiente código:

 a = 2 b = a ipshell() 

inicia un shell IPython en el scope de la persona que llama que me permite inspeccionar los valores de a y b .

Lo que me gustaría hacer es ejecutar automáticamente el siguiente código cada vez que llamo a ipshell() :

 frameinfo = getframeinfo(currentframe()) print 'Stopped at: ' + frameinfo.filename + ' ' + str(frameinfo.lineno) 

Esto siempre mostraría el contexto donde se inicia el shell de IPython para que sepa qué archivo / función, etc. Estoy depurando.

Tal vez podría hacer esto con un decorador, pero todos mis bashs han fracasado, ya que necesito que ipshell() ejecute dentro del contexto original (de modo que tenga acceso a b desde el shell de IPython).

¿Cómo puedo lograr esto?

Puede llamar a ipshell() desde otra función definida por el usuario, por ejemplo, ipsh()

 from inspect import currentframe def ipsh(): frame = currentframe().f_back msg = 'Stopped at {0.f_code.co_filename} and line {0.f_lineno}'.format(frame) ipshell(msg,stack_depth=2) # Go back one level! 

Luego use ipsh() cuando quiera colocar en el shell de IPython.

Explicación:

  • stack_depth=2 le pide a ipshell que suba un nivel al recuperar el espacio de nombres para el nuevo shell de IPython (el valor predeterminado es 1 ).
  • currentframe().f_back() recupera el marco anterior para que pueda imprimir el número de línea y el archivo de la ubicación donde se llama a ipsh() .