Montag, 7. Juli 2008

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.



Freitag, 15. Februar 2008

psycopg, segfaults, Valgrind

Diese Woche habe ich einen Segfault in psycopg behoben, der bei einem Zope-Server häufig für Abstürze sorgte. Das interessante: psycopg hat immer wenn ein Client-Encoding angegeben wurde, das keine Binde- oder Unterstriche enthalten hat, ein Byte zu wenig alloziiert. Genaue Fehlerbeschreibung und Patch gibts im Trac.

Schlussendlich hat mir Valgrind sehr geholfen das Problem zu analysieren. Die Aufrufzeile um einen Zope-Server, der im Vordergrund läuft zu überwachen ist:
valgrind --leak-check=yes --trace-children=yes --suppressions=valgrind-python.supp bin/zopectl fg
Die Suppressions-Datei wird im Python-Source-Code mitgeliefert und sorgt dafür, dass Valgrind sich nicht von Python's Memory-Manager für kleine Objekte verwirren lässt.