Ein Webrahmenwerk wie Rubys Sinatra?

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Samstag 20. Dezember 2008, 14:49

Nachdem ich in einem Vergleich zwischen Python und Ruby ca. 2h erklärt hatte, wie Python und Django funktionieren, kam der Ruby-Mensch daher und zeigte Sinatra. Kann ich bitte ein genauso einfaches Rahmenwerk auch für Python haben?!

CherryPy kommt dem nah, doch man vergleiche einfach nur mal die beiden Webseiten. Sinatra suggeriert bereits mit seinem Layout Eleganz und Einfachheit während CherryPy einen mit Informationen erdrückt. Eine weitere Alternative könnte web.py sein. Statt Code sprechen zu lassen, listet die Website da lieber Zitate.

In beiden Fällen ist das "Hallo, Welt"-Beispiel aber nicht so klar und einfach wie bei Sinatra. Liegt das einfach an Ruby als bessere Sprache?

Vielleicht kann man (konzeptionell) Sinatra für Python portieren?

Hier ist mein Versuch:

Code: Alles auswählen

import sammy

@url('/')
def get():
    return "Hello, World!"
Da ich keine Blöcke habe, muss ich eine Funktion `get` benutzen. Die URL annotiere ich als Decorator. Dadurch kann ich alle Funktionen `get` bzw. `post` (usw.) nennen. Die Funktion `url` würde die Funktionen dann irgendwo registrieren.

Einen Webserver zu starten, ohne ihn explizit aufzurufen, könnte jedoch problematisch sein. Eine Idee wäre, ihn zeitverzögert eine Sekunde nach dem ersten Aufruf von `url` oder dem Import von "sammy" zu starten. Schön ist das allerdings nicht. Mir fällt jedoch nichts anderes ein, da ich keinen "loaded"-Hook habe, oder? Ha, nein, ich kann mich auch über atexit() anmelden und dann, wenn Python denkt, das Modul und Programm ist beendet, dann fange ich erst wirklich an. Oder mich mache folgendes:

In 'sammy.py' komme ich an den Namen des "__main__"-Moduls, welches ich dann nochmals lade, passende transformiere und ausführe, ohne jemals aus dem Import zurückzukehren. Das scheint mir noch am wenigsten gehackt. Ich kann da außerdem prüfen, ob sich die Datei ändert und sofort nachladen, das für die Entwicklung praktisch ist.

Bei Parametern in der URL kann ich ausnutzen, dass ich eine Funktion mit Parameterliste habe und brauche kein `params[]` wie Sinatra:

Code: Alles auswählen

@url('/say/:what')
def get(what):
    return "Ich sage %s." % what
Um die Variable zu matchen muss ich zwar auf `f.func_code.co_varnames` zugreifen, aber das ist IMHO vertretbar.

Wenn ich wie oben den Quelltext lade, kann ich ihn auch noch verändern. Folgende Transformation wäre relativ einfach möglich: Aus `"Hallo #{name if name else 'Welt'}"` mache ich `("Hallo %s" % (name if name else 'Welt'))"`. Für eingebettete Templates ist das ganz nett. Ich könnte auch ein "return" für das letzte Statement nachrüsten, doch das verändert vielleicht zu sehr die Semantik von Python.

Für Template-Variablen nutzt Sinatra (wie Rails) Exemplarvariablen, die es bei Python so nicht gibt. Man müsste auf `self` zugreifen, das ist aber nicht gebunden und müsste dann eine globale (bzw. threadlokale) Variable sein. Unschön. Dann lieber eine dedizierte globale Variable wie z.b. `c`, der man Attribute zuweist. Dann wird `@foo = ...` zu `c.foo = ...`. Alternativ muss man Variablen für Templates als dict oder als Schlüsselwörter angeben, was ich für vertretbar halte:

Code: Alles auswählen

@url('/say/:id')
def get(id):
    haml('say', foo=Foo.objects.get(id=id))

def template_say():
    return """
        ...
    """
Eingebettete Templates wie bei Sinatra wären mit einem """-String ebenfalls möglich - insbesondere, wenn ich das Modul wie oben beschrieben explizit lade.

Schließlich unterstützt Sinatra noch `before`-Filter, Methoden für Fehlermeldungen und `helper`, die dann in Templates als Funktionen zur Verfügung stehen. Da kann man eigentlich einfach eine Klasse zur Gruppierung benutzen (man beachte, dass es kein `self` gibt, weil das alles statische Funktionen werden):

Code: Alles auswählen

class Helpers:
    def entry(entry):
        haml('entry.haml', entry=entry)
Möglicherweise will man in Python auch immer eine Klasse benutzen. Dann bin ich fast bei CherryPy (ohne `self`) angekommen.

Code: Alles auswählen

class Webapp:
    @url('/')
    def get():
        return "Hello, World"

    @url('/:name')
    def get(name):
        return "Hello #{name}"
Was meint ihr?

Stefan
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Samstag 20. Dezember 2008, 15:41

So könnte man #{} in Strings in Python-Dateien ersetzen: http://gist.github.com/38336

Stefan
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Sonntag 4. Januar 2009, 18:43

Also ich persoenlich mag Glashammer (sozusagen Werkzeug + Jinja + Framework-Sachen), aber was Sinatra da macht ist schon ziemlich schick. So was aehnliches macht - auch wenn es wohl allgemein nicht so empfehlenswert sein soll - Karrigell.
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Antworten