Seite wählen

NETWAYS Blog

Weekly Snap: PuppetConf Photos, Shell File Transfers & SQL Triggers

weekly snap19 – 23 August shared Shell and SQL tips, and impressions from the OSMC past, PuppetConf of the present and OpenNebula Conf to come.
Eva began by counting 67 days to the OSMC 2013 with Team Icinga’s presentation from last year.
She went on to remind interested participants to book their tickets for the OpenNebula Conf on 24 – 26 September and snap up the remaining gold packages for accommodation at the conference hotel.
Marius G then discovered how to transfer files via Shell and Python while Matthias demonstrated the power of SQL triggers.
To close the week, Tobias played his third round of IT buzzword bingo as Bernd reported live from PuppetConf 2013 in San Francisco with his impressions of the first day.

PostgreSQL bulk inserts mit Python

Wer oft viele Daten in seine PostgreSQL Datenbank schreibt, dem möchte ich den COPY-Befehl ans Herz legen. Damit können Daten zwischen Dateien und Tabellen kopiert werden. Mit Psycopg2, „dem“ PostgreSQL-Datenbankadapter für Python, sieht das dann ungefähr so aus:

import psycopg2
from cStringIO import StringIO
from itertools import imap
rows = [
    # Wert Spalte A, Wert Spalte B
    [1, 1],
    [2, 2],
    [3, None]
    # ...
]
buff = StringIO()
for row in rows:
    # \t ist standardmäßig der Spaltentrenner und join erwartet string
    print >>buff, "\t".join(imap(str, row))
# Nicht vergessen ;)
buff.seek(0)
with psycopg2.connect('...') as conn:
    with conn.cursor() as cursor:
        # None als NULL senden
        cursor.copy_from(buff, 'Tabelle', null='None')

Dass das ganze echt schnell ist, muss mir an dieser Stelle einfach geglaubt werden ;-).

Eric Lippmann
Eric Lippmann
CTO

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.

coverage.py in Jenkins integrieren

Nachdem bereits letzte Woche Gunnar etwas zu code coverage geschrieben hat werde ich jetzt noch einmal nachlegen, mich jedoch auf coverage.py und dessen Nutzung sowie die Integration in Jenkins beschränken.
Was ist coverage.py?
coverage.py ist ein Tool um für in Python geschriebenen Quellcode coverage reports zu generieren. Aber zuerst einmal müssen ein paar Informationen generiert werden, damit überhaupt irgendetwas visuell dargestellt werden kann:
coverage run python-script
Reports werden dann folgendermaßen generiert:
coverage report # Text-basierter Report in der Konsole
coverage html -d ziel-verzeichnis # html Report mit im Quellcode hervergehobenen Zeilen
coverage xml -o xml-datei # xml Report für die Weiterverarbeitung in anderen Systemen
Das ganze geht natürlich auch in Verbindung mit nosetests. Details dazu könnt ihr hier finden.
Integration in Jenkins
Um nun coverage reports in Jenkins für das eigene Projekt zu generieren greifen wir selbstverständlich auf coverage.py zurück. Um das zu realisieren bietet sich „Execute shell“ als build step an in welchem wir oben angegebene Befehle ausführen lassen:
coverage run python-script
coverage xml # Output landet per default in coverage.xml
Dann legt man eine post-build action an, die sich „Publish Cobertura Coverage Report“ nennt und gibt dort bei „Cobertura xml report pattern“ den Pfad zu der vom build step generierten xml Datei an. (**/coverage.xml, falls die Datei direkt im workspace liegt.)
Soweit so gut. Wenn nun ein Build ausgeführt wird, hat man am Ende einen coverage report in Jenkins, der jedoch keinerlei Details dazu aufführt welche Zeilen im Quellcode denn nun genau betroffen sind. Zu beurteilen woran das liegt, maße ich mir hier einfach mal nicht an und gebe nur einen kleinen Hinweis wie dieses Problem mit einer kleinen Erweiterung des build steps zu lösen ist:
sed -i -e 's??ein/relativer/pfad/zum/quellcode?' coverage.xml
sed -i -e 's?filename="'$WORKSPACE'/ein/relativer/pfad/zum/quellcode/?filename="?' coverage.xml
Wobei hier „ein/relativer/pfad/zum/quellcode“ zu ersetzen ist. Zu beachten ist hierbei, dass es sich tatsächlich um einen relativen Pfad handeln muss, ausgehend vom workspace. Beim nächsten Build gibts dann auch hervorgehobene Zeilen im Quellcode. 🙂
Zu guter letzt noch ein Protip:
Um coverage.py dazu zu bringen branch coverage (conditionals usw.) zu messen muss eine spezielle Option angegeben werden:
coverage run --branch python-script
Damit das auch mit nosetests funktioniert, bedarf es erneut eines kleinen Tricks:
touch .coveragerc
echo "# .coveragerc to control coverage.py\n\n[run]\nbranch=True" > .coveragerc
Das muss im selben Verzeichnis ausgeführt werden in dem auch coverage.py selbst ausgeführt werden wird.
Und nun viel Spaß mit den vielen bunten Trends und Quellcodes! 😀

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

Simpel, schnell und praktisch – Webapplikationen mit Flask erstellen

Auf dem Planeten der serverseitigen Webtechnologien herrscht eine unbegrenzte Artenvielfalt. In den verschiedensprachigen Ländern und Inseln (Java, Pythonien, etc.) tummeln sich viele kleine Technologievölker und verehren ihre vielen Frameworks, die allesamt unermesslich Mächtig und Allumfassend sind. Unerbittliche Kriege werden geführt, welches Framework und welche Sprache besser ist, Neulinge kämpferisch missioniert und für die eigene Sache geworben.
Manchmal wünscht man sich einen kleinen Kometen, der ein wenig für Ordnung sorgt. Daher will ich zumindest in Python einen kleinen Tipp geben, wenns mal weniger sein darf:
Zur Vorgeschichte: Auch ich bin auf den Raspberry Pi Zug aufgesprungen und finde die Kiste als kleinen Programmierspielkasten wirklich sehr spaßig. Da ich für kleinere Spielereien Python oder NodeJS bevorzuge, war ich also auf der Suche nach einem kleinen Python Webframework – direkt gegen die WSGI zu programmieren empfinde ich doch als etwas unkomfortabel. Nun ist es hier nicht so einfach, ein passendes Framework zu finden, das mir nicht von vornherein MV* aufdrängt (manchmal braucht man das nicht, ehrlich), klein ist und sich ‚elegant anfühlt‘.
Nachdem die Liste im Python wiki überflogen habe, bin ich erstmal aus dem Raum gegangen und habe ein wenig geweint. Django, Pylon, Zope… das war mir alles (auf den ersten Blick) zu groß, zu Vereinnahmend. Klar, große Frameworks mit ORM, SOAP support, MVC und allen möglichen Schnittstellen, Helfern und Features haben Ihren Sinn, aber manchmal ist auch bei der Webentwicklung weniger mehr (und mit NodeJS habe ich ja auch in ein paar Zeilen einen HTTP Server laufen ohne vorher ein Projektskeleton auf der Konsole zu erstellen).
Dann bin ich über Flask gestolpert und allein schon das Beispiel auf der Startseite hat die Tränen etwas trocknen lassen. Ein paar Zeilen, schon hat man einen Webdienst am Laufen, ein paar Zeilen mehr und man kann komplexe Templates einbinden. Formulare, Uploads, Routing, etc. – alles ist vorhanden. Dabei ist es egal ob man ein paar Funktionen über Urls ansprechen will oder man auf Klassenbasierte Views setzt – das Framework skaliert hier recht gut mit (aber zugegeben: Letzteres haben andere Frameworks schon eleganter umgesetzt).
Für mich wird das wohl das Pythonframework meiner Wahl für kleine und mittelgroße Projekte im Web (auch wenn es natürlich auch andere Frameworks, wie z.B. bottle gibt, die ähnlich kompakt sind). Für wirklich größere Anwendungen mit vielen Schnittstellen, Ausgabeformaten, Lokalisierung, etc. würde ich dann allerdings doch auf Django oder Zope umsteigen, hier ergibt der Mehraufwand beim Konfigurieren und der Größe dann auch wirklich Sinn.

Pylint, Pylint on the wall, who has the fairest code of them all?

„You, my Developer, have the fairest of all.“ So oder so ähnlich wünscht man es sich, wenn einem die Qualität des eigenen Programms am Herzen liegt. Für all die Python-Entwickler da draußen, welche nicht jegliche Richtlinien aus dem PEP8 Guide auswendig wissen und es auch sonst im Eifer des Programmierens nicht so ernst mit der Qualität nehmen, bietet Pylint ein sehr nützliches Werkzeug, um so eilig wie geschwind das hässliche Entlein wieder in einen schönen Schwan zu verwandeln. Doch wie soll das gehen, und was unterscheidet es von gängigen Python Source Code Checkern wie beispielsweise PyChecker?
Nun, zunächst einmal bietet Pylint in den Grundfeatures ziemlich das selbe wie PyChecker. Das bedeutet, beide Programme überprüfen den Code auf Qualität und Sauberkeit. Doch während PyChecker in der Altfränkischen „Bassd scho“-Manier arbeitet, ist Pylint eher der strenge Deutschlehrer, der auch jeden noch so kleinen Fehltritt rot anstreicht. Da wird penibel auf Dinge wie die maximale Zeilenlänge (max. 80 Zeichen) oder der maximal erlaubten Zeilenanzahl (max. 1000 Zeilen) innerhalb einer Datei geachtet. Auch vergessene allseits bekannte Kommentare wie „TODO“ oder „FIXME“ werden dem eifrigen Entwickler nochmal ins Gedächtnis gerufen. Wem diese ganzen Richtlinien von PEP8 nicht zusagen oder sowieso schon nach seinen eigenen Standards codet, dem bietet Pylint eine sehr schnelle und einfache Möglichkeit Regeln zu ändern oder sogar mithilfe von Modulen zu erweitern.
Wie funktioniert nun also dieses wunderbare Werkzeug? Wir starten den ausführlichen Test zunächst einmal mit der Standardkonfiguration:

pylint pfad/zum/projekt

Nach einer kurzen Wartezeit (je nach Projektumfang) spuckt das Programm auch schon eine Statistik mit jeglichen Makel und Fehler. Sogar eine Punktwertung wie im guten alten Sport wird vergeben! Wer seine Punkte nun verbessern möchte, muss sich nun daran machen, die gelisteten Meldungen abzuarbeiten und so seinen Code zurechtschleifen. Möchte man gewisse Regeln ändern oder Ausnahmen hinzufügen, so kann man dass indem man eine neue rcfile generiert:

pylint --generate-rcfile > ~/.pylintrc

Diese Datei öffnet man dann mit dem Editor seiner Wahl und fügt seine Änderungen hinzu. Dank der ausführlichen Dokumentation findet man sich innerhalb der configfile sehr schnell zurecht.
Wer jetzt noch gerne wüsste, wie denn das eigene Kind so aussieht, der kann sich mithilfe des mitgelieferten Programms „pyreverse“ eine Art UML-Diagramm generieren lassen:

pyreverse pfad/zum/projekt

Generiert werden zwei .dot dateien, die mithilfe folgender Befehle ganz leicht in beispielsweise .png dateien umgewandelt werden können:

dot -Tpng packages_Name.dot -o packages-Name.png
dot -Tpng classes_Name.dot -o classes-Name.png

Mithilfe eines solch strengen Lehrers sollte einem nichts mehr im Wege stehen, um das Märchen wahr werden zu lassen!