7 – 11 January was packed with events from the upcoming RootCamp, OSDC and a Puppet webinar to the first company ski trip, plus Python and Ruby tips to boot.
Eva explained unconferences, barcamps and what is to be expected at RootCamp on 24-25 May in Berlin. She also counted down 100 days to the OSDC 2013 with Olivier Renault’s ‘Introduction to Eucalyptus’.
More on events, Martin announced the first German language Puppet webinar on 24 January while Vanessa shared photos from our first Netways skiing trip.
Ronny then reminded us to manage Ruby and gem updates with RVM and Johannes recommended pdb++ for Python debugging.
To close the week, Christian shared good news that Teltonika ModemUSB5/10 now comes with an x64 driver for Windows.
NETWAYS Blog
Besserer Python-Debugger gefällig?
Welcher Python-Programmierer hat sich nicht schon einmal über die kleinen Macken des builtin-debuggers (im folgenden der „Normale“) geärgert oder schmerzlich Syntax-highlightning und TAB-Vervollständigung vermisst? Nun, ich bin so einer und möchte euch deshalb heute pdb++ vorstellen. Einmal installiert ersetzt dieser Debugger den normalen aus der stdlib und wartet mit einigen sehr nützlichen Features auf. mehr lesen…
Der Python Debugger
Das Python-Modul pdb stellt einen interaktiven Debugger für Python-Programme zur Verfügung. Es umfasst den Quelltext in Einzelschritten zu evaluieren, Variablen zu inspizieren, beliebigen Python-Code an jeder Stelle auszuführen und das sogenannte „post-mortem debugging“.
Debugger Starten
Frei nach dem Motto: „viele Wege führen nach Rom“ – gibt es verschiedene Wege den Debugger zu starten. Je nach Bedarf, wo und was zu debuggen ist, entscheidet der Benutzer, wann der Python-Interpreter den Debugger „betritt“.
Von der Kommandozeile
Die Eingabeaufforderung des Debuggers ist (Pdb).
Rufen wir den Debugger von der Kommandozeile aus auf, lädt dieser unser Skript pdb_test.py und stoppt bei der ersten Anweisung:
$ python -m pdb pdb_test.py > .../pdb_test.py(3)() -> def test(): (Pdb)
Im Interpreter
Experimentiert man im interaktiven Interpreter, ist es hilfreich den Debugger auch hier via pdb.run oder pdb.runeval starten zu können:
$ python Python 2.7.2 (default, Oct 27 2011, 01:40:22) [GCC 4.6.1 20111003 (Red Hat 4.6.1-10)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import pdb >>> import pdb_test >>> pdb.run('pdb_test.test()') > <string>(1)<module>() (Pdb)
Im Programm
Die oben genannten Möglichkeiten sind in den meisten Fällen nur dann hilfreich, wenn das entwickelte Programm überschaubar ist oder Probleme schon am Anfang der Ausführung auftreten. Stößt man auf Fehler in größeren Programmen oder erst später in der Ausführung, ist es von Vorteil, den Debugger im Programm zu starten:
#!/usr/bin/env python
import pdb
def test():
pdb.set_trace()
print "Hallo!"
if __name__ == '__main__':
test()
Der Funktionsaufruf pdb.set_trace() in Zeile 6 startet den Debugger, wenn die Instruktion erreicht wird:
$ python pdb_test.py > .../pdb_test.py(7)test() -> print "Hallo!" (Pdb)
Nach einem Fehler
Programme nach einem Fehler zu debuggen, nennt sich „post-mortem debugging“. pdb unterstützt das durch die Funktionen pm() und post_mortem().
class Output(object):
def __init__(self, output):
self.the_output = output
def echo(self):
print self.output
In Zeile 7 versteckt sich ein AttributeError, da wir eigentlich self.the_output ausgeben müssten. Wird die besagte Zeile aufgerufen, stoppt die Ausführung mit dem entsprechenden Fehler. Danach können wir pdb.pm() aufrufen, um den Debugger an der Stelle zu starten, an der die Exception aufgetreten ist:
$ python Python 2.7.2 (default, Oct 27 2011, 01:40:22) [GCC 4.6.1 20111003 (Red Hat 4.6.1-10)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import pdb_test >>> pdb_test.Output("Hallo!").echo() Traceback (most recent call last): File "", line 1, in File "pdb_test.py", line 11, in echo print self.output AttributeError: 'Output' object has no attribute 'output' >>> import pdb >>> pdb.pm() > .../pdb_test.py(11)echo() -> print self.output (Pdb)
Debugger benutzen
Der Debugger versteht einen definierten Satz an Befehlen – alle anderen Anweisungen werden als Python-Code behandelt und im Kontext des Programm ausgeführt. So können sogar Variablen und Funktionen während dem Debugging verändert werden. Die Eingabe einer leeren Zeile wiederholt den letzten eingegeben Befehl.
Navigation
w(here): Anzeigen der Position im call stack und nächste auszuführende Instruktion:
(Pdb) where /usr/lib64/python2.7/bdb.py(387)run() -> exec cmd in globals, locals(1) () > .../pdb_test.py(3) () -> import pdb
l(ist) [start[, ende]]: Auruf ohne Argumente zeigt 5 Zeilen vor und nach der aktuellen Zeile. Mit einem Argument werden 5 Zeilen vor und nach der angegebenen Zeile angezeigt und mit 2 Argumenten der angegebene Bereich:
(Pdb) list 1 #!/usr/bin/env python 2 3 -> import pdb 4 5 class Output(object): 6 7 def __init__(self, output): 8 self.the_output = output 9 10 def echo(self): 11 print self.output (Pdb) l 13 8 self.the_output = output 9 10 def echo(self): 11 print self.output 12 13 if __name__ == '__main__': 14 Output("Hallo!").echo() [EOF] (Pdb) l 5, 14 5 class Output(object): 6 7 def __init__(self, output): 8 self.the_output = output 9 10 def echo(self): 11 print self.output 12 13 if __name__ == '__main__': 14 Output("Hallo!").echo()
u(p), d(own): Aktuelle frame im call stack nach oben (up, älter) oder unten (down, neuer) verschieben:
(Pdb) up > .../pdb_test.py(14)() -> Output("Hallo!").echo() (Pdb) d > .../pdb_test.py(11)echo() -> print self.output
Schrittweise Ausfhüren
s(step): Führt die aktuelle Zeile aus und stoppt bei der nächsten aufzurufenden Funktion oder Zeile in der aktuellen Sequenz:
(Pdb) ... > .../pdb_test.py(14)() -> Output("Hallo!").echo() (Pdb) s --Call-- > .../pdb_test.py(7)__init__() -> def __init__(self, output):
n(ext): Verhält sich ähnlich wie step, stoppt aber nicht bei Funktionen die von der auszuführenden Anweisung aufgerufen werden:
(Pdb) ... > .../pdb_test.py(14)() -> Output("Hallo!").echo() (Pdb) n AttributeError: "'Output' object has no attribute 'output'" > /tmp/pdb_test.py(14) () -> Output("Hallo!").echo()
r(eturn): Stoppt bei der nächsten return-Anweisung:
#!/usr/bin/env/python
import random
def randint(a, b):
random_int = random.randint(a, b)
return random_int
if __name__ == '__main__':
random.seed()
print randint(0, 100)
(Pdb) ... > .../pdb_return.py(11)() -> print randint(0, 100) (Pdb) s --Call-- > .../pdb_return.py(5)randint() -> def randint(a, b): (Pdb) r --Return-- > .../pdb_return.py(7)randint()->58 -> return random_int
Variablen überprüfen
a(rgs): Zeigt die Argumente der aktuellen Funktion und
p expression: Evaluiert expression und zeigt dessen Ausgabe, zum Beispiel den Wert einer Variable:
(Pdb) ... > .../pdb_return.py(11)() -> print randint(0, 100) (Pdb) s --Call-- > .../pdb_return.py(5)randint() -> def randint(a, b): (Pdb) r --Return-- > .../pdb_return.py(7)randint()->24 -> return random_int (Pdb) args a = 0 b = 100 (Pdb) p random_int 24
Natürlich unterstützt der Debugger auch Breakpoints und jump – dazu schreibe ich vielleicht etwas in einem zweiten Teil.
Weiterführende Informationen sind in der Python Dokumentation und den absolut genialen Abhandlungen von Doug Hellmann, namens Python Module of the Week, zu finden, dessen Gliederung ich hier mal ganz frei übernommen habe.