198 votes

Débogage pas à pas avec IPython

D'après ce que j'ai lu, il y a deux façons de déboguer du code en Python :

  • Avec un débogueur traditionnel tel que pdb o ipdb . Cela prend en charge des commandes telles que c pour continue , n pour step-over , s pour step-into etc.), mais vous n'avez pas d'accès direct à un shell IPython qui peut être extrêmement utile pour l'inspection des objets.

  • Utilisation de IPython par intégration un shell IPython dans votre code. Vous pouvez faire from IPython import embed et ensuite utiliser embed() dans votre code. Lorsque votre programme/script rencontre une embed() vous vous retrouvez dans un shell IPython. Cela permet l'inspection complète des objets et le test du code Python en utilisant toutes les fonctionnalités d'IPython. Cependant, lorsque vous utilisez embed() vous ne pouvez pas étape par étape à travers le code grâce à des raccourcis clavier très pratiques.

Y a-t-il un moyen de combiner le meilleur des deux mondes ? Par exemple.

  1. Être capable de étape par étape à travers votre code avec des raccourcis clavier pdb/ipdb très pratiques.
  2. À n'importe quelle étape de ce processus (par exemple, pour une déclaration donnée), vous avez accès à une véritable Shell IPython .

Débogage d'IPython dans le cas de MATLAB :

Un exemple de ce type de "débogage amélioré" peut être trouvé dans MATLAB, où l'utilisateur toujours a un accès complet au moteur/coque MATLAB, et elle peut toujours étape par étape à travers son code, définir des points d'arrêt conditionnels, etc. D'après ce que j'ai discuté avec d'autres utilisateurs, c'est la fonction de débogage qui manque le plus aux gens lorsqu'ils passent de MATLAB à IPython.

Débogage d'IPython dans Emacs et d'autres éditeurs :

Je ne veux pas rendre la question trop spécifique, mais je travaille principalement dans Emacs, et je me demande s'il existe un moyen d'y intégrer cette fonctionnalité. Idéalement Dans le cas d'un programmeur, Emacs (ou l'éditeur) permettrait au programmeur de placer des points d'arrêt n'importe où dans le code et de communiquer avec l'interpréteur ou le débogueur pour qu'il s'arrête à l'endroit de votre choix et qu'un interpréteur IPython complet apparaisse à cet endroit.

0 votes

Pdb a ! commande qui exécute toute commande python au point d'arrêt

5 votes

Je cherche aussi un débogueur python similaire à Matlab ! Par exemple, je fais beaucoup de prototypage dans le shell python. Toutes les variables sont sauvegardées avec le shell. Maintenant je rencontre un problème. J'espère pouvoir déboguer un petit morceau de code, avec ces variables calculées avec le shell. Cependant, un nouveau débogueur ne peut pas accéder aux anciennes variables. Ce n'est pas pratique pour le prototypage.

1 votes

Pour les utilisateurs d'Emacs, RealGUD a une interface incroyablement bonne.

120voto

Ehvince Points 1672

Qu'en est-il de ipdb.set_trace() ? Dans votre code :

import ipdb; ipdb.set_trace()

mise à jour : maintenant en Python 3.7, nous pouvons écrire breakpoint() . Il fonctionne de la même manière, mais il obéit aussi à la règle de l'art. PYTHONBREAKPOINT variable d'environnement. Cette fonctionnalité provient de ce PEP .

Cela permet une inspection complète de votre code, et vous avez accès à des commandes telles que c (continuer), n (exécuter la ligne suivante), s (entrer dans la méthode au point) et ainsi de suite.

Voir le ipdb repo y une liste de commandes . IPython s'appelle désormais (modifier : partie de) Jupyter .


ps : notez qu'une commande ipdb a la priorité sur le code python. Donc pour écrire list(foo) vous auriez besoin print(list(foo)) ou !list(foo) .

De plus, si vous aimez l'invite d'ipython (ses modes emacs et vim, son historique, ses complétions, ), il est facile d'obtenir la même chose pour votre projet puisqu'il est basé sur le module kit d'outils d'invite python .

10 votes

C'est comme ça qu'il faut faire.

0 votes

Ma réponse inclut maintenant comment utiliser ipdb dans Emacs en utilisant RealGUD y isend-mode pour faire exactement ce que le PO demande.

1 votes

Jupyter n'est pas un remplacement pour IPython, mais pour IPython Notebook. Les notebooks Jupyter utilisent le noyau en arrière-plan. Pour les notebooks Python, le noyau est généralement un noyau IPython. Le site Projet IPython continue plus loin.

40voto

user815423426 Points 9267

(Mise à jour le 28 mai 2016) Utilisation de RealGUD dans Emacs

Pour tous ceux qui utilisent Emacs, ce fil montre comment accomplir tout ce qui est décrit dans l'OP (et plus encore) en utilisant

  1. un nouveau débogueur important dans Emacs appelé RealGUD qui peut fonctionner avec n'importe quel débogueur (notamment ipdb ).
  2. Le paquet Emacs isend-mode .

La combinaison de ces deux paquets est extrêmement puissante et permet de recréer exactement le comportement décrit dans l'OP et de faire encore plus.

Plus d'informations sur l'article de 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 de discussion, l'une de mes méthodes préférées pour déboguer Python avec IPython est l'utilisation de shells intégrés.

Définition d'un shell IPython embarqué personnalisé :

Ajouter ce qui suit sur un script à votre PYTHONPATH de sorte que la méthode ipsh() devient 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 des objets, etc. Par exemple, disons que je veux déboguer my_function en dessous de

L'utiliser :

def my_function(b):
  a = b
  ipsh() # <- This will embed a full-fledged IPython interpreter
  a = 4

et ensuite j'invoque my_function(2) de l'une des manières suivantes :

  1. Soit en exécutant un programme Python qui invoque cette fonction à partir d'un shell Unix
  2. Ou en l'invoquant 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 faire Ctrl-D et Python reprendra son 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 shell IPython normal (cas 2 ci-dessus), le nouveau shell IPython sera emboîté à l'intérieur de celui à partir duquel vous l'avez invoqué, ce qui est parfaitement normal, mais il est bon d'en être conscient. De toute façon, une fois que l'interpréteur s'arrête sur l'emplacement de ipsh je peux inspecter la valeur de a (qui est 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, et vous amène ensuite dans un interpréteur IPython à part entière. Malheureusement, elle ne vous permet pas d'ajouter ou de supprimer des points d'arrêt une fois que vous avez invoqué le script, ce qui est très frustrant. À mon avis, c'est le seulement 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 endroits où vous voulez que l'interpréteur Python lance un shell IPython (c'est-à-dire un breakpoint ). Vous pouvez ensuite "sauter" entre différents "points d'arrêt" prédéfinis et codés en dur avec Ctrl-D qui quitterait le shell IPython embarqué en cours et s'arrêterait à nouveau dès que l'interpréteur atteindrait le prochain appel à la commande ipsh() .

Si vous empruntez cette voie, une façon de quitter le "mode de débogage" et d'ignorer tous les points d'arrêt ultérieurs est d'utiliser la commande suivante ipshell.dummy_mode = True qui fera en sorte que Python ignore toute instanciation ultérieure de l'objet ipshell que nous avons créé ci-dessus.

2 votes

Veuillez mettre à jour cette page si vous trouvez une solution encore meilleure. Mais ça a l'air bien. Je vais l'utiliser.

0 votes

Où utiliser ipshell.dummy_mode = True ? Peut-on l'utiliser à partir de avec dans une session ipython en cours ?

0 votes

@Phani -- oui, vous pouvez le faire à tout moment pendant la "session de débogage" (c'est-à-dire chaque fois que le shell imbriqué ipsh() est invoqué et vous avez terminé le débogage).

19voto

tkf Points 1815

Vous pouvez démarrer une session IPython à partir de pudb et revenir à la session de débogage comme vous le souhaitez.

BTW, ipdb utilise IPython en arrière-plan et vous pouvez effectivement utiliser les fonctionnalités d'IPython telles que la complétion TAB et les commandes magiques (celle qui commence par % ). Si vous connaissez bien ipdb, vous pouvez le lancer depuis IPython en utilisant des commandes telles que %run y %debug La session ipdb est en fait meilleure que celle d'IPython en ce sens que vous pouvez monter et descendre dans la trace de la pile, etc. Qu'est-ce qui manque dans ipdb pour "l'inspection des objets" ?

De plus, python.el, fourni avec Emacs >= 24.3, offre un bon support pour ipdb.

1 votes

Merci tkf. Je suis un grand fan de votre paquet Emacs-Jedi. Quand vous dites qu'Emacs 24.3 a un bon support pour ipdb, pouvez-vous développer ? Je démarre habituellement IPython dans un fichier séparé M-x ansi-term et ensuite j'utilise isend-mode pour lier mes tampons de source au tampon IPython afin de pouvoir envoyer du code à l'interpréteur IPython à l'aide d'un raccourci clavier qui envoie automatiquement la balise %paste magique vers le tampon IPython. Cela me permet de tester rapidement des régions dans IPython. Je lance toujours mes programmes à partir de ce shell IPython avec run et utiliser embed() de s'arrêter.

3 votes

Par exemple, lorsque vous avancez dans le code, le code source est ouvert dans l'autre tampon avec une flèche indiquant le point d'exécution actuel. Vous disposez également de la commande send-region, comme vous le faites avec isend-mode.

0 votes

Merci @tkf Comment puis-je commencer un ipdb session de débogage en utilisant python.el et avoir des choses comme send-region etc. vers le shell correspondant ? En général, où puis-je trouver plus d'informations à ce sujet ?

7voto

user1953384 Points 258

Préfixer un symbole " !" aux commandes que vous tapez dans pdb semble avoir le même effet que de faire quelque chose dans un shell IPython. Cela fonctionne pour accéder à l'aide d'une certaine fonction, ou même aux noms de variables. Peut-être cela vous aidera-t-il dans une certaine mesure. Par exemple,

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)

Mais !help(numpy.transpose) vous donnera la page d'aide attendue sur numpy.transpose. De même pour les noms de variables, disons que vous avez une variable l, taper "l" dans pdb liste le code, mais !l imprime la valeur de l.

3 votes

Il s'agit d'une mauvaise surprise pour pdb, qui mérite d'être connue.

3voto

LogicalKnight Points 144

Une option consiste à utiliser un IDE comme Spyder qui devrait vous permettre d'interagir avec votre code tout en déboguant (en utilisant une console IPython, en fait). En fait, Spyder est très proche de MATLAB, ce qui, je suppose, était intentionnel. Cela inclut les inspecteurs de variables, l'édition de variables, l'accès intégré à la documentation, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X