Elegante Filterscripte mit Python und dem fileinput Modul

Im Alltag bin ich viel und gerne auf der Kommandozeile (Shell) unterwegs.

Häufig erzeuge ich dabei Daten, die wiederum als Eingabe für ein Python-Script dienen. Der Grund dafür ist die wunderbare Eigenschaft einer leistungsfähigen Shell bzw. des darunter liegenden Betriebssytems, dass beliebige Filterkommandos und deren Parameter miteinander verkettet werden können und die Ausgabe eines Kommandos in der Kette jeweils die Eingabe für das nächste Kommando ist:

cat access_log | egrep -i ".+Jan.+200.+googlebot.+" | egrep "66\.249" | wc -l
11

Dieses Kommando sagt mir z. B. wie häufig im Zugriffslog access_log meines Webservers der erfolgreiche Besuch, also HTTP 200, des Googlebots im Januar stattgefunden hat.

Das Ergebnis: Genau 11 mal. Das Pipe-Symbol “|” zwischen den Kommandos “cat”, “egrep” und “wc” ist dabei sozusagen das “Rohr”, das alle Kommandos miteinander verkettet und durch das die Daten jeweils vom linken Kommando in das rechte Kommando fließen.

Was aber wenn ich so ein Kommando in Python schreiben möchte? Und vor allem: Wie mache ich das möglichst schnell und einfach, ohne große Mengen von Boilerplate Code zu schreiben?

Ich mache das so:

Dieses Script ersetzt ganz einfach die falsch geschriebene Adresse dieses Blogs gegen die korrekte Adresse und nutzt den praktischen Membership-Operator “in”, den Python bereit stellt. Das Ergebnis sieht so aus:

echo "Mein Blog ist unter www.suchkultur.net zu finden" | ./filter.py
Mein Blog ist unter www.suchkultur.de zu finden

Für mich ist das ein praktischer Skeleton, den ihr euch per Git von hier ziehen könnt: https://gist.github.com/4605608 .

Viel Spass auf der Commandline :-)

Django Grundlagen Workshop Rhein Main (PyUGRM)


Beim letzten Treffen der Python User Group RheinMain (PyUGRM) wurde klar, dass Python vor allem in Verbindung mit dem Django Web Framework ein Thema bei vielen Einsteigern ist. Die Meisten Besucher waren das erste mal bei der PyUGRM zu Gast, was uns natürlich sehr gefreut hat. Gleichzeitig scheint die Mehrheit ein großes Interesse am Web Framework Django zu haben.

Einige setzen es entweder schon ein oder planen sich damit zu beschäftigen. Ich zähle mich natürlich auch dazu. Mich persönlich erinnert das ein wenig an den Hype von Ruby on Rails vor ein paar Jahren, der viele positive Effekte für die Verbreitung der Sprache und die Ruby-Community hatte. Die Python Community ist meinem Gefühl nach eher als “still” zu beschreiben, wenn es darum geht die Sprache und das Ökosystem zu promoten. Die Qualität von Django spricht allerdings für sich und ich bin sicher, dass viele Entwickler bald ihren Werkzeugkasten um ein sehr praktisches Tool erweitern können ;-)

Aus diesen Gesprächen entstand daher der Wunsch einen Workshop zu machen, der die Grundlagen vermittelt und Raum für Fragen & Antworten zum Thema bietet.

Dieser Workshop ist nun fest geplant und wer teilnehmen möchte, der kann sich hier anmelden: http://de.amiando.com/django_frankfurt.html

Ich werde natürlich auch vor Ort sein.

Eine schlanke API für HTTP-Requests in Python

Python ist in seinen Grundeigenschaften eine Programmiersprache, die gut dazu geeignet ist schnell und elegant Aufgaben aller Art zu erledigen.

Von der Systemadministration über wissenschaftliches Arbeiten bis hin zur Webentwicklung ist alles problemlos mit Python möglich. Zusammen mit der umfangreichen Standardbibliothek und einer großen Anzahl von third party Modulen hat der Pythonista alles Nötige beisammen, um die typischen Aufgaben zu stemmen.

Da ich Python hauptsächlich dazu verwende um Plugins für das Monitoring-Werkzeug Nagios zu schreiben und dabei vor allem mit Webservern über HTTP kommuniziere, nutze ich in der Regel die urllib für diese Aufgabe. Die urllib ist in der Python Standardbibliothek enthalten und liefert mit urllib.urlopen() im Grunde alles um mit URLs umzugehen.

Warum jetzt aber ein weiteres Modul? Die Antwort ist denkbar einfach: Im modernen Web nutzt man nicht nur URLs alleine, sondern man muss sich darüber hinaus auch noch um um viele Details rund um die Kommunikation kümmern. Gerade die Authentifizierung gegenüber modernen REST Schnittstellen und die steigende Bedeutung von GET, POST, PUT, DELETE und HEAD im vielzitierten “Mitmach-Web” ist eine Aufgabe bei der bei Nutzung der urllib mehr Code nötig ist, als der typische Python-Entwickler von seiner API erwartet. Gerade wenn es um das Debuggen komplexer Vorgänge an REST-Schnittstellen geht ist weniger deshalb häufig mehr. Wer beispielsweise ein Modul für die Zahlungsabwicklung zwischen einem Webshop und einem – oder mehreren – Zahlungsdienstleistern implementiert freut sich über schlanken Quellcode und eine intuitive API im Sinne des PEP 20 oder schöner: “The Zen of Python”.

Kenneth Reitz hatte wohl das PEP 20 im Hinterkopf, als er auf Basis der urllib mit seinem requests-Modul eine Alternative geschaffen hat, die 90% der typischen Anwendungsfälle eines Webentwicklers abdeckt und gleichzeitig deutlich intuitiver zu handhaben ist.

Ein Beispiel in der die urllib mit Kenneth’s requests Modul verglichen wird gibt der Autor selbst. Der Beispielcode zeigt sehr schön das simple API-Design von Kenneth. Das häufig verwendete GET wurde direkt als Methode abgebildet und die bei Webservices obligatorische Authentifizierung ist als (optionaler) Parameter realisiert. Der Statuscode eines GET-Abrufs wird als einfacher Integer verfügbar gemacht und der beim GET-Request verwendete URL als String hinterlegt. Die gelieferten Header werden dagegen in ein handliches Dictionary gefüllt. Alles ganz so wie man es intuitiv erwarten würde.

Ein Beispielabruf anhand der populärsten HTTP-Methode (die Inhalte der einzelnen Felder stehen in Kommentarzeichen)

import requests
import pprint

r = requests.get("http://www.nytimes.com/")

r.status_code
# 200

r.cookies
# {'RMID': '32356e0019a84e6a16fb23b7', 'adxcs': 's*27d12=0:1|s*2550c=0:1|s*25056=0:1'}

pprint.pprint(r.headers)
#{'cache-control': 'no-cache',
# 'content-encoding': 'gzip',
# 'content-type': 'text/html; charset=UTF-8',
# 'date': 'Fri, 09 Sep 2011 13:39:07 GMT',
# 'expires': 'Thu, 01 Dec 1994 16:00:00 GMT',
# 'pragma': 'no-cache',
# 'server': 'Sun-ONE-Web-Server/6.1',
# 'set-cookie': 'RMID=32356e0019a84e6a16fb23b7; expires=Saturday, 08-Sep-2012 13:39:07 GMT; path=/; domain=.nytimes.com, adxcs=-; path=/; domain=.nytimes.com, adxcs=s*27d12=0:1|s*2550c=0:1|s*25056=0:1; path=/; domain=.nytimes.com',
# 'transfer-encoding': 'chunked'}

r.url
# 'http://www.nytimes.com/'

Analog zur GET-Methode funktionieren natürlich auch die anderen HTTP-Methoden, die das requests-Modul unterstützt.

Natürlich hat dieser 90% Ansatz von Kenneth Reitz auch seine Nachteile.

In den fehlenden 10% steckt beispielsweise die Möglichkeit Proxies zu verwenden, was man mit der urllib folgendermaßen notieren würde: (diese Information ist mittlerweile nicht mehr korrekt. Siehe Update am Ende dieses Artikels).

import urllib
proxies = {'http': 'http://proxy.example.com:8080/'}
opener = urllib.FancyURLopener(proxies)
f = opener.open("http://www.python.org")
f.read()

Da das requests-Modul noch nicht einmal seinen einjährigen Geburtstag gefeiert hat, ist davon auszugehen, dass sich in den nächsten Monaten hier noch einiges tun wird und aus der 90% Lösung vielleicht irgendwann die 99% Lösung wird. Zwingend nötig ist das allerdings nicht, denn das gesetzte Ziel über die urllib einen leichtgewichtigen Wrapper zu stülpen, der die urllib für viele erst sinnvoll benutzbar macht, hat Kenneth Reitz schon erreicht.

Update:

Mittlerweile unterstützt das requests Modul Proxies, wie man in der Dokumentation bei “Proxies” unter “Advanced Usage” nachlesen kann.

Haystack Search für Django ist in Version 2.0.0 Alpha verfügbar

Haystack ist eine Python-API, die eine modulare Anbindung unterschiedlicher Suchmaschinen-Backends für das Web Framework Django realisiert. Haystack verhält sich dabei wie eine Django-App, die als Abstraktionsschicht für unterschiedliche Suchmaschinen-Backends dient. Das ist vergleichbar mit dem objektrelationalen Datenbank-Layer, den Django als Kernfunktion bereits mitbringt.

In der Version 2.0.0 Alpha von Haystack ist es nun möglich mehrere Suchmaschinen gleichzeitig zu verwenden. Dadurch werden jetzt zum Beispiel Master/Slave Installationen oder die Nutzung unterschiedlicher Suchmaschinen und/oder Indexe für verschiedene Anforderungen möglich.

Beispielsweise könnte ein spezialisierter Index für diverse Autocomplete-Funktionen genutzt werden, und ein zweiter Index liefert die eigentlichen Suchergebnisse. Auch denkbar ist die Nutzung verschiedener Indexe für unterschiedliche Nutzergruppen. Dabei kann beispielsweise ein Index für die öffentlichen Inhalte einer Webseite gedacht sein, und ein separater Index ist nur für eingelogte Nutzer zugänglich.

Den aktuellen Entwicklungsstand kann man sich auf Github besorgen.