(Mise à jour du 28 mai 2016) Utilisation de RealGUD dans Emacs
Pour n'importe qui dans Emacs, ce fil montre comment accomplir tout ce qui est décrit dans l'OP (et plus) en utilisant
- un nouveau débogueur important dans Emacs appelé RealGUD qui peut fonctionner avec n'importe quel débogueur (y compris
ipdb
).
- Le package Emacs
isend-mode
.
La combinaison de ces deux packages est extrêmement puissante et permet de recréer exactement le comportement décrit dans l'OP et d'en faire encore plus.
Plus d'informations sur l'article wiki de RealGUD pour ipdb.
Réponse originale:
Après avoir essayé de nombreuses méthodes différentes pour déboguer Python, y compris tout ce qui est mentionné dans ce fil, l'un de mes moyens préférés de déboguer Python avec IPython est d'utiliser des shells intégrés.
Définition d'un shell IPython intégré personnalisé:
Ajoutez ce qui suit sur un script à votre PYTHONPATH
, afin que la méthode ipsh()
devienne 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)
Ensuite, chaque fois que je veux déboguer quelque chose dans mon code, je place ipsh()
juste à l'endroit où je dois faire l'inspection d'objet, etc. Par exemple, disons que je veux déboguer my_function
ci-dessous
En l'utilisant:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
puis j'invoque my_function(2)
de l'une des manières suivantes:
- Soit en exécutant un programme Python qui invoque cette fonction depuis un shell Unix
- Ou en l'appelant directement depuis IPython
Quelle que soit la façon dont je l'invoque, l'interprète s'arrête à la ligne qui dit ipsh()
. Une fois que vous avez terminé, vous pouvez le faire Ctrl-D
et Python reprendra l'exécution (avec toutes les mises à jour de variables que vous avez effectuées). Notez que, si vous exécutez le code à partir d'un IPython standard le shell IPython (cas 2 ci-dessus), le nouveau shell IPython sera imbriqué dans celui à partir duquel vous l'avez appelé, ce qui est parfaitement bien, mais il est bon d'en être conscient. Quoi qu'il en soit, une fois que l'interpréteur s'arrête à l'emplacement de ipsh
, je peux inspecter la valeur de a
(quel être 2
), voir quelles fonctions et quels objets sont définis, etc.
Le problème:
La solution ci-dessus peut être utilisée pour que Python s'arrête où vous le souhaitez dans votre code, puis vous place dans un interpréteur IPython à part entière. Malheureusement, il ne vous permet pas d'ajouter ou de supprimer des points d'arrêt une fois que vous avez appelé le script, ce qui est très frustrant. À mon avis, c'est la seule chose qui empêche IPython de devenir un excellent outil de débogage pour Python.
Le mieux que vous puissiez faire pour le moment:
Une solution de contournement consiste à placer ipsh()
a priori aux différents emplacements où vous voulez que l'interpréteur Python lance un shell IPython (ie a breakpoint
). Vous pouvez alors "sauter" entre différents "points d'arrêt" prédéfinis et codés en dur avec Ctrl-D
, ce qui quitterait le shell IPython intégré actuel et s'arrêterait à nouveau chaque fois que l'interpréteur frappera le prochain appel à ipsh()
.
Si vous suivez cette route, une façon de quitter le "mode de débogage" et d'ignorer tous les points d'arrêt suivants est d'utiliser ipshell.dummy_mode = True
ce qui fera en sorte que Python ignore toutes les instanciations ultérieures de l' ipshell
objet que nous avons créé ci-dessus.
!
commande qui exécute n'importe quelle commande python au point d'arrêt