Montag, 7. Juli 2008

py.test: rapid testing with minimal effort

Holger Krekel hat ein 1-stündiges Tutorial gegeben um die Verwendung von py.test zu erläutern.

Übersicht
  • py.test ist projektübergreifend und hält den Test-Tool-Code in einer eigenen Bibliothek
  • sammelt Python-Tests automatisch auf und führt sie aus
  • versucht die Boiler-Plate innerhalb eines Projekts klein zu halten
  • kann projektspezifisch erweitert werden
  • läuft auf Linux, Windows, OSX und unter Python 2.3-2.5
Grundlagen
  • Installation als Egg, stellt "py.test" als Executable zur Verfügung
  • Der "py"-Namensraum hat einen automatischen Lazy-Importer, der alles unterhalb von "py.*" importiert, so dass man nur "py" importieren braucht, der Rest kommt automatisch mit.
  • Tests werden über Konventionen automatisch gefunden (Klasse mit Namen "Test*" und Methoden mit dem Namen test_*) automatisch gefunden.
  • Automatisches Auffinden kann über "--collectonly" nachverfolgt werden
    um zu sehen wie py.test vorgeht und was es tatsächlich sieht und findet.
  • Assertions werden über Python's "assert"-Statement formuliert. Exceptions können über eine Helferfunktion "py.test.raises" mit dem "assert"-Statement kombiniert werden.
  • Fehlerhafte Werte bei einem Fehler werden getraced um zu zeigen wie sie berechnet wurden.
  • Generative Tests: wenn eine Testmethode ein Generator ist, kann sie Callables und deren Parameter yielden, die dann als eigentlicher Test ausgeführt werden.
  • stdout/stderr werden umgeleitet und nur im Fehlerfall ausgegeben
  • --pdb lädt einen pdb nach einem Fehler
  • -x beendet den Testlauf nach dem ersten Fehler
  • --looponfailing: führt die fehlgeschlagenen Tests automatisch neu aus, wenn Dateien, die zu diesen Tests gehören verändert werden
  • setup/teardown: setup_module, setup_class, setup_method, teardown_*
  • setup_method bekommt das Methodenobjekt reingereicht, setup_module erhält das Modul-Objekt, setup_class erhält die Klasse
  • doctests werden anhand der Extension ".txt" automatisch gefunden
Erweiterbarkeit
  • py.test sucht nach "conftest.py"-Dateien, die die Konfiguration von py.test beeinflussen.
  • Mehrere conftest.py-Dateien können über Verzeichnisebenen miteinander kombiniert werden.
  • Diverse Elemente (Session, Collection, Module, ...) können beerbt werden, um eigene Funktionalität unterzubringen.
  • Dazu werden via "conftest.py" dynamisch die konkreten Klassen für Session, Collection, Module, ... nachgeschlagen, die unterhalb eines Verzeichnisses verwendet werden sollen.
  • Fehlerberichte können in HTMl generiert werden. Dies kann ältere Testläufe beinhalten, so dass man den historischen Verlauf einsehen kann.
  • Weitere Plugins für Prolog-Tests, JavaScript-Tests (via SpiderMonkey), verteilte Tests um Tests auf anderen Maschinen (mit ggfs. anderen Plattformen) auszuführen, Integration mit klassischen UnitTest
  • Reporting kann man momentan nicht (einfach) anpassen
Fragen
  • Ist die py-Import-Magic kompatibel mit py2exe? Antwort: Unbekannt.
  • Wie schwer wird es sein py.test auf Python 3k auszuführen? Antwort: Unbekannt
  • Parallele Ausführung: über verteilte Tests. Können sowohl lokal als auch remote verteilt werden inkl. Multi-CPU-Support.
  • Gruppierung von tests nach Setup ala Layer: Gibt es momentan nichts.

ReportLab Paragraphs Reloaded

Dinu Gherman gab einen Vortrag über ReportLab. Dabei ist er speziell auf die Implementation von Paragraphen, deren Probleme und einer Reimplementation eingegangen.

ReportLab-Übersicht
  1. Canvas, eine Zeichenfläche, die in etwa einer Seite entspricht. Kann auch als Bilddatei exportiert werden.
  2. Platypus, "Page LAyout TYPography Using Scripts", bietet verschiedene Objekte (Frame, PageTemplate, DocumentTemplate, Content, Flowables) um Typographie und Inhalt einer oder mehrer Seiten zu beschreiben um daraus ein PDF zu erzeugen.
  3. RML, "ReportLab Markup Language", ein Aufsatz für Platypus, der XML in Platypus-Anweisungen übersetzt (kommerziell, eine freie Drittanbieter-Implementation (z3c.rml) ist aber auch verfügbar)
Paragraphen sind Flowables aus der Platypus-Bibliothek, deren Hauptaufgabe die Berechnung von Zeilenumbrüchen ist. Außerdem wenden Paragraphen verschiedene Stile für Schriften, Einzüge und Anstriche an. Innerhalb eines Paragraphen können XML-Tags verwendet werden, um einige Stile auf Wortebene anzuwenden.

Paragraphen können momentan nicht:
  • eingebettete Bilder (im ReportLab SVN inzwischen doch)
  • Silbentrennung
  • Kerning
Außerdem ist der Code für Paragraphen nur sehr schwer verständlich und nicht erweiterbar. Leider ist das Hauptaugenmerk der Entwicklung bisher auf Geschwindigkeit gelegt worden.

"Paragraphs Reloaded"

Ein neues Flowable, genauer: eine Familie von Paragraphen-Klassen, die abgeleitet werden können (und sollen).

Der MinimalParagraph ist ausschließlich für die Berechnung von Zeilenumbrüchen und wenigen Paragraph-Stilen da.

Paragraphen bieten ein Event-Schema, an dem eigener Code in das Layouting eingreifen kann. Beispielsweise an Wort- oder Zeilengrenzen.

Beispiele für Erweiterbarkeit, die Dinu bereits implementiert hat: einzelne Wörter markieren, Silbentrennung, eingebettete Bitmap- und Vektorbilder, Zeilennummerierung.

Beim Vergleich der Code-Komplexität der Original-Implementation fällt auf, dass der bisherige Paraph etwa 1400 Codezeilen hat, während die neue Minimalimplementation mit etwa 200 Zeilen auskommt.

Im Geschwindigkeitsvergleich hat die bisherige Implementation die Nase vorn. Der neue Code braucht etwa 2-5mal länger um einen Vergleichbaren Paragraphen zu zeichnen. Nach Dinus Erfahrung ist das aber immer noch schnell genug für die meisten Aufgaben.

In Zukunft will Dinu weitere Paragraphen-Attribute implementieren, sowie Kerning, eingebettetes XML, generische Callbacks und eventuell RTL-Unterstützung.

Fragen
  • Frage nach der Verwendung des TeX-Zeilenumbruch-Algorithmus: nicht berücksichtigt. Andrew Kuchling hatte ihn mal teilweise implementiert, ist aber extrem langsam gewesen.

EuroPython 2008

Die EP 2008 beginnt heute. Eine gute Neuerung des Hotels ist die freie Verfügbarkeit von WLAN auf den Zimmern, nicht nur im Konferenzbereich. Die Registrierung lief bedeutend einfacher als letztes Jahr: zur Anmeldung gehen, eigenes Namensschild und Konferenztüte nehmen, fertig.

Freitag, 27. Juni 2008

Neue Blob-Verzeichnisstrukturen

Die ZODB unterstützt seit einiger Zeit große Dateien über den eigenen Datentyp "Blob". Bisher wurde für jeden Blob ein Verzeichnis angelegt, in dem sämtliche Revisionen des Blobs gespeichert wurden.

Eine Installation brachte dies an die Grenze, da als Dateisystem ext3 benutzt wurde, und dort die Anzahl der Einträge je Verzeichnis auf 32k begrenzt ist. Da dies auch in anderen Dateisystemen der Fall ist habe ich das Blob-Verzeichnis etwas stärker strukturiert: 8 Ebenen von Verzeichnissen, abgebildet über die Little-Endian-Repräsentation der OID. Das garantiert maximal 256 Einträge je Verzeichnis und balanciert den Baum relativ einfach aus. Die Implementation ist abwärtskompatibel für alle, die bereits Datenbanken im alten Schema haben.

Momentan lebt der Code noch auf einer Branch und ist für ZODB-trunk und ZODB 3.8 verfügbar.

Eine Einschränkung der Branches ist momentan, dass die Datenbankgröße nur ohne den Platz, den Blobs einnehmen berechnet werden kann, da getSize von ZEO in jeder Transaktion einmal aufgerufen wird, und bei der neuen Struktur sehr langsam wird.

Donnerstag, 22. Mai 2008

Pakete von Drittanbietern konfigurieren

Ich hatte gestern mit Sebastian das Problem aus einem Python-Paket für Zope 3 (gocept.country) eine ZCML-Konfiguration (konkret: i18n:registerTranslations) relativ zu einem anderen Python-Paket (pycountry) zu spezifizieren.

Leider erlaubt i18n:registerTranslations nur eine relative Pfadangabe zum aktuell konfigurierten Paket. Glücklicherweise gibt es einen generischen Mechanismus in ZCML um Konfigurationsangaben im Kontext beliebiger Python-Pakete auszuführen: das configure-Statement.

Configure-Statements können verschachtelt werden und erlauben die freie Angabe eines Pakets, das für alle darin eingebetteten Anweisungen als Kontext benutzt wird. Das ganze sieht dann folgendermaßen aus:

...
<configure package="pycountry">
<i18n:registertranslations directory="locales">
</i18n:registertranslations>
...

Freitag, 2. Mai 2008

ZEORaid in Beta

Seit Mittwoch gibt es ZEORaid 1.0b1, das wir inzwischen auf einem internen Produktionsserver testweise einsetzen. Die initiale Replikation der 1.1 GB grossen ZODB hat etwas weniger als 15 Minuten gedauert und resultiert normalerweise in Byte-genauen Kopien der originalen Datenbank.

Setzt man zwei identisch konfigurierte ZEORaid-Server auf, kann man auch ZEORaid selbst als einzelnen Ausfallpunkt ausschließen, wobei ein paar operative Einschränkungen zu beachten sind.

ZEORaid unterstützt Zope ab Version 2.8, Blobs und alle anderen ZODB-Funktionen ausser "Versions".

Freitag, 14. März 2008

PyCon 2008

PyCon 2008 (diesmal in Chicago) läuft seit einigen Stunden. Fotos gibt es ebenfalls.