(Actualización el 28 de mayo de 2016) Uso de RealGUD en Emacs
Para cualquier persona en Emacs, este hilo muestra cómo lograr todo lo descrito en el OP (y más) usando
- un nuevo depurador importante en Emacs llamado RealGUD que puede funcionar con cualquier depurador (incluido
ipdb
).
- El paquete Emacs
isend-mode
.
La combinación de estos dos paquetes es extremadamente poderosa y permite recrear exactamente el comportamiento descrito en el OP y hacer aún más.
Más información sobre el artículo wiki de RealGUD para ipdb.
Respuesta original:
Después de haber probado muchos métodos diferentes para depurar Python, incluido todo lo mencionado en este hilo, una de mis formas preferidas de depurar Python con IPython es con shells incrustados.
Definición de un shell IPython incrustado personalizado:
Agregue lo siguiente en un script a su PYTHONPATH
, para que el método ipsh()
esté disponible.
import inspect
# First import the embed function
from IPython.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'
# Wrap it in a function that gives me more context:
def ipsh():
ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)
frame = inspect.currentframe().f_back
msg = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)
# Go back one level!
# This is needed because the call to ipshell is inside the function ipsh()
ipshell(msg,stack_depth=2)
Luego, cada vez que quiero depurar algo en mi código, lo coloco ipsh()
justo en el lugar donde necesito hacer una inspección de objetos, etc. Por ejemplo, digamos que quiero depurarmy_function
continuación
Utilizándolo:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
y luego invoco my_function(2)
de una de las siguientes maneras:
- Ya sea ejecutando un programa Python que invoca esta función desde un shell de Unix
- O invocandolo directamente desde IPython
Independientemente de cómo lo invoque, el intérprete se detiene en la línea que dice ipsh()
. Una vez que haya terminado, puede hacerlo Ctrl-D
y Python reanudará la ejecución (con cualquier actualización variable que haya realizado). Tenga en cuenta que, si ejecuta el código desde un IPython normal, el shell de IPython (caso 2 anterior), el nuevo shell de IPython estará anidado dentro del que lo invocó, lo cual está perfectamente bien, pero es bueno tenerlo en cuenta. De todos modos, una vez que el intérprete se detiene en la ubicación de ipsh
, puedo inspeccionar el valor de a
(que puede ser2
), ver qué funciones y objetos están definidos, etc.
El problema:
La solución anterior se puede usar para que Python se detenga en cualquier lugar que desee en su código y luego lo deje en un intérprete de IPython completo. Desafortunadamente, no le permite agregar o eliminar puntos de interrupción una vez que invoca el script, lo cual es muy frustrante. En mi opinión, este es el único que impide que IPython se convierta en una gran herramienta de depuración para Python.
Lo mejor que puedes hacer por ahora:
Una solución alternativa es colocar ipsh()
a priori en las diferentes ubicaciones donde desea que el intérprete de Python inicie un shell de IPython (es decir, a breakpoint
). Luego puede "saltar" entre diferentes "puntos de interrupción" predefinidos y codificados Ctrl-D
, lo que saldría del shell IPython incrustado actual y se detendría nuevamente cada vez que el intérprete llegue a la siguiente llamada paraipsh()
.
Si sigue esta ruta, una forma de salir del "modo de depuración" e ignorar todos los puntos de interrupción subsiguientes es utilizar lo ipshell.dummy_mode = True
que hará que Python ignore cualquier instanciación posterior del ipshell
objeto que creamos anteriormente.
!
comando que ejecuta cualquier comando de python en el punto de interrupción