Tipps zum Python-Debuggen

Tipps zum Python-Debuggen

Dieser Artikel ist der Artikel zum 24. Tag von Python Advent Calendar 2016. Hier sind einige Tipps zum Debuggen von Python.

Debuggen mit print ()

Debuggen Sie, indem Sie den Wert, den Sie überprüfen möchten, mit der Funktion print () in stdout drucken. Wenn dies das Problem löst, ist es besser.

Debuggen Sie FizzBuzz. Angenommen, Sie möchten diesmal FizzBuzz mit einer Zahl von 1 bis 20 ausgeben. Der folgende Code hat einen offensichtlichen Fehler. Verstehst du?

example_fizzbuzz_buggy.py::

for ii in range(1, 21):
    if ii % 3 == 0:
        print('Fizz')
    elif ii % 5 == 0:
        print('Buzz')
    elif ii % 15 == 0:
        print('FizzBuzz')
    else:
        print(ii)

Wenn Sie dies tun, zeigt example_fizzbuzz.py die folgende Meldung an:

$ python example_fizzbuzz.py
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz
16
17
Fizz
19
Buzz

Irgendwas stimmt nicht. Es gibt keinen Hinweis auf "FizzBuzz". Für 15 sollten Sie FizzBuzz sehen. Fügen wir print () hinzu, um das Verhalten bei 15 zu sehen.

for ii in range(1, 21):
    print('CURRENT: {}'.format(ii))  #hinzufügen
    if ii % 3 == 0:
        print('Fizz')
    elif ii % 5 == 0:
        print('Buzz')
    elif ii % 15 == 0:
        print('HIT')  #hinzufügen
        print('FizzBuzz')
    else:
        print(ii)

Die mit "add" kommentierte Zeile ist der hinzugefügte print (). Ich habe den Code hinzugefügt, um die folgende Debug-Nachricht auszugeben.

Machen wir das.

$ python  example_fizzbuzz.py
CURRENT: 1
1
CURRENT: 2
2
CURRENT: 3
Fizz
CURRENT: 4
4
CURRENT: 5
Buzz
CURRENT: 6
Fizz
CURRENT: 7
7
CURRENT: 8
8
CURRENT: 9
Fizz
CURRENT: 10
Buzz
CURRENT: 11
11
CURRENT: 12
Fizz
CURRENT: 13
13
CURRENT: 14
14
CURRENT: 15
Fizz
CURRENT: 16
16
CURRENT: 17
17
CURRENT: 18
Fizz
CURRENT: 19
19
CURRENT: 20
Buzz

Wenn "CURRENT: 15" angezeigt wird, wird "Fizz" angezeigt und "HIT" wird nicht angezeigt. Dies bedeutet, dass wir den Block von "if ii% 3 == 0:" und nicht den Block von "elif ii% 15 == 0:" ausführen. Wenn ii 15 ist, ist es natürlich durch 3 teilbar, also "wenn ii% 3 == 0:" wahr ist und das "elif ii% 15 == 0:", nachdem es nicht ausgeführt wurde, weil es "elif" ist. .. Ich fand, dass ii% 15 == 0 vor anderen Bedingungen verzweigen musste, also werde ich den Code korrigieren.

$ python example_fizzbuzz.py
CURRENT: 1
1
CURRENT: 2
2
CURRENT: 3
Fizz
CURRENT: 4
4
CURRENT: 5
Buzz
CURRENT: 6
Fizz
CURRENT: 7
7
CURRENT: 8
8
CURRENT: 9
Fizz
CURRENT: 10
Buzz
CURRENT: 11
11
CURRENT: 12
Fizz
CURRENT: 13
13
CURRENT: 14
14
CURRENT: 15
HIT
FizzBuzz
CURRENT: 16
16
CURRENT: 17
17
CURRENT: 18
Fizz
CURRENT: 19
19
CURRENT: 20
Buzz

Wenn es 15 ist, werden "HIT" und "FizzBuzz" angezeigt. Hört sich gut an. Der Fehler wurde entfernt. Löschen Sie danach das zuvor hinzugefügte print (). Der endgültige Code sieht folgendermaßen aus:

example_fizzbuzz.py::

for ii in range(1, 21):
    if ii % 15 == 0:
        print('FizzBuzz')
    elif ii % 3 == 0:
        print('Fizz')
    elif ii % 5 == 0:
        print('Buzz')
    else:
        print(ii)

Diese Technik wird üblicherweise in jeder Programmiersprache verwendet. Und es ist leicht zu vergessen, den letzten Druck zu löschen (). Vergiss nicht, es zu löschen.

Überprüfen Sie das Verhalten des Programms zeilenweise mit pdb

Beim Debuggen mit print () habe ich die Funktionsweise des Programms überprüft, indem ich eine Debug-Nachricht an stdout gedruckt habe. Ein einfaches Programm kann mit dem Prozess Schritt halten, aber wenn es komplizierter wird, wird es schwierig, die Bewegung allein anhand der Debug-Nachricht zu verstehen. Wenn Sie pdb verwenden, können Sie das Programm ausführen, während Sie es zeilenweise überprüfen, und Sie können den Wert der Variablen zu diesem Zeitpunkt überprüfen, sodass Sie den Wert des Programms genauer überprüfen können. Es wird einfacher sein, den Prozess zu verfolgen.

Führen Sie nun den Buggy "example_fizzbuzz_buggy.py" mit pdb aus. Da pdb eine Standardbibliothek ist, müssen Sie sie nicht mit pip installieren.

$ python -m pdb example_fizzbuzz_buggy.py
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(1)<module>()
-> for ii in range(1, 21):
(Pdb)

Fügen Sie dem Python-Argument -m pdb hinzu. Das von pdb ausgeführte Skript stoppt bei dem zuerst auszuführenden Code und wartet auf die Eingabe. Führen Sie den Debugger aus, indem Sie hier den Befehl pdb angeben und ENTER eingeben. Details zum Befehl pdb werden in 27.3. Pdb - Python Debugger - Python 3.5.2-Dokumentation erläutert.

Geben Sie n (was als nächstes bedeutet) ein, um Zeile für Zeile auszuführen.

(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb)

pdb lief eine Zeile und zeigte die nächste auszuführende Zeile an.

Das zu diesem Zeitpunkt angezeigte > /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py (2) <module> () hat das folgende Format.

> Dateipfad (Anzahl der ausgeführten Zeilen) Funktionsname ()

Da es sich diesmal nicht um eine Funktion handelt, wird der Funktionsname als "" angezeigt. (Zeigt tatsächlich den Wert von \ _ \ _ name \ _ \ _ an.)

Wenn nur ENTER (kein Befehl angegeben), wird der vorherige pdb-Befehl ausgeführt. Wenn Sie daher eine andere Zeile verarbeiten möchten, geben Sie ENTER ein.

(Pdb)
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(4)<module>()
-> elif ii % 5 == 0:
(Pdb)

Mit l (Bedeutungsliste) können Sie sehen, wo die Leitung gerade läuft.

(Pdb) l
  1     for ii in range(1, 21):
  2         if ii % 3 == 0:
  3             print('Fizz')
  4  ->     elif ii % 5 == 0:
  5             print('Buzz')
  6         elif ii % 15 == 0:
  7             print('FizzBuzz')
  8         else:
  9             print(ii)
[EOF]
(Pdb)

Die nächste mit -> gekennzeichnete Zeile wird ausgeführt. Wenn Sie statt Zeile für Zeile fortfahren möchten, geben Sie c an (dh weiter).

(Pdb) c
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz
16
17
Fizz
19
Buzz
The program finished and will be restarted
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(1)<module>()
-> for ii in range(1, 21):

Ich habe das Programm bis zum Ende ausgeführt. Wenn das Programm bis zum Ende verarbeitet ist, druckt pdb "Das Programm ist beendet und wird neu gestartet" und führt das Programm erneut aus.

Wenn Sie die Verarbeitung durch Angabe der Anzahl der Zeilen beenden möchten, verwenden Sie einen Haltepunkt. Um die Verarbeitung zu überprüfen, wenn ii 15 ist, verwenden Sie den Befehl b (dh break), um den Haltepunkt in der zweiten Zeile festzulegen, die zuerst in der if-Anweisung verzweigt.

(Pdb) b 2
Breakpoint 1 at /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py:2
(Pdb)

Dadurch wird das Programm angehalten, bevor die zweite Zeile verarbeitet wird. Fahren wir mit dem Befehl c fort.

(Pdb) c
1
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb)

Es hat aufgehört. Verwenden Sie den Befehl p (dh Drucken), um den Wert von ii zu ermitteln.

(Pdb) p ii
2
(Pdb)

Es ist 2. Ich möchte die Verarbeitung bei 15 überprüfen, also lassen Sie uns c 13 noch mehrmals ausführen.

(Pdb) c
2
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Fizz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
4
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Buzz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Fizz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
7
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
8
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Fizz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Buzz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
11
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
Fizz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
13
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) c
14
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) p ii
15
(Pdb)

Oben wurde c viele Male eingegeben, aber Sie können auch die Bedingungen zum Stoppen festlegen. Dieses Mal möchte ich, dass Sie aufhören, wenn ii 15 ist. Geben Sie daher die Bedingungen wie folgt an.

(Pdb) b 2, ii == 15
Breakpoint 3 at /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py:2
(Pdb)

Und wenn Sie c ausführen, wird es erst gestoppt, wenn ii 15 ist, sodass Sie c nicht mehrmals eingeben müssen.

(Pdb) c
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(2)<module>()
-> if ii % 3 == 0:
(Pdb) p ii
15
(Pdb)

Führen Sie danach n Zeile für Zeile aus und überprüfen Sie die Operation.

(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(3)<module>()
-> print('Fizz')
(Pdb) n
Fizz
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(1)<module>()
-> for ii in range(1, 21):
(Pdb)

Sie können sehen, dass die for-Anweisung in der ersten Zeile nach der Ausführung der dritten Zeile verarbeitet wird (dh, die elif ii% 15 == 0: in der sechsten Zeile wird nicht verarbeitet).

(Pdb) list
  1  -> for ii in range(1, 21):
  2 B       if ii % 3 == 0:
  3             print('Fizz')
  4         elif ii % 5 == 0:
  5             print('Buzz')
  6         elif ii % 15 == 0:
  7             print('FizzBuzz')
  8         else:
  9             print(ii)
[EOF]
(Pdb)

Da "ii% 3 == 0" wahr ist, wenn ii 15 ist, habe ich pdb verwendet, um zu bestätigen, dass dieses if-elif-else nicht richtig funktioniert, wenn es 15 ist.

(Pdb) p ii
15
(Pdb) p ii % 3 == 0
True
(Pdb)

Haltepunkte werden mit cl gelöscht (was klar bedeutet).

(Pdb) cl
Clear all breaks? yes
Deleted breakpoint 3 at /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py:2
(Pdb)

Geben Sie s (Bedeutungsschritt) an, um die Verarbeitung der aufgerufenen Funktion zu überprüfen.

example_fizzbuzz_buggy2.py::

def fizzbuzz(num):
    if ii % 3 == 0:
        print('Fizz')
    elif ii % 5 == 0:
        print('Buzz')
    elif ii % 15 == 0:
        print('FizzBuzz')
    else:
        print(ii)

for ii in range(1, 21):
    fizzbuzz(ii)

Versuchen Sie, die Funktion fizzbuzz mit example_fizzbuzz_buggy2.py aufzurufen.

$ python -m pdb example_fizzbuzz_buggy2.py
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(1)<module>()
-> def fizzbuzz(num):
(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(11)<module>()
-> for ii in range(1, 21):
(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(12)<module>()
-> fizzbuzz(ii)
(Pdb) p ii
1

Bisher fahren wir mit den zuvor erläuterten Inhalten bis zum Aufruf von fizzbuzz () in der 12. Zeile fort.

Geben Sie als Nächstes s an, um den Prozess in fizzbuzz () zu stoppen.

(Pdb) s
--Call--
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(1)fizzbuzz()
-> def fizzbuzz(num):
(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(2)fizzbuzz()
-> if ii % 3 == 0:
(Pdb)
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(4)fizzbuzz()
-> elif ii % 5 == 0:

Geben Sie r (bedeutet return) an, um zum Ende der Funktion fizzbuzz () zu gelangen.

(Pdb) r
1
--Return--
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(9)fizzbuzz()->None
-> print(ii)
(Pdb) n
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy2.py(11)<module>()
-> for ii in range(1, 21):

fizzbuzz () -> None gibt an, dass fizzbuzz () None zurückgegeben hat.

Schreiben Sie "import pdb; pdb.set_trace ()" in Ihren Code

Ich habe mit python -m pdb gearbeitet, um pdb zu verwenden, aber jetzt muss ich die Boot-Optionen ändern. Auf diese Weise können Sie pdb nicht verwenden, wenn Sie ein Startskript schreiben oder Python nicht direkt aufrufen.

pdb liefert dafür set_trace (). Wenn set_trace () aufgerufen wird, wechselt es in den pdb-Debug-Modus und wartet auf Befehle.

Setzen Sie set_trace () in example_fizzbuzz_buggy.py.

example_fizzbuzz_buggy.py::

for ii in range(1, 21):
    if ii % 3 == 0:
        print('Fizz')
    elif ii % 5 == 0:
        import pdb; pdb.set_trace()  #hinzufügen
        print('Buzz')
    elif ii % 15 == 0:
        print('FizzBuzz')
    else:
        print(ii)

Import pdb; pdb.set_trace () in Zeile 5 hinzugefügt. Führen Sie example_fizzbuzz_buggy.py aus, geben Sie diesmal jedoch nicht -m pdb an.

$ python  example_fizzbuzz_buggy.py
1
2
Fizz
4
> /working/advent-calendar-2016-python/example_fizzbuzz_buggy.py(6)<module>()
-> print('Buzz')
(Pdb)

Es blieb an der 6. Linie stehen.

(Pdb) l
  1     for ii in range(1, 21):
  2         if ii % 3 == 0:
  3             print('Fizz')
  4         elif ii % 5 == 0:
  5             import pdb; pdb.set_trace()
  6  ->         print('Buzz')
  7         elif ii % 15 == 0:
  8             print('FizzBuzz')
  9         else:
 10             print(ii)
[EOF]
(Pdb)

Die Verarbeitung wird in der Zeile nach set_trace () gestoppt. Mit dieser Methode können Sie pdb starten, ohne die Startoptionen zu ändern.

Dieser Debug-Code muss am Ende des Debugs entfernt werden. Wenn Sie vergessen, es zu löschen, startet pdb und wartet während des Produktionsvorgangs auf Eingaben. Im Gegensatz zum Debuggen mit print () gibt es immer echten Schaden. Wir empfehlen, mit Git-Commit-Hooks und CI-Tests auf PDF-Kontamination zu prüfen.

import pdb; pdb.set_trace () hat zwei Anweisungen, eine ist eine import-Anweisung. Normalerweise ist es vorzuziehen, die Importanweisung am Anfang der Datei zu schreiben. Dieser Debug-Code muss also am Ende des Debuggens gelöscht werden Es wird in eine Zeile geschrieben, um die Anzahl der zu löschenden Zeilen zu verringern. Dies wird auch in der offiziellen Python-Dokumentation vorgestellt. Es ist üblich, es in einer Zeile zu schreiben.

Debuggen mit ipdb

ipdb ist eine Bibliothek, die die Funktionalität von pdb mithilfe von IPython erweitert.

ipdb wird mit pip installiert.

$ pip install ipdb

Geben Sie zunächst "-m ipdb" als Python-Startoption an oder schreiben Sie "import ipdb; ipdb.set_trace ()" in Ihren Code. Der Code ist hervorgehoben und leicht zu sehen.

スクリーンショット 2016-12-24 20.52.10.png

Sie können die Attributliste anzeigen, indem Sie auf die Registerkarte klicken.

スクリーンショット 2016-12-24 20.52.34.png

Davon abgesehen entspricht die Verwendung fast der von pdb.

Debuggen mit bpdb

bpdb ist eine Bibliothek, die die Funktionalität von pdb mithilfe von BPython erweitert. Dies wird als Funktion von BPython selbst bereitgestellt.

bpdb installiert bpython mit pip.

$ pip install bpython

Geben Sie zunächst "-m bpdb" als Python-Startoption an oder schreiben Sie "import bpdb; bpdb.set_trace ()" in Ihren Code. Es verhält sich wie pdb, aber wenn Sie "B" eingeben, wird BPython im aktuellen Stapelrahmen gestartet.

スクリーンショット 2016-12-24 21.16.30.png

Das Ende von BPython ist "C-d".

Debuggen mit pudb

PuDB ist ein Hochleistungsdebugger, der auf der Konsole verwendet werden kann.

Es installieren.

pip install pudb

Nach der Installation können Sie den Befehl pudb3 (für Python3) verwenden. Geben Sie zunächst den Dateipfad an, den Sie in pudb3 ausführen möchten.

$ pudb3 example_fizzbuzz_buggy.py

Der Debugger-Bereich entspricht der Arbeit mit pdb. Sie können "C-x" verwenden, um zwischen dem Debugger-Bereich und dem interaktiven Shell-Bereich zu wechseln.

スクリーンショット 2016-12-25 0.15.41.png

Sie können das Thema usw. festlegen und die Einstellungswerte werden in ~ / .config / pudb / pudb.cfg gespeichert.

~/.config/pudb/pudb.cfg::

[pudb]
breakpoints_weight = 1
current_stack_frame = top
custom_stringifier =
custom_theme =
display = auto
line_numbers = True
prompt_on_quit = True
seen_welcome = e027
shell = classic
sidebar_width = 0.5
stack_weight = 1
stringifier = type
theme = dark vim
variables_weight = 1
wrap_variables = True

Debuggen mit PyCharm

PyCharm ist eine von JetBrains entwickelte Python-IDE. Sie können den Debugger mit GUI-Operationen betreiben. Es ist sehr intuitiv und wunderbar. Sie können das Installationsprogramm von https://www.jetbrains.com/pycharm/download/ herunterladen.

Öffnen Sie die Datei und versuchen Sie, einen Haltepunkt festzulegen.

スクリーンショット 2016-12-25 0.37.53.png

Wenn Sie auf die rechte Seite der Zeilennummernanzeige klicken, wird ein roter Kreis angezeigt. Dies ist der Debugger. Es ist das gleiche wie VS oder Eclipse.

Führen Sie über das Menü [Ausführen]> [Debuggen](oder Fehlermarkierung) aus )Klicken.

スクリーンショット 2016-12-25 0.41.05.png

Fehlerzeichen

スクリーンショット 2016-12-25 0.41.26.png

Wenn es ausgeführt wird, stoppt es am Haltepunkt und die Stapelrahmen und Variablen werden im Bereich angezeigt.

スクリーンショット 2016-12-25 0.38.40.png

Da das Symbol für detaillierte Vorgänge aktiviert ist, können Sie es durch Klicken bedienen. Wenn Sie mit der Maus darüber fahren, wird das zu erledigende Symbol angezeigt.

スクリーンショット 2016-12-25 0.42.37.png

Sie können die Remote-Debug-Funktion auch in der Professional Edition verwenden.

Debuggen in verschiedenen Szenen

Wenn Sie den Debugger mit unittest verwenden möchten

Wenn Sie in unittest einen Fehler erhalten, aber die Ursache nicht kennen, sollten Sie mit Testcode debuggen. In diesem Fall können Sie "pdb.set_trace ()" in den Testcode einfügen und pdb starten.

Der folgende Testcode startet beispielsweise pdb, wenn der Test ausgeführt wird.

test_main.py::

from unittest import TestCase


def create_message(count):
    return 'Fish: {}'.format(count)


class SimpleTest(TestCase):
    def test_it(self):
        import pdb; pdb.set_trace()  #Debug-Code
        msg = create_message(1)
        self.assertEqual(msg, 'Fish: 1')

Wenn Sie unittest ausführen, wird pdb gestartet.

$ python -m unittest
> /working/advent-calendar-2016-python/test_main.py(11)test_it()
-> msg = create_message(1)
(Pdb) list
  6
  7
  8     class SimpleTest(TestCase):
  9         def test_it(self):
 10             import pdb; pdb.set_trace()  #Debug-Code
 11  ->         msg = create_message(1)
 12             self.assertEqual(msg, 'Fish: 1')
[EOF]
(Pdb)

Wenn Sie den Debugger mit Nase verwenden möchten

Nase ist ein beliebtes Testframework. Geben Sie "--nocapture" an, wenn der Test wie zuvor mit pdb vorzeitig gestoppt werden soll.

$ nosetests --nocapture
> /working/advent-calendar-2016-python/test_main.py(11)test_it()
-> msg = create_message(1)
(Pdb)

Es bietet auch "--pdb", "--pdb-Fehler" und "--pdb-Fehler", um pdb im Falle eines Fehlers oder Fehlers zu starten.

$ nosetests --pdb
> /Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/unittest/case.py(665)fail()
-> raise self.failureException(msg)
(Pdb)

In der Nasen-Dokumentation heißt es: "Warnung Nase selbst unterstützt Python 3, viele Plugins von Drittanbietern jedoch nicht!" Es scheint, dass die Python3-Unterstützung des Nasen-Plugins nicht erweitert ist, nicht die Nase selbst.

Wenn Sie den Debugger mit pytest verwenden möchten

pytest ist auch ein beliebtes Testframework wie die Nase. Wenn Sie pytest so ausführen, wie es ist, wird pdb gestartet, wenn set_trace () ausgeführt wird.

$ pytest
================================================================================ test session starts ================================================================================
platform darwin -- Python 3.5.2, pytest-3.0.5, py-1.4.32, pluggy-0.4.0
rootdir: /working/advent-calendar-2016-python, inifile:
plugins: celery-4.0.0
collected 1 items

test_main.py
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /working/advent-calendar-2016-python/test_main.py(11)test_it()
-> msg = create_message(1)
(Pdb)

Sie können den Debugger bei einem Fehler starten, indem Sie "--pdb" angeben.

$ pytest --pdb
================================================================================ test session starts ================================================================================
platform darwin -- Python 3.5.2, pytest-3.0.5, py-1.4.32, pluggy-0.4.0
rootdir: /working/advent-calendar-2016-python, inifile:
plugins: celery-4.0.0
collected 2 items

test_main.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

self = <test_main.SimpleTest testMethod=test_error>

    def test_error(self):
        msg = create_message(1)
>       self.assertEqual(msg, 'ERROR')
E       AssertionError: 'Fish: 1' != 'ERROR'
E       - Fish: 1
E       + ERROR

test_main.py:15: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/unittest/case.py(665)fail()
-> raise self.failureException(msg)
(Pdb)

Wenn Sie einen Debugger mit Django verwenden möchten

Django ist ein beliebtes Webframework. Verwenden von pdb mit Django Wenn es sich um einen Entwicklungsserver handelt (manage.py runserver), ist nichts schwierig.

Erstellen Sie ein Projekt und starten Sie pdb.

Die Struktur des Projekts ist wie folgt.

$ tree proj
proj
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

Das proj / urls.py ist wie folgt geschrieben.

from django.conf.urls import url
from django.http import HttpResponse


def top_view(request):
    import pdb; pdb.set_trace()
    return HttpResponse('OK')

urlpatterns = [
    url(r'^$', top_view),
]

Wir haben eine Ansicht definiert, die beim Zugriff auf "/" eine Anfrage mit "OK" zurückgibt. (Da es schwierig war, die Datei zu teilen, wird die Ansicht auch in urls.py beschrieben.) Pdb.set_trac () wird in der View-Funktion beschrieben.

Starten Sie den Entwicklungsserver mit runserver.

$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
December 24, 2016 - 13:45:26
Django version 1.11.dev20161224024349, using settings 'proj.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Senden Sie eine Anfrage an die URL.

$ curl http://127.0.0.1:8000/

Der Entwicklungsserver startet pdb mit pdb.set_trace () und wartet auf Eingabe.

> /working/advent-calendar-2016-python/proj/urls.py(7)top_view()
-> return HttpResponse('OK')
(Pdb)

Alles was Sie tun müssen, ist zu debuggen. Sie können auch den Inhalt des Anforderungsobjekts überprüfen. Andere WAFs können häufig auch mit pdb debuggt werden.

Wenn Sie den Debugger mit Gunicorn verwenden möchten

gunicorn ist ein beliebter WSGI-HTTP-Server. Führen Sie das Django-Projekt früher unter gunicorn aus.

$ gunicorn proj.wsgi:application
[2016-12-24 22:53:59 +0900] [8915] [INFO] Starting gunicorn 19.6.0
[2016-12-24 22:53:59 +0900] [8915] [INFO] Listening at: http://127.0.0.1:8000 (8915)
[2016-12-24 22:53:59 +0900] [8915] [INFO] Using worker: sync
[2016-12-24 22:53:59 +0900] [8918] [INFO] Booting worker with pid: 8918

Senden Sie eine Anfrage an die URL.

$ curl http://127.0.0.1:8000/

pdb.set_trace () startet pdb.

> /working/advent-calendar-2016-python/proj/urls.py(7)top_view()
-> return HttpResponse('OK')
(Pdb)

Es ist dasselbe wie der Django-Entwicklungsserver.

Achten Sie auf Auszeiten

Gunicorn hat eine Einstellung zum Zeitlimit für die Anforderung, die standardmäßig 30 Sekunden beträgt. Zeigen Sie (Pdb) [2016-12-24 23:09:37 +0900] [9102] [CRITICAL] WORKER TIMEOUT (pid: 9115) an, während Sie pdb starten und debuggen Wenn pdb beendet wird, wird die Anforderung als Zeitüberschreitung behandelt. Legen Sie daher mit "--timeout" einen großen Zeitüberschreitungswert fest und führen Sie ihn aus.

$ gunicorn proj.wsgi:application --timeout 9999999
[2016-12-24 23:13:11 +0900] [9126] [INFO] Starting gunicorn 19.6.0
[2016-12-24 23:13:11 +0900] [9126] [INFO] Listening at: http://127.0.0.1:8000 (9126)
[2016-12-24 23:13:11 +0900] [9126] [INFO] Using worker: sync
[2016-12-24 23:13:11 +0900] [9130] [INFO] Booting worker with pid: 9130
> /working/advent-calendar-2016-python/proj/urls.py(7)top_view()
-> return HttpResponse('OK')
(Pdb)

Wenn Sie einen Debugger mit Sellerie verwenden möchten

Sellerie ist eine häufig verwendete Aufgabenwarteschlange. Ich werde Redis dieses Mal als Broker verwenden, also starte es.

$ nohup redis-server 2>&1 > /dev/null &
[1] 9384

Erstellen Sie die Datei task.py und definieren Sie die Aufgabe add (). Dieses Mal möchten wir diese add () - Task debuggen.

tasks.py::

from celery import Celery

app = Celery('tasks', broker='pyamqp://guest@localhost//')

@app.task
def add(x, y):
    import pdb; pdb.set_trace()
    return x + y

Starten Sie den Arbeiter.

$ celery -A tasks.app worker

 -------------- [email protected] v4.0.0 (latentcall)
---- **** -----
--- * ***  * -- Darwin-16.1.0-x86_64-i386-64bit 2016-12-24 23:23:27
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app:         tasks:0x1042b4940
- ** ---------- .> transport:   redis://127.0.0.1:6379//
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery

Feuern Sie die Aufgabe in einem anderen Terminal ab.

>>> import tasks
>>> tasks.add.delay(1, 2)
<AsyncResult: a07399f4-e28a-4471-b57d-30ce1cb3abf4>
>>>

Ich erhalte eine bdb.BdbQuit-Ausnahme in einem Terminal, in dem ein Worker ausgeführt wird.

[2016-12-24 23:24:50,006: WARNING/PoolWorker-4] > /working/advent-calendar-2016-python/tasks.py(9)add()
-> return x + y
[2016-12-24 23:24:50,007: WARNING/PoolWorker-4](Pdb)
[2016-12-24 23:24:50,061: ERROR/PoolWorker-4] Task tasks.add[a07399f4-e28a-4471-b57d-30ce1cb3abf4] raised unexpected: BdbQuit()
Traceback (most recent call last):
  File "/Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/site-packages/celery/app/trace.py", line 368, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/site-packages/celery/app/trace.py", line 623, in __protected_call__
    return self.run(*args, **kwargs)
  File "/working/advent-calendar-2016-python/tasks.py", line 9, in add
    return x + y
  File "/working/advent-calendar-2016-python/tasks.py", line 9, in add
    return x + y
  File "/Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/bdb.py", line 48, in trace_dispatch
    return self.dispatch_line(frame)
  File "/Users/sximada/ng2/var/lib/miniconda3/envs/py3.5.2/lib/python3.5/bdb.py", line 67, in dispatch_line
    if self.quitting: raise BdbQuit
bdb.BdbQuit

Das Debuggen von Sellerie finden Sie unter http://docs.celeryproject.org/en/latest/userguide/debugging.html. Sie können pdb nicht unverändert verwenden. Sie müssen celery.contrib.rdb verwenden und den Debugger über Telnet verwenden. Ändern Sie die Datei task.py.

tasks.py::

from celery import Celery
from celery.contrib import rdb

app = Celery('tasks', broker='redis://127.0.0.1/')


@app.task
def add(x, y):
    rdb.set_trace()
    return x + y

Die Aufgabe neu entzünden.

>>> import tasks
>>> tasks.add.delay(1,2)
<AsyncResult: 42b88871-a679-492f-bfc9-1f86043dab33>
>>>

Der Worker zeigt dann die Meldung "Remote Debugger: 6900: Warten auf Client ..." an. Greifen Sie mit Telnet auf diese Portnummer zu.

$ telnet 127.0.0.1 6900
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
> /working/advent-calendar-2016-python/tasks.py(10)add()
-> return x + y
(Pdb) p x
1
(Pdb) p y
2
(Pdb)

pdb wartet auf Eingabe. Der Rest ist der gleiche wie der Betrieb von pdb. Der Worker schließt den Port, wenn die Aufgabe abgeschlossen ist. Wenn Sie es mehrmals ausführen, müssen Sie jedes Mal eine neue Verbindung mit Telnet herstellen.

Im Fall von Sellerie ist add (1, 2) eine normale Funktionsausführung, daher ist es auch eine gute Idee, damit zu debuggen. Der Code von Celery wird jedoch weiterhin ausgeführt. Wenn Sie ihn also für die Ausführung als Funktion vorbereiten, die keine Aufgabe ist, Es ist einfacher zu isolieren, ob es sich um ein Sellerieproblem handelt.

Wenn Sie den Debugger mit Jupyter Notebook verwenden möchten

Das Jupyter-Notizbuch bietet einen magischen Befehl "% debug", mit dem Sie pdb starten können. Das Folgende ist das Debuggen von request.get ('http://example.com') mit pdb.

スクリーンショット 2016-12-25 0.05.23.png

Wenn Sie den Debugger mit CircleCI verwenden möchten

Circle CI ist ein beliebter CI-Dienst. Manchmal schlägt ein Test auf Circle CI fehl und die Ursache kann nicht ermittelt werden. In diesem Fall können Sie, wenn Sie zum Erstellen "Mit SSH neu erstellen" auswählen, SSH in den Build-Container einfügen und das Verhalten überprüfen.

スクリーンショット 2016-12-24 22.20.56.png

Ich klone das Repository in mein Home-Verzeichnis, also füge ich dort "pdb.set_trace ()" in den Code ein Durch manuelles Ausführen des Tests können Sie die Fehlerursache leichter ermitteln.

Wenn Sie den Debugger in der Staging-Umgebung verwenden möchten

Dies ist nicht auf Python beschränkt. Wenn Sie jedoch eine Staging-Umgebung haben, in der Sie sich mit ssh anmelden können, Sie möchten pdb in einer Staging-Umgebung ausführen, oder?

Zum Beispiel für eine Django-Anwendung Schreiben Sie pdb.set_trace () beim Staging und starten Sie den Entwicklungsserver manuell mit einer entsprechenden Portnummer. Es ist schnell und einfach, eine Verbindung zum Entwicklungsserver mit SSH-Port vorwärts herzustellen.

[staging]$ python manage.py runserver 4649

Verbinden Sie localhost: 8000 mit Staging: 4649 mit ssh-Port vorwärts.

$ ssh -L 8000:localhost:4649 staging

Senden Sie dann die Anfrage, als würden Sie auf localhost testen.

Wenn Sie einen Debugger in einer Produktionsumgebung verwenden möchten

Lass uns absolut aufhören. Ich habe einen Unfall (Erklärung). Wenn Sie eine RC-Umgebung haben, können Sie dies tun, aber Wenn Sie jedoch nicht genau aufpassen, können Sie es nicht sehen.

Recommended Posts

Tipps zum Python-Debuggen
Python-Tipps
Python-Tipps
Python-Tipps
Python Conda Tipps
Python DS-Debugging
Python-Klick-Tipps
Unerwartet (?) Python Bean Wissen
Python- und Numpy-Tipps
[Python] Super nützliches Debugging
Python-Tipps (mein Memo)
Tipps zur Installation von Python PyTorch
[Python] Effizienteres Debuggen!
Tipps zum Nachdenken über np.newaxis in Python / Numpy
Python
Debuggen mit pdb in Python
Empfangen von Standardeingabetipps @ python
[Tipps] Behandle Athena mit Python
[Python + Selen] Tipps zum Scraping
Python | Jupyter> Post-Mortem-Debugging | pdb.post_mortem ()
Google Drive API-Tipps (Python)
~ Tipps für Python-Anfänger mit Liebe von Pythonista ③ ~
Vollständiges Verständnis des Python-Debuggens
Tipps zur Eingabe / Ausgabe von Python-Dateien
[TouchDesigner] Tipps für die Anweisung von Python
Tipps zum Aufrufen von Python von C.
Schreiben Sie Python-Liste schnell vim Tipps
Tipps zum Ersetzen und Debuggen von Funktionen
Kafka Python
Python-Grundlagen ⑤
Python-Zusammenfassung
Eingebaute Python
Python-Einschlussnotation
Python-Technik
Python 2.7 Countdown
Python-Memorandum
Python FlowFishMaster
Python-Dienst
Tipps, um das Lesen von Python-Hördokumenten zu vereinfachen
Python-Funktion ①
Python-Grundlagen
Python-Memo
Ufo-> Python (3)
Python-Einschlussnotation
Jupyters Trick 4
Installieren Sie Python
Python Singleton
Python-Grundlagen ④
Python-Memorandum 2
Python-Memo
Python Jinja2
Python-Inkrement
atCoder 173 Python
[Python] -Funktion
Python-Installation
numpy tipps