Debugowanie krok po kroku za pomocą IPython

Z tego, co czytałem, są dwa sposoby debugowania kodu w Pythonie:

  • Z tradycyjnym debugerem, takim jak pdb LUB ipdb. Obsługuje polecenia takie jak c dla continue, n na step-over, s dla step-into itd.), ale nie masz bezpośredniego dostępu do powłoki IPython, która może być niezwykle przydatna do kontroli obiektów.

  • Użycie IPython przez osadzenie powłoki IPython w Twoim kodzie. Możesz zrobić from ipython import embed, a następnie użyć embed() w Twój kod. Gdy twój program / skrypt trafi w instrukcję embed(), zostaniesz przeniesiony do powłoki IPython. Pozwala to na pełną kontrolę obiektów i testowanie kodu Pythona przy użyciu wszystkich gadżetów IPython. Jednak przy użyciu embed() nie można już krok po kroku przechodzić przez kod za pomocą poręcznych skrótów klawiaturowych.

Czy jest jakiś sposób, aby połączyć to, co najlepsze z obu światów? I. E.

  1. być w stanie krok po kroku poprzez swój kod z handy pdb/ipdb skróty klawiaturowe.
  2. na każdym takim kroku (np. na danej instrukcji), mają dostęp do pełnowartościowej powłoki IPython.

Debugowanie IPython jak w MATLAB:

Przykład tego typu "ulepszonego debugowania" można znaleźć w MATLAB, gdzie użytkownik zawsze ma pełny dostęp do silnika/powłoki MATLAB i nadal może krok po kroku poprzez swój kod, definiować warunkowe punkty przerwania itp. Z tego co dyskutowałem z innymi użytkownicy, jest to funkcja debugowania, której ludzie najbardziej brakuje podczas przechodzenia z MATLAB do IPython.

Debugowanie IPython w Emacsie i innych edytorach:

Nie chcę, aby pytanie było zbyt szczegółowe, ale pracuję głównie w Emacsie, więc zastanawiam się, czy jest jakiś sposób, aby wprowadzić tę funkcjonalność do niego. najlepiej , Emacs (lub edytor) pozwoliłby programiście ustawić punkty przerwania w dowolnym miejscu kodu i komunikować się z interpreterem lub debuggerem, aby zatrzymać go w lokalizacja do wyboru, i doprowadzić do pełnego interpretera IPython w tej lokalizacji.

Author: Amelio Vazquez-Reina, 2013-06-01

13 answers

A co z ipdb?set_trace() ? W kodzie:

import ipdb; ipdb.set_trace()

Update : teraz w Pythonie 3.7 możemy napisać breakpoint(). Działa tak samo, ale jest również zgodna ze zmienną środowiskową PYTHONBREAKPOINT. Ta funkcja pochodzi z tego PEP .

Pozwala to na pełną kontrolę kodu i masz dostęp do poleceń takich jak c (continue), n (execute next line), s (krok do metody w punkcie) i tak dalej.

Zobacz IPDB repo i lista poleceń . IPython jest teraz nazywany (edit: part of) Jupyter.


Ps: zauważ, że polecenie ipdb ma pierwszeństwo przed kodem Pythona. Więc aby napisać list(foo), potrzebujesz print list(foo).

Ponadto, jeśli podoba Ci się monit ipython (jego tryby emacs i vim, historia, uzupełnienia,...), łatwo jest uzyskać to samo dla Twojego projektu, ponieważ jest on oparty na Python prompt toolkit .

 81
Author: Ehvince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-13 15:16:10

RealGUD w Emacs-Ie]}

Dla każdego w Emacsie, ten wątek pokazuje jak wykonać wszystko opisane w OP (i nie tylko) za pomocą

  1. nowy ważny debuger w Emacsie o nazwie RealGUD , który może działać z każdym debuggerem (w tym ipdb).
  2. Pakiet Emacs isend-mode.

Połączenie tych dwóch pakietów jest niezwykle potężne i pozwala odtworzyć dokładnie opisane zachowanie w OP i zrobić jeszcze więcej.

Więcej informacji na artykuł wiki Z RealGUD dla ipdb.


Oryginalna odpowiedź:

Po wypróbowaniu wielu różnych metod debugowania Pythona, w tym wszystkich wymienionych w tym wątku, jednym z moich preferowanych sposobów debugowania Pythona za pomocą Ipythona są wbudowane powłoki.

W tym celu należy wykonać następujące czynności:]}

Dodaj następujący skrypt do swojego PYTHONPATH, tak aby metoda ipsh() stała się dostępny.

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)

Następnie, gdy chcę debugować coś w moim kodzie, umieszczam ipsh() dokładnie w miejscu, w którym muszę wykonać inspekcję obiektu itp. Na przykład, powiedzmy, że chcę debugować my_function poniżej

Użycie:

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

A potem wywołuję my_function(2) w jeden z następujących sposobów:

  1. albo uruchamiając program Pythona, który wywołuje tę funkcję z powłoki Uniksa
  2. Czy też poprzez wywołanie go bezpośrednio z IPython [30]}

Niezależnie od tego jak wywołując to, interpreter zatrzymuje się na linii, która mówi ipsh(). Gdy skończysz, możesz wykonać Ctrl-D i Python wznowi wykonywanie (z dowolnymi aktualizacjami zmiennych, które wykonałeś). Zauważ, że jeśli uruchomisz Kod ze zwykłej powłoki IPython IPython (przypadek 2 powyżej), nowa powłoka IPython będzie zagnieżdżona wewnątrz tej, z której ją wywołałeś, co jest całkowicie w porządku, ale dobrze jest być tego świadomym. W każdym razie, gdy interpreter zatrzyma się na miejscu ipsh, mogę sprawdzić wartość z a (które są 2), zobacz jakie funkcje i obiekty są zdefiniowane, itd.

Problem:

Powyższe rozwiązanie może zostać użyte do zatrzymania Pythona w dowolnym miejscu kodu, a następnie wrzucenia go do pełnowartościowego interpretera Ipythona. Niestety nie pozwala dodawać ani usuwać punktów przerwania po wywołaniu skryptu, co jest bardzo frustrujące. Moim zdaniem jest to tylko rzecz, która uniemożliwia IPython stanie się świetnym narzędziem debugowania dla Python.

The best you can do now:

Obejściem jest umieszczenie ipsh() a priori w różnych miejscach, w których chcesz, aby interpreter Pythona uruchomił powłokę IPython (np. breakpoint). Następnie można" przeskakiwać "między różnymi predefiniowanymi, zakodowanymi na twardo" punktami przerwania " za pomocą Ctrl-D, które zamykają obecną wbudowaną powłokę IPython i zatrzymują się ponownie, gdy interpreter uruchomi następne wywołanie ipsh().

Jeśli pójdziesz tą trasą, jeden sposób, aby wyjść z "debugging mode" i ignorowanie wszystkich kolejnych punktów przerwania polega na użyciu ipshell.dummy_mode = True, co spowoduje, że Python zignoruje wszelkie kolejne instancje obiektu ipshell, który stworzyliśmy powyżej.

 40
Author: Amelio Vazquez-Reina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-29 22:27:20

Możesz rozpocząć sesję IPython od pudb i wrócić do sesji debugowania, jak chcesz.

BTW, ipdb używa Ipythona za kulisami i możesz faktycznie używać funkcji IPython, takich jak wypełnianie kart i magiczne polecenia(ta zaczyna się od %). Jeśli jesteś w porządku z ipdb, możesz uruchomić go z IPython za pomocą poleceń takich jak %run i %debug. sesja ipdb jest rzeczywiście lepsza niż zwykły IPython w tym sensie, że można przejść w górę iw dół w śledzeniu stosu itp. Co? czy w ipdb brakuje "object inspection"?

Również python.el w pakiecie z Emacs > = 24.3 ma ładne wsparcie ipdb.
 18
Author: tkf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 19:10:09

Nikt jeszcze nie wspomniał o fladze Ipythona. Po prostu zadzwoń %pdb W Ipythonie, a gdy wystąpi błąd, automatycznie spadniesz do ipdb. Podczas gdy nie masz stepping od razu, jesteś w ipdb później.

Ułatwia to debugowanie poszczególnych funkcji, ponieważ można po prostu załadować plik za pomocą %load, a następnie uruchomić funkcję. Możesz wymusić błąd za pomocą assert W odpowiedniej pozycji.

 12
Author: sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-14 14:14:04

Wygląda na to, że podejście w odpowiedzi @gaborous jest przestarzałe.

Nowe podejście wydaje się być:

from IPython.core import debugger
debug = debugger.Pdb().set_trace

def buggy_method():
    debug()
 9
Author: Elliot Larson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 19:51:12

Przedrostek"!"symbol poleceń, które wpisujesz w pdb, wydaje się mieć taki sam efekt, jak robienie czegoś w powłoce IPython. Działa to w przypadku dostępu do pomocy dla określonej funkcji, a nawet nazw zmiennych. Może to ci w jakimś stopniu pomoże. Na przykład,

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)
Ale !pomoc (numpy.transpose) da ci oczekiwaną stronę pomocy na numpy.transpozycja. Podobnie dla nazw zmiennych, powiedzmy, że masz zmienną l, wpisując "l" w pdb wyświetla kod, ale !l wyświetla wartość l.
 6
Author: user1953384,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-14 15:50:31

Próbowałeś tego napiwku?

Albo jeszcze lepiej, Użyj ipython i wywołaj:

from IPython.Debugger import Tracer; debug_here = Tracer()

Wtedy możesz po prostu użyć

debug_here()

Gdy chcesz ustawić punkt przerwania

 4
Author: gaborous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-26 01:32:22

Jedną z opcji jest użycie IDE podobnego do Spyder , które powinno pozwolić na interakcję z kodem podczas debugowania (w rzeczywistości przy użyciu konsoli IPython). W rzeczywistości Spyder jest bardzo podobny do Matlaba, co, jak przypuszczam, było zamierzone. Obejmuje to zmienne, edycję zmiennych, wbudowany dostęp do dokumentacji itp.

 3
Author: Benjamin B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-05 11:54:58

Po wpisaniu exit () w konsoli embed () kod jest kontynuowany i przechodzi do następnej linii embed ().

 2
Author: TurinTurambar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-21 21:55:30

Pyzo IDE ma podobne możliwości jak OP. Nie musisz uruchamiać w trybie debugowania. Podobnie jak w MATLAB, polecenia są wykonywane w powłoce. Po skonfigurowaniu punktu przerwania w jakiejś linii kodu źródłowego, IDE zatrzymuje tam Wykonywanie, a Ty możesz debugować i wydawać zwykłe polecenia IPython.

Wydaje się jednak, że step-into Nie (jeszcze?) działa dobrze (tzn. zatrzymując się w jednej linii, a następnie przechodząc do innej funkcji), chyba że ustawisz inną punkt przerwania.

Mimo to, pochodząc z Matlaba, wydaje się to najlepszym rozwiązaniem, jakie znalazłem.

 2
Author: user6715080,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-14 14:49:57

Uruchamiany z IPython-shell Emacsa i breakpoint ustawiony przez pdb.set_trace () powinno działać.

Sprawdzone w trybie Pythona.el, M-x ipython RET itp.

 1
Author: Andreas Röhler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 07:52:38

W Pythonie 3.2, masz polecenie interact, które daje Ci dostęp do pełnej przestrzeni poleceń Pythona/ipythona.

 1
Author: alpha_989,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-01 19:53:14

Właściwą, łatwą, fajną i dokładną odpowiedzią na to pytanie jest użycie makra % run z flagą-D.

In [4]: run -d myscript.py
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.        
> /cygdrive/c/Users/mycodefolder/myscript.py(4)<module>()
      2                                                            
      3                        
----> 4 a=1                                            
      5 b=2
 1
Author: Ping,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-20 04:51:04