programmierung - 2.8.2005 - 2.10.2005

IRC-Logger für #django

Es gibt jetzt einen IRC-Logger für #django auf freenode.net. Seit der loglibrary ausgefallen ist, dachte ich darüber nach, meinen eigenen zu erstellen. Also begann ich, die für einen IRC-Logger benötigten Dinge zu bauen. Die Schnittstelle selbst ist natürlich mit django geschrieben.

Wie immer ist der Quellcode in meiner Trac-Instanz verfügbar. Derzeit läuft er nur in #django, aber er kann leicht auf andere Kanäle erweitert werden. Und er speichert die Protokollzeilen in einer Datenbank, sodass ich in der Lage sein werde, Suchfunktionen und dergleichen hinzuzufügen. Er hat bereits eine Kalenderansicht der Protokolle.

Das Protokollieren selbst erfolgt mit muh - ein netter IRC-Proxy, der das Protokollieren in Named Pipes ermöglicht. Dann gibt es ein Skript fetch.py, das die Zeilen aus der Named Pipe zieht und sie in der Datenbank speichert. Der letzte Teil ist der django-basierte Viewer für diese Protokolle.

Aktualisierung: Das Protokollieren erfolgt jetzt mit einem dedizierten IRC-Logger, der in Python geschrieben ist. Er befindet sich im Quellcodebaum als loggerbot.py.

Ich hätte generische Ansichten in Django verwenden können, nur dass ich sie parameterisieren musste. Das habe ich mit einer Wrapper-Funktion gemacht, die Dinge von den Schlüsselwörtern einer View-Funktion zu den extra_lookup-Argumenten und den extra-Kontext-Schlüsselwörtern der generischen Ansichten verschiebt. Sie können den Code im Repository sehen.

Der Rest ist nur Standard-Django-Zeug: generische Vorlagen (die den coolen regroup-Tag nutzen) und einige benutzerdefinierte Tags für den Kalender und die Benutzerfarbgebung. Ein bisschen Modell-Hackerei und das war's eigentlich. Schön und einfach. Es hat nur ein paar Stunden gedauert, um das zusammenzubauen, und das schließt das Herumspielen mit muh und Named Pipes ein ...

TwistedDAV ist ein WebDAV Server in Python, der unter Twisted läuft. Sehr interessant wenn man etwas auf DAV aufbauen möchte - bisher gabs da nur den Zope-Source als Beispiel und Basis.

How-to get decimal.py if I have Python 2.3.x beschreibt, wie man Zahlen in Dezimaldarstellung (entgegen den dusseligen binären Floats mit ihren nervigen Rundungsproblemen) für Python 2.3 bekommt. Ab 2.4 ist das ja ein Standardmodul.

i18n und django

Jacob hat mir die Berechtigungen für Branch-Commits und einen Branch für i18n-Sachen eingerichtet. Daher habe ich heute an den Ideen im Patch von Ticket 65 von nesh gearbeitet. Ich habe die meisten Sachen von Grund auf neu geschrieben, weil ich einige Dinge etwas anders haben wollte, und jetzt ist es zum Testen verfügbar.

Zuerst, wie Sie die i18n-Sachen mit Ihrem Django-Checkout verwenden können. Sie benötigen einen aktuellen svn trunk Checkout und gehen Sie zum Root Ihres Checkouts und führen Sie den folgenden Befehl aus:

svn switch http://code.djangoproject.com/svn/django/branches/i18n/

Danach sollten Sie einen Baum mit meinen Patches angewendet haben. Ich habe bisher nur sehr wenig übersetzt, um den Patch und die Änderungen so klein wie möglich zu halten, aber ich habe bereits eine deutsche Übersetzungsdatei mit Sachen für den Admin-Index und den isAlphaNumeric-Validator hinzugefügt. Ich denke, ich werde bald noch mehr Sachen zu den Übersetzungen hinzufügen.

Der Patch behandelt nur den Übersetzungsanteil - andere Dinge wie Datumsformatierung, Zahlenformatierung, Zeitzonenbehandlung sollten in verschiedene Patches gehen, um jeden von ihnen so klein wie möglich zu halten. Das Übersetzungsobjekt (das ist das Biest, das für die Umwandlung von Zeichenfolgen in ihre neue Form verantwortlich ist) wird auf Anfrage erstellt. Dies gibt uns die Möglichkeit, verschiedene Stellen zu betrachten, die bei der Entscheidung helfen können, welche Sprache dem Benutzer präsentiert werden soll. Der Code beginnt damit, in der Sitzung nach einer django_language-Variablen zu suchen. Wenn diese nicht gefunden wird, sucht er in den Cookies nach einem django_language-Cookie. Wenn auch das nicht gefunden wird, gräbt er in den HTTP-Headern. Es sucht nach dem Http-accept-language-Header und teilt diesen nach Sprachen auf und sortiert sie nach Vorliebe. Es wird die erste Sprache (sortiert nach Vorliebe, höchste Vorlieben zuerst) verwenden, die in dem django-Nachrichtenfile-Repository gefunden wird. Wenn keine dieser Sprachen gefunden werden kann, wird es letztlich auf das Standardübersetzungsobjekt zurückgreifen, das durch die LANGUAGE_CODE-Einstellung in Ihrer Einstellungsdatei definiert ist. Nachrichten-Dateien können an drei verschiedenen Stellen gespeichert werden: Die django-Projekt-Nachrichten-Dateien werden im django.conf-Paket in einem Unterverzeichnis namens locale gespeichert. Dies ist ähnlich wie die admin_media- und admin-Vorlagenverzeichnisse. Das locale-Unterverzeichnis ist wie typisch bei der Speicherung von lokalen Daten strukturiert: ein Unterverzeichnis pro Sprache und ein LC_MESSAGES-Verzeichnis darin. Der Sprachbereich für django-Nachrichten-Dateien ist immer django. Der nächste Ort, an dem django nach Nachrichten-Dateien sucht, ist das Projekt - wenn Sie ein locale-Verzeichnis in Ihrem Projekt haben, können Sie dort zusätzliche Nachrichten-Dateien speichern. Der dritte Ort ist die Anwendung - Sie können ein locale-Verzeichnis neben Ihrem Anwendungs-Views-Verzeichnis haben. Alle locale-Verzeichnisse sind gleich strukturiert.

Ein Übersetzungsobjekt für eine bestimmte Sprache ist tatsächlich eine Verkettung von vier Übersetzungsobjekten: zuerst das Anwendungsübersetzungsobjekt. Dies wird auf das Projektübersetzungsobjekt zurückgreifen. Dieses wiederum wird auf das globale Übersetzungsobjekt zurückgreifen, das auf das Übersetzungsobjekt für die Standardsprache zurückgreifen wird. Auf diese Weise können höhere Ebenen Übersetzungen von niedrigeren Ebenen überschreiben und Anwendungen können ihre eigenen Übersetzungen bereitstellen.

Die Anwendung für die Übersetzungen wird tatsächlich durch Modulintrospektion entdeckt - es verwendet die View-Funktion, um auf eine URL zuzugreifen, um herauszufinden, welche Anwendung diese View-Funktion trägt, und verwendet diese, um nach lokalen Übersetzungen zu suchen. Es gibt zwei Tools, die zur Verwaltung von Übersetzungen bereitgestellt werden: make-messages.py und compile-messages.py. Beide Tools können entweder im Root des django svn-Baums oder im Projektverzeichnis oder im Anwendungsverzeichnis aufgerufen werden. make-messages.py wird das aktuelle Verzeichnis und alles darunter nach zu übersetzenden Zeichenfolgen durchsuchen und wird eine django.po-Datei im locale-Verzeichnis für die gegebene Sprache erstellen. compile-messages.py wird einfach alle .po-Dateien in .mo-Dateien umwandeln. Das Hinzufügen von Übersetzungen ist einfach. In Python-Code umgeben Sie einfach Zeichenfolgen (nur Zeichenfolgenkonstanten!) mit ('...') oder ("..."). Dadurch werden diese Zeichenfolgen für die Übersetzung markiert, sodass make-messages.py sie herausziehen und in die .po-Dateien schreiben kann. Und es wird die Zeichenfolge zur Laufzeit übersetzen, unter Verwendung des aktuellen Übersetzungsobjekts, das aus der Anfrage ermittelt wurde. In Vorlagen gibt es das Vorlagentag {% i18n ('....') %} - dieselbe Syntax wie mit Python-Code, nur müssen Sie es als Vorlagentag umschließen. Diese Zeichenfolgen werden ebenfalls aus den .html-Dateien in die .po-Datei gezogen. Das i18n-Tag unterstützt die Zeichenfolgeninterpolation aus dem Kontext: {% i18n ('blah %(blubb)s blubber') %} würde zunächst die Zeichenfolge übersetzen und dann die Kontextvariable blubb in das übersetzte Ergebnis interpolieren.

Ein Tipp: Wenn Sie Zeichenfolgen zum Übersetzen schreiben, verwenden Sie keine positional parameters für die Interpolation (die %s-Sachen), sondern verwenden Sie stattdessen benannte Parameter (%(blah)s). Auf diese Weise können Personen, die Übersetzungen erstellen, die Zeichenfolge neu anordnen, ohne Ihren Code zu brechen - einige Sprachen haben eine andere Reihenfolge als Englisch.

Die Verwendung der Übersetzungen ist ebenfalls einfach: Sie müssen nur Ihre Standardsprache in der LANGUAGE_CODE-Einstellung festlegen und django.middleware.locale.LocaleMiddleware zu Ihrer Middleware-Einstellung hinzufügen. Sie müssen es an die Spitze setzen - besonders im Admin sollte es vor dem AdminUserRequired Middleware kommen - aber es muss nach dem SessionMiddleware sein, wenn Sie dieses verwenden.

Das ist erst der Anfang, spielen Sie damit und sagen Sie mir, wenn etwas schief geht. Der beste Ort, um es zu sagen, ist im Ticket im django trac.

Open Dylan

Open Dylan ist ex-Harleqin-Dylan, ex-Functional Developer - eine integrierte Umgebung für Dylan-Programmierung und eine Library von diversen Klassen für verschiedenste Zwecke - vor einiger zeit open-sourced und jetzt als erste Beta zum Download für Linux und Windows verfügbar.

Mir wärs ja noch lieber wenn Apple das Apple Dylan freigeben würde, denn dessen Entwicklungsumgebung war wirklich um Welten weiter als alles was sonst so auf dem Markt ist, aber das wird wohl nie kommen - eher wirds von Open Dylan eine OS X Version geben. Auch ganz nett.

Routes für Python

Sehr interessant: Ben Bangert hat Routes für Python portiert. Routes ist der Kern des Mappings von URLs auf Funktionen und zurück der in Ruby on Rails benutzt wird. Also ein allgemeiner Mechanismus mit dem aus einer URL ein Python-Objekt und aus einem Python-Objekt seine URL ermittelt werden kann - flexibel konfigurierbar.

Könnte auch als Element in Django interessant sein, als Alternative zum derzeitigen URL Pattern System. Das derzeitige System liefert ja recht elegant aus einer URL die aufzurufende Funktion - aber leider gibt es nicht diesen gleichen Weg zurück vom Objekt oder der Funktion zurück zur URL.

Ausserdem könnte Routes auch innerhalb von WSGI-Projekten interessant sein - es löst elegant einen kleinen Teilbereich und das so abstrakt, das es gut mit Sachen wie Python Paste(Ian Bickings Meta-Framework für WSGI-Anwendungen) harmonieren müsste.

Warum ich so bei Rails meine Zweifel habe

könnte klar werden, wenn man sich den Artikel hier durchliest: Choose a single layer of cleverness (Loud Thinking) - ja, genau, seine Meinung ist, raus mit Referentieller Integrität, Stored Procedures und Triggern aus der Datenbank, weil er die alle in seinem Code halten will. Wie wärs mit "das Kind mit dem Bade ausschütten"?

Das ist sowas von peinlich, das ich schon fast nicht mehr weiss ob ich nicht drüber lachen sollte - aber eines werd ich sicherlich nicht: meine Karten auf so ein Pferd setzen ...

Hemdsärmelige Ansätze mit einfachen, pfiffigen Lösungen die auch mal gegen Konventionen verstossen sind ok (und wichtig - sonst würden wir alle bei Java und J2EE landen ...) - aber wenn die Programmierung nur noch aus aneinandertackern von halbgaren Lösungen besteht, dann halt ich mich da lieber raus. Da könnte ich ja auch gleich PHP benutzen ...

Weil ichs für ein Firmenprojekt gesucht habe: InformixDB ist ein Python-DBAPI1-Client für die Informix Datenbanken. Funktioniert auch mit Informix SE.

wxWindows Buch

Es gibt ein Buch über wxWindows/wxWidgets: Cross-Platform GUI Programming with wxWidgets - allerdings Schwerpunkt auf den wxWidgets und damit primär für die C++-Programmierer, die wxPython-Bindings sind dort aussen vor. Trotzdem sicherlich interessant wenn man wxWindows in irgendeiner Form benutzt, da die Bindings für andere Sprachen ja immer auf der originalen Bibliothek aufbauen.

Common Scheme

Common Scheme ist eine Implementation eines gemeinsamen Modul-Standards für verschiedene Scheme-Implementationen inklusive eines Paketinstallers der seine Sachen aus dem Netz holen kann. Dazu kommen eine Reihe von ersten Modulen die darüber verteilt werden. Könnte sowas wie CPAN für Scheme werden.

Ähnliche Ansätze gabs schon öfter, aber leider immer nur für einzelne Schemes (z.B. MZScheme hat sowas). Eine Scheme-übergreifende Lösung könnte auf Dauer doch einiges einfacher machen - und Scheme etwas aus der akademischen Ecke holen. Verdient hätte die Sprache es.

Und das beste: Gambit-C und Chicken sind bei den unterstützten Schems dabei

Leider fehlt MZScheme in der Liste der unterstützten Schemes - es wäre schon ziemlich cool seine Programme mit DrScheme zu entwickeln und dann hinterher einfach durch Chicken zu jagen um sie schnell zu bekommen ...

I want one!

Erste Lebenszeichen von Open Genera auf PowerMac - das wäre echt ein Hammer, wenn Open Genera nicht mehr nur auf seltsamen OpenVMS Kisten liefe, sondern auch auf einem PowerMac - da würd ich mir glatt doch noch einen Desktop-Rechner für kaufen

Django-Galerie-Status

Erneut Neuigkeiten von meinem Galerie-Projekt - es macht gute Fortschritte, auch wenn einige meiner neuesten Arbeiten nicht direkt sichtbar sind. Ich habe viel an dem Code gearbeitet und viele Änderungen an der Admin-Oberfläche vorgenommen. Dinge im Quellcode, die für andere Djangonistas interessant sein könnten:

  • Ich habe immer noch eine vollständig dateisystembasierte Galerie - aber ich habe einen im Datenbank gespeicherten Cache hinzugefügt. Wenn nun Inhalte vom Dateisystem geladen werden, prüft der Code direkt seinen Datenbank-Cache und aktualisiert diesen entsprechend. Dies führte zu einer umfangreichen Überarbeitung des Codes, so dass nun tatsächlich alles durch Modellobjekte gesteuert wird - die Cache-Einträge sind nur Teil des Django-Modells. Dadurch wird der Code viel einfacher und ermöglicht die nächsten beiden Änderungen.
  • Ich habe eine automatische Sitemap für Galerien hinzugefügt. Die ersten Versionen durchsuchten das Dateisystem, aber jetzt verwendet es einfach den Datenbank-Cache, um eine Ordnerhierarchie mit Miniaturansichten zu erstellen.
  • Ich habe RSS-Unterstützung hinzugefügt. Die Hauptgalerie-Auswahl verweist auf einen RSS-Feed über alle Galerien und die Ordner- und Bildansichten innerhalb einer Galerie verweisen auf einen RSS-Feed nur für Bilder innerhalb dieser Galerie. Dies macht von dem RSS-Framework von Django Gebrauch.
  • Die Ansicht, die Galerie-Ordner und Bilder anzeigte, wurde überarbeitet, um viel mehr von Django-ähnlichen Dingen Gebrauch zu machen: anstatt von Lazy Closures, die an die Vorlage übergeben werden, verwende ich nun benutzerdefinierte Vorlagen, die helfen, den Code der Ansicht drastisch zu reduzieren (ok, der Code wird in die Taglib verschoben, aber das ist eine viel bessere Entkopplung als zuvor).

Das Ergebnis: Die Galerie ist viel schneller, ich habe RSS laufen und habe automatische Sitemaps. Der Code selbst ist viel einfacher, da er modellgetriebener ist - der frühere Konflikt zwischen Bildordner-Modell-Dingen auf der einen Seite und FSObject-Instanzen auf der anderen Seite ist verschwunden - und die Cache-Wartung ist automatisch. Und die XMLRPC-Integration ist auch viel schneller. Alles in allem einige sehr nützliche interne Änderungen.

Andere Änderungen gibt es in der Verwaltungs-Oberfläche, wo Sie nun nicht nur die AJAX-Funktionen zum Ändern von Objektnamen und dem versteckten Zustand haben, sondern dies auch über einen Dateimanager tun können. Dieser Dateimanager wird auch um einfache Verwaltungsfunktionen wie Verschieben, Löschen usw. erweitert. Er kann bereits neue Ordner erstellen.

Parser für Python-ähnliche Konfigfiles

Philip J. Eby hackt mal wieder. Diesmal einen Parser für Konfigurationssprachen deren Syntax an Python angelehnt ist. Besonders interessant: mit dem Parser kann man sehr schön abstrakte Sprachen aufbauen die in Teilen einfach Python für Code benutzen - man kann enthaltene Python-Blöcke nämlich von der Token-Form wieder in sauber formatierten und eingerückten Python-Code umwandeln. Der Parser kennt natürlich all die Randfälle der Sourceformatierung in Python und kommt mit denen auch klar.

Interessant ist das ganze deshalb, weil man mit Python ja leider keine Makrosprache hat und deshalb eigene Syntaxerweiterungen und Sprachen mit domain-spezifischer Syntax und Semantik nicht direkt in Python abbildbar sind - aber man kann über diesen Parser einen Translator für solche DSLs bauen und diese dann wieder in Python wandeln. Dazu dann noch ein bischen Import-Magic und man hätte sowas wie poor-mans-macros für Python ...

MochiKit Tutorial Teil 1

Es ist der erste Teil des MochiKit Tutorial online. Sehr interessante Lektüre - einige der Punkte sind durchaus bedenkenswert. Und MochiKit hat sich bei mir im Echteinsatz auch schon bewehrt - und ja, ich benutze fast ausschließlich JSON dabei.

Nachrichten vom Galerieprojekt

Nachrichten von meinem Django Gallery Projekt: Es kommt gut voran. Wenn Sie Beispielcode für AJAX mit Django oder XML-RPC mit Django möchten - sehen Sie sich den Quellcode an. Ich habe Teile der Blogger API, metaWeblog API und MoveableType API implementiert - gerade genug, damit Photon Bilder in meine Galerie posten kann. AJAX wird verwendet, damit angemeldete Benutzer den Titel von Bildern und Ordnern einfach durch Klicken auf den Titel ändern können und um das Werkzeugkasten auf der Rückseite von Bildern zu aktivieren. Zusätzlich enthält die Galerie die üblichen PIL-Funktionen wie das Erstellen von Thumbnails - ich bin besonders stolz auf das Aussehen der umgedrehten Ecke für Ordner-Thumbnails. Andere interessante Dinge, die sich lohnen zu untersuchen, könnten die Verwendung von lazy evaluation sein, um Inhalte in die Vorlage zu schieben, ohne sie vorher zu berechnen - sie wird nur berechnet, wenn die Vorlage sie tatsächlich verwendet. Und interessant könnte die Abstraktion des dateisystembasierten Inhalts sein - nur der Basispfad wird im Datenbankmodell gespeichert, der Rest der Galerie befindet sich im Dateisystem (und kann so leicht mit FTP, SSH oder direkt auf der Unix-Shell verwaltet werden).

Zusätzlich können Sie es sich für die Handhabung der Authentifizierung ansehen - die Benutzerregistrierung ist noch nicht abgeschlossen, wird aber irgendwann folgen. Ebenso Kommentare und RSS - aber ich muss das zuerst schreiben. Und ich beginne, Dokumentation zu schreiben - Docstrings im Code und Dokumentationsseiten im Wiki.

JavaScript + CSS Box-Modell Rätsel

Also ich hab da so eine HTML-Table. In der sind alle TDs mittels text-align: center zentriert von ihrem Inhalt her. In diesen TDs hab ich zwei DIVs, die übereinander angezeigt werden. Die obere enthält ein IMG, die untere einfach nur einen Text. Beide Inhalte werden auch brav zentriert. Jetzt tausche ich per JavaScript DOM Funktionen die obere DIV mit dem IMG drin gegen eine andere DIV aus, die nur zwei DIVs enthält, die wiederum Text enthalten. Die Texte in den inneren DIVs der neuen DIV sind brav zentriert. Nur die DIV selber, in der die inneren DIVs liegen, ist bezogen auf die umfassende TD nicht mehr zentriert. Das Problem ist mit Safari und Camino reproduzierbar - irgendwie geht die Eigenschaft "Inhalt zentriert ausrichten" flöten für die neu zugefügten Element. Ich hab schon alle möglichen CSS Attribute durchgeguckt und mit allem möglichen rumprobiert (z.B. gucken ob die alte DIV mit dem IMG drin oder das IMG selber einen Wert für left hinterlegt hat), aber irgendwie will das ums Verrecken nicht funktionieren.

Der Hintergrund für das ganze: per Klick auf ein Icon soll ein IMG komplett gegen eine gleichgrosse DIV ausgetauscht werden, in der ein paar Schalter drin sind mit denen Eigenschaften des IMG geändert werden können. Im Prinzip sowas ähnliches wie die Widgets bei Dashboard machen - Konfiguration auf der "Rückseite" eines Bildes.

Im Moment übernehme ich nur die Höhe des Bildes, damit passt die vertikale Ausrichtung perfekt. Nur halt bei der horizontalen Ausrichtung bleibt jetzt alles dynamisch an der Stelle. Wenn ich zwei Zellen übereinanderstehen habe und beide umschalte auf Konfiguration wird die Tabelle in der Breite verändert. Was dann hässliches Zucken gibt. Aber ich will jetzt nicht die TDs statisch aufspannen, denn dann würde sich das Layout nicht mehr dynamisch an die Browserbreite anpassen.

Achso, das ganze muss auch noch mit dem Safari funktionieren, ist schliesslich mein Hauptbrowser

Upadte: in den Kommentaren stehen Links auf Testseiten mit denen man sich das ganze im Effekt mal angucken kann.

JavaScript und die escape() Funktion

Note to self: escape() in JavaScript ist nur latin-1 tauglich - ein utf-8 String mit Sonderzeichen schickt diese als latin-1 Zeichen über die Leitung. Ziemlich dämlich wenn man mit Ajax ein Formular dengelt und dann daraus einen Wert an eine Funktion im Backend schickt und das eigentlich utf-8 erwartet. encodeURIComponent ist die Antwort, nicht escape.

MochiKit – erste Erfahrungen

Ich hatte ja schon kurz MochiKit – A lightweight Javascript library erwähnt. Jetzt hab ich es bei viele-bunte-bilder.de (seit 2007 offline) benutzt (damit der Besitzer einer Galerie die Bildnamen und Ordnernamen ändern kann). Ziemlich geniale kleine Library für JavaScript. Macht die Arbeit mit JavaScript deutlich angenehmer.

PostgresPy ist eine Sammlung verschiedener Python-Module rund um Postgres. Serverseite und Clientseite.

DjangoGallery - Beispiel-App mit Beispielinstallation

Wieder einmal auf Englisch, da auch für #django interessant

Ich habe den Quellcode hochgeladen und das Repository sowie eine Trac-Instanz für meine Django-Projekte verfügbar gemacht. Das erste Projekt, das dort zu finden ist, ist die DjangoGallery - das ist das, was ich auf viele-bunte-bilder.de verwende. Ich habe eine erste Version einer Installationsanleitung geschrieben, die zeigt, wie man die Galerie auf der eigenen Website zum Laufen bringt - man könnte sie sogar in das eigene Projekt integrieren (allerdings werden einige kleinere Änderungen am Quellcode erforderlich sein - hauptsächlich das Ersetzen des Projektnamens "gallery" durch den Namen Ihres Projekts).

Die Anwendung ist noch nicht vollständig fertig. Es gibt viele Pläne, wie man sie erweitern kann, da sie meine Hauptmotivation sein wird, alle anderen Galerie-Software, die ich betreibe, zu entfernen (ich habe bereits PHP Gallery ersetzt und jetzt ziele ich auf meine alten mod_perl-Dinge ab und das letzte wird meine Wordpress-basierte Galerie sein), also seien Sie gewarnt, dass sie sich im Laufe der Zeit ändern wird.

Wenn Sie Fehler finden, können Sie gerne Tickets einreichen. Sie können auch Verbesserungswünsche einreichen - aber da das Hauptziel dieses Projekts darin besteht, meine eigenen anderen Galerieprojekte zu ersetzen, ist es unwahrscheinlich, dass ich viel Arbeit neben dem investieren werde, was nötig ist, um dieses Ziel zu erreichen. Zumindest vorerst - es gibt keine Grenzen dafür, was mit dem Code gemacht werden kann, nachdem ich alle PHP- und Perl-Codes ausgelagert habe.

Seit 2007 sind diese Links nicht mehr funktionsfähig, daher habe ich sie entfernt.

Kibot ist ein in Python geschriebener IRC bot. Mit einfacher Pluginschnittstelle, so das man den gut als alround-bot auf einen Channel loslassen könnte.

erste Django-Anwendung life

So, meine erste Django-Anwendung ist life - noch nicht fertig, aber im Moment schon mal so gut, das sie besser ist als das alte PHP-Gemölter das da vorher lief. Und zwar gehts hier um meine Bildergalerie unter viele-bunte-bilder.de. Im Moment gibts zwar die Benutzerregistrierung und alles was damit zusammenhängt - aber das werd ich noch irgendwann mal einbauen. Oder auch nicht. Schaun mer mal.

Auf jeden Fall ist es schon mal ganz nett - ich kann Bilder wieder direkt aus iPhoto hochladen (was der wichtigste Vorteil der alten Galeriesoftware war) und die Sachen liegen im Filesystem, nicht in einer Datenbank - was ebenfalls ein recht wichtiger Punkt war.

Die Software selber ist natürlich verfügbar - wer stöbern will, ich hab eine Trac-Instanz mit meinen Django-Spielereien aufgesetzt.

Seit 2007 ist nix mehr davon online.

ObjectiveCLIPS

Way cool: Objective CLIPS ist eine neue Entwicklungsumgebung für OS X. Aus der Beschreibung:

Using Objective C runtime introspection, CLIPS, and FScript, it is possible to write intelligent Cocoa applications. Any Objective C object can be asserted as a fact in CLIPS, however, CoreData provides an additional meta model along with object persistence.

CLIPS ist eine Expertensystemumgebung die im Prinzip auf einem Lisp-Dialekt aufbaut und die Verwaltung von Regeln und Fakten ermöglicht, sowie das Reasoning darüber. FScript ist eine an Smalltalk angelehnte Scriptsprache die direkt mit den ObjectiveC-Klassen im OS X zusammenarbeitet. Beides zusammen sollte ziemlich coole Sachen ermöglichen, zumal mit CoreData auch einfach Datenbanken und Dokumente erstellt werden können. Und beide Sprachen (CLIPS und FScript) fand ich bei meinen Spielereien damit recht interessant - CLIPS war sogar längere Zeit bei mir als "Lisp-Ersatz" im Einsatz, weil es zwar ein recht altmodisches Lisp ist, aber dafür eben mit mächtigen zusätzlichen Abstraktionsmöglichkeiten ausgestattet ist.

RSS 3 - gleich zweimal

Mal wieder jemand der meint er könne ein tolles neues Format kreieren: RSS 3.0 - und der jemand ist zu blöd vorher mal zu googlen. Denn sonnst wäre er über RSS 3.0 gestolpert und hätte vielleicht mal nachgedacht.

Ach watt, nachdenken zählt nicht zu den üblichen Tätigkeiten von tollen Erfindern von Syndizierungsformaten, hat man ja schon in der Diskussion rund um Atom gemerkt. Ich bin immer noch überzeugt das die ganze Syndizierungsformate nur ein grossangelegter netzpsychologischer Test sind.

Heise hat auch was drüber. Und genauso Rogers Cadenhead - der ja im RSS Advisory Board sitzt.

Writing PlugIns beschreibt wie man iPhoto Exporter Plugins erstellt. Könnte mal ganz interessant sein.

Django hat einen wichtigen Schritt für den Release 1.0 gemacht: anonyme Sessions. Bisher waren ja Sessions bei Django an eine Benutzeranmeldung gekoppelt, aber jetzt gehts auch ohne Registrierung. Wesentlich netter als tausende Cookies beim Benutzer zu erzeugen.

CRUD mit Django

Create, Read, Update, Delete - die Standardfunktionen klassischer Interfaces - kann man mit Django sehr einfach zusammenbauen. Dazu gibt es die Generic Views. Auf Postneo gibts jetzt ein CRUD Tutorial, welches zeigt wie simpel solche Oberflächen mit Django zusammengestellt werden können.

Mal was interessantes in Rails

Endlich mal eine Anwendung in Ruby on Rails die über die üblichen Beispielanwendungen hinaus geht - und nicht einfach ein Weblog oder eine total sinnlose Todo-Listen-Verwaltung oder Artverwandtes ist: VitalSource ist eine iTunes-ähnliche Anwendung für Bücher mit einem entsprechenden Backend und einem ebenfalls auf Rails aufbauenden (aber in der Anwendung integrierten) Frontend:

Apparently their backend applications have been running Rails for a while. But they've recently released their client software, and it runs Rails as well. Except... you won't see it running in a conventional browser. As the picture shows, the Rails app runs embedded within the client executable: in the case of the Mac client it uses WebKit to render the responses from the Rails app.

Mir gingen schon die ganzen Rails-Anwendungen - die irgendwie alle nach Übungsbuchaufgaben klangen - auf den Wecker.

A comparison of Django with Rails ist ein recht guter Vergleich von Rails und Django. Wobei Vergleich bei zwei Systemen die durchaus unterschiedliche Themen adressieren natürlich recht schwierig ist - aber der Artikel versucht zumindestens die beiden Frameworks gegeneinander zu positionieren.

Lebende Daten

Komischer Titel, oder? Naja, mir ist einfach nur was aufgefallen bei der Beschäftigung mit Webframeworks und anderen Anwendungen, speziell im Ruby und Pyhton Umfeld. Und zwar die Art und Weise wie Minidaten gespeichert werden und wie zum Beispiel Konfigurationsdaten gehalten werden.

Im Java-Umfeld gibts da eine Inflation von XML-Mini-Languages - Berge von toten Daten. Tot deshalb, weil diese Daten eben nur im XML-Format leben und nur über XML-Werkzeuge bearbeitet und verändert werden können - habe ich zum Beispiel sich ständig wiederholende oder algorithmisch beschreibbare Konfigurationsblöcke (z.B. einen Berg von sich ziemlich ähnlich sehenden URL-Mustern für ein Webframework), kann ich diese nur über XML-Werkzeuge generieren - z.B. mittels XSLT aus einfacheren Formaten generieren. Oder ich schreib mir kleine Tools dafür.

In Ruby sieht die Situation ähnlich aus - nur das da statt XML dann eben YAML genommen wird. Letztendlich ist das aber auch nicht besser - die Konfiguration ist immer noch ein totes File.

Aber sowohl im Python-Umfeld als auch bei diversen anderen dynamischen Sprachen gibt es eine gute Alternative dazu: nimm einfach ein Modul in deiner Programmiersprache. Denn zum Beispiel Pythonmodule leben - ist die Struktur komplexer, aber teilweise repetitiv - einfach eine kleine Python-Funktion schreiben die bei der dynamischen Erstellung der Config hilft. Soll die Config teilweise aus Datenbankinhalten kommen - einfach eine Python-Funktion schreiben die diese Daten zur Laufzeit aus der DB liest und in die Config einmischt. Lebende Konfigurationdaten eben.

Natürlich kommen so Sicherheitsprobleme mit ins Spiel - wir wollen ja nicht den PHP-Fehler mit dem ewigen eval wiederholen. Was dazu also dringend notwendig wäre, wäre eine saubere Sandbox für solche Module. Leider ist genau da in Python ein massives Loch in der Implementierung. Es gab früher mal die Bytecodehacks, die auch wiederbelebt wurden - aber das sind eben nur Hacks. Auch die Methode mittels eingeschränkter Imports und Proxy-Objekten eine Scheinsandbox aufzubauen wie es Zope macht ist nicht der Weisheit letzter Schluss.

Perl bietet hier - wie bei allen Sicherheitsfeatures in Perl üblich wird das natürlich von fast keinem Projekt verwendet - eine sehr saubere Methode über die safe execution. Man kann bis ins kleinste hinein reglementieren was der Code in einer solchen Sandbox darf - und damit ist eine Konfiguration über Perl-Modul definitiv besser abzusichern als in Sprachen ohne so ein Konzept.

Java selber hat natürlich ein ziemlich ausgefeiltes Sicherheitsmanagement - zwangsweise, es soll ja auch in Browsern mit sehr stark beschränkten Rechten laufen. Dieses Security-Modell ist auch für Anwendungen nutzbar und könnte zum Beispiel für Servlets oder eben auch Java-Configs zum Einsatz kommen - vor allem da man mit Java ja auch problemlos Files zur Laufzeit übersetzen und dynamisch laden kann. Erklär mir jetzt mal einer warum die Java-Leute so fixiert auf XML sind, wo sie doch die besten Grundlagen für sichere lebende Daten haben ...

Das Safe-Modell von PHP ignorieren wir hier mal geflissentlich, denn das ist ein Sekt-oder-Selters-Modell - entweder läuft jeder Code unter safemode, oder garkeiner. Was wir bräuchten wäre aber eine selektive Aktivierung unterschiedlicher Sicherheitsklassen für einen einzelnen Codeblock oder Modulimport (ok, Modulimporte hat PHP auch nicht, nur Includes - ich sag ja, wir ignorieren es einfach mal).

Bisher kann man also bei Python nur dann mit lebenden Konfigurationen arbeiten, wenn man sich sicher ist das die Konfigurationen nur von Usern ohne böse Absichten bearbeitet werden. Django zum Beispiel benutzt nur lebende Konfigurationen - es wäre daher eine ziemlich dumme Idee, würde man z.B. die Konfigurationdateien bei zentral gehosteten Anwendungen über das Web editierbar machen.

Wir brauchen dringend eine saubere Sandbox für Python. Ich glaube sogar das wäre ein wichtigeres Teilprojekt als die diversen syntaktischen Erweiterungen die immer wieder angegangen werden.

wxWindows jetzt auch für Common Lisp

wxCL bietet Common Lisp Libraries für die Nutzung der genialen wxWindows GUI Bibliothek. Sehr schön - ich habe wxWindows in seiner Python-Inkarnation schon zu schätzen gelernt, auch in Scheme (über DrScheme) ist es sehr hilfreich, jetzt dürfen auch Common Lisper. Ich weiss das bei Common Lisp natürlich CLIM (heute oft in der Form von McCLIM) das Toolkit der Wahl ist, zumal es wesentlich mächtiger als wxWindows ist. Aber trotzdem ist es schon nett eine Cross-Plattform GUI Bibliothek zu haben, auch und gerade weil es diese eben für mehr als eine Programmiersprache gibt.

die seltsame Neigung der PHP-Programmierer zu eval

Schwachstellen in PHP-Modulen gefährden (mal wieder) zahlreiche Webapplikationen - und zwar wieder mal XML-RPC. Da wird immer noch eval benutzt - und zwar zur Auswertung von Tags. Bitte was? Sorry, Leute, aber das ist einfach nur noch albern - eval ist euch schon mal um die Ohren geflogen, warum wurden die ganzen Aufrufe nicht damals schon rausgeworfen? Oder wenigstens vernünftig gesichert?

Und da wundern sich Leute wenn ich von PHP-Software nicht allzuviel halte ...

trac - Softwareprojektmanagement leicht gemacht

trac ist ein Webinterface für Subversion -Repositories. Allerdings ist es nicht nur die passende Weboberfläche - dazu kommt ein Wiki, ein Bugtracking-System, eine Meilensteinverwaltung und sehr komfortabel zu erstellende Reports auf Basis des Bugtrackings. Und das ganze in einer sehr leicht installierbaren Packung - bei Debian genügt ein apt-get install trac und dann mit trac-admin initenv eine Trac-Instanz erzeugen. Das ganze sieht auch noch recht ansprechend aus und die Funktionen sind sehr gut integriert - Links aus den Tickets ins Wiki oder Links von Changeset-Bescheibungen in das Wiki oder das Bugtracking sind einfach zu machen und helfen natürlich gewaltig bei der Verwaltung der Softwareänderungen. Dazu kommt eine nette Timeline die Änderungen am System dann zeitlich dokumentiert und verlinkt - unter anderem auch auf einen sehr komfortablen Changeset-Browser.

Ich hab für TooFpy jetzt das ganze handgestrickte Zeugs weggeworfen und auf trac umgestellt. Allein schon die Möglichkeit meine bisher im Sourcetree verwaltete ToDo-Liste jetzt über Tickets den geplanten Releases zuzuordnen bringt eine Menge Überblick über das Projekt.

Yep, wer ein Softwareprojekt verwalten muss sollte sich definitiv trac mal angucken, denn wer nicht unbedingt Kontrollfetischist ist wird sicherlich mit der eher offenen Struktur von trac glücklicher als mit manchem overengineered Teil.

kenosis ist eine Python Library für ein einfaches P2P-Protokoll das auf XMLRPC aufbaut. Simpel und schlicht, allerdings ohne jegliche Form von Verschlüsselung - sollte also über extern verschlüsselte oder anderweitig gesicherte Wege benutzt werden.

Nitro ist ein Webframework für Ruby. Klar als Konkurrenz zu Rails ausgelegt adressiert es einige der Schwächen von Rails - zum Beispiel die recht mageren Object-Relation-Mapper in Rails über ActiveRecords. Nitro benutzt da Og. Auch sonst sind die Features deutlich besser ausgebaut - mehr Code, weniger Hype.

XchatPython ist ein Plugin für X-Chat mit dem man Erweiterungen in Python schreiben kann.

Mathematische Unkenntniss

Es ist ja schon fast modern zu erzählen wie schlecht man in Mathe war (ich nicht, ich war sehr gut in Mathe - und ja, mir hat Mathe sehr viel Spaß gemacht), aber wenn man dann von James Gosling die Fragen zu Sinus/Cosinus und den Sinn der Periodendefinition mit 2*Pi liest, dann packt man sich schon an den Kopf. Slava Prestov sieht darin immerhin die Erklärung warum die meisten Programmierer saublöde Fragen zu simpelsten mathematischen Problemen stellen, wenn selbst die Grössen der Branche einfache Trigonometrie nicht kapieren ...

International Components for Unicode ist eine Library von Referenzimplementierungen der ganzen Unicode-Standards, speziell die Transformation, Normalisierung und Sortierung von Zeichen betreffend, aber auch viele andere Lokalisierungsprobleme wie Datumsformatierung etc.

PyICU ist eine Integration der ICU C++ Schnittstelle in Python. Scheint recht vollständig zu sein, was den Umfang angeht. Integration mit Python Stringdatentypen ist ebenfalls gegeben.

Connecting databases to Python with SQLObject ist eine ganz nette Einführung in SQLObject - einen der netteren Object-Relation-Mapper für Python.

Unicode HOWTO für Python. Sollten Python-Programmierer lesen.

Crypt::PasswdMD5 ist ein Perl-Modul das MD5 Passwörter so hashed wie es Linux und Solaris auch tun.

md5crypt.py ist der gleiche Algorithmus für MD5 Passwörter, nur diesmal in Python.

Passwörter als Hashes speichern - sicher?

Nicht mehr ganz neu (Sommer letzten Jahres war es neu, aber da hab ich es irgendwie verpasst, das zugrundeliegende Paper ist sogar schon 2 Jahre alt), aber immer noch interessant: Project RainbowCrack ist ein Projekt das die Erstellung von Tools zum schnelleren Knacken von Hashes zum Ziel hat. Hashes können normalerweise nur durch brute force aufgelöst werden - unterstützt durch algorithmische Schwächen (wie kürzlich bei MD5 und SHA1 gefunden). Es gibt aber einen Ansatz die aufwändigeren Berechnungen die beim brute-force-Vorgang anfallen (also im Prinzip algorithmische Teilschritte) schon im Vorhinen zu erstellen - zum Beispiel wenn man eh nur vor hat z.B. Passwörter mit maximaler Zeichenzahl zu knacken.

Das ganze kommt natürlich nicht umsonst: man tauscht Rechenzeit gegen Speicherplatz ein. Tabellen zum Knacken von bis zu 14 stelligen Windows Passwörtern belegen lockere 64 GiB an Speicher. Die praktische Relevanz des Ansatzes und der Tools wird aus diesem Zitat vielleicht offensichtlich:

Some ready to work lanmanager and md5 tables are demonstrated in Rainbow Table section. One interesting stuff among them is the lm #6 table, with which we can break any windows password up to 14 characters in a few minutes.

Zu Project RainbowCrack gibts auch noch eine Weboberfläche zu einem verteilten Rechencluster über die man MD5-Hashes an einen MD5-Cracker schicken kann und der dann - sofern es ein maximal 8 Zeichen langer String ist - den Klartext rausspuckt. Und das Teil baut nebenbei immer mehr Rainbow Tables auf, wodurch das Knacken nach und nach schneller wird.

Nur so als Warnung für diejenigen, die meinen das ein einfacher MD5 Hash (oder letztendlich nahezu jeder Hash) auf das Passwort ausreichend wäre. Unix-Systeme benutzen üblicherweise salted hashes - das Passwort wird um einen offenen Text erweitert und damit zusammen dann der Hash gebildet. Das verlängert im Prinzip das Passwort, auch wenn natürlich die Verlängerung nicht geheim ist - für die Rechenzeit oder die Tabellengrösse ist das wurscht, die Passwörter sind einfach länger und damit schwerer zu knacken. Ist aber auch nur eine Frage von Platz, bis die nicht sicher sind.

Besser sind Passphrases statt Passwörter - eben einfach normal lange Sätze. Zum Einen kann man sich diese häufig besser merken (viele Menschen können sich keine Telefonnummer merken, aber Zeilen aus Gedichten zitieren) und zum Anderen sind sie einfach länger (und vor allem flexibel lang), so das Rainbow Tables als Angriffsmethode ausscheiden. Die algorithmischen Schwächen von MD5 und SHA1 bleiben natürlich erhalten.

Ein Treeview in JavaScript der innerhalb von Seiten (ohne Frames) benutzt werden kann und trotzdem sich State merkt.

Mal wieder neues bei Django

Neues gibts da ja dauernd, aber diesmal wieder ein sehr interessantes Feature: das inspectdb Kommando liefert nämlich aus einer PostgreSQL Datenbank die ganzen Tabellen und Felder im Format eines Python Datenmodells. Zusätzlich werden - sofern in der Datenbank abgelegt - auch Fremdschlüssel gefunden. Sehr praktisch wenn man eine Oberfläche für eine bestehende Datenbank bauen muss, man spart sich viel Tipparbeit.

Ian Bicking darüber was bei SQLObject derzeit passiert - es war ja recht still um einen der nettesten SQL-Object-Layer für Python geworden, aber jetzt gehts weiter. Für mich interessantester Punkt: Toolunterstützung für Datenbankupgrades. Ein Punkt der zum Beispiel auch bei Django noch fehlt.

Coroutinen für Python

Philip J. Eby hat einen Patch zur Implementation von PEP 342 geliefert. Damit stehen die Chancen das Python in Zukunft Coroutinen haben wird sehr gut.

Und das wiederum bedeutet das Python eine - wenn auch primitive - Form von Continuations bekommt. Jetzt fehlt nur noch das sowas wie statesaver mit in Python integriert wird - für Multishot Continuations (ok, erstmal nur copyable Coroutines, aber das wäre immerhin der Anfang).

Das alles natürlich nur um dann endlich in Webframeworks mit Continuations arbeiten zu können. Ok, geht mit CherryFlow jetzt schon, aber es wäre schon wenn das ganze in das Mainstream-Python wandern würde.

Wer sich mal mit grösserer Erlang-Software beschäftigen möchte und einen Jabber-Server ausprobieren will, für den ist vielleicht ejabberd interessant - ein Jabber-Server der all die netten Features von Erlang ausnutzt um zum Beispiel einfaches Clustering und gute Datenverteilung zu bieten.

The Illusive setdefaultencoding

Ian Bicking hat in seinem Artikel über setdefaultencoding einen Verweis auf einen netten Trick drin: einfach mit reload(sys) das sys-Modul neu laden, damit setdefaultencoding verfügbar ist.

setdefaultencoding dient dazu einzustellen, welches Standardencoding bytestrings benutzen. Normalerweise ist das ASCII, kann aber auch auf iso-8859-1 oder utf-8 umgestellt werden - wenn man setdefaultencoding überhaupt hat. Das wird nämlich dummerweise beim Start der Python Laufzeitumgebung gelöscht - weil die Python-Macher da mal wieder die User bevormunden wollen.

reload(sys) ist natürlich etwas das nicht unbedingt für Vertrauen sorgt - sys ist ja ein nicht ganz unwichtiges Modul. Aber in meinen Experimenten hat es bisher gut geklappt und es hilft definitiv bei der ganzen Unicode-Problematik wenn man seinen programmen ein anderes Encoding als Standard verpassen kann.

Schöner wärs natürlich wenn in der Standarddistribution setdefaultencoding nicht mehr gelöscht würde. Klar, kann man auch erreichen durch einen Patch von site.py, aber das ist auch nicht besser als sys neu zu laden ...