Bottle: Micro Web Framework

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Markdown hat etwa den selben Funktionsumfang wie Creole, bietet allerdings standardmäßig keine Syntax für Wiki-Links (ein Umstand, den ich bewusst verschwiegen habe). Mir gefällt es schon aus dem Grund besser, dass TextMate einen Edit- und Preview-Modus dafür hat.

Ich konnte in 5min eigentlich nur Code zeigen und nicht erklären, warum er so und nicht anders aussieht oder ihn entsprechend herleiten. Das finde ich eigentlich nicht so gut. Deswegen wäre länger IMHO besser gewesen.

Mein Code enthält zudem (mindestens) einen Fehler. Das richtige Escapen von HTML und URLs und das korrekte Kodieren und Dekodieren von Strings in Bytes für die Templates ist auch ein Thema, das mehr Zeit bräuchte, da es mit das Schwierigste ist, wo man eigentlich Hilfe vom Rahmenwerk haben will.

Schließlich wäre es gerade für die Vergleichbarkeit nett, Sessions und/oder eine Benutzerverwaltung zu sehen. Da muss man dann auf einmal mehr eigenes Rahmenwerk bauen, als der Wiki eigentlich Code hat :)

Und zum Stopfen: Man merkt da vielleicht, dass mir die Worte fehlten. Aber zu diesem Zeitpunkt hatte ich das ganze gefühlt schon ein Dutzend Male durchgezogen (insgesamt haben mich die 5min etwa 2h Arbeit gekostet) und so fiel dann die Klappe.

Stefan
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Das "Stopfen" ist ja nicht schlimm. Musst nur schmunzeln :)

Ich weiß selber, dass einem bei sowas manchmal gern die Worte fehlen
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

sma hat geschrieben: Mein Code enthält zudem (mindestens) einen Fehler. Das richtige Escapen von HTML und URLs und das korrekte Kodieren und Dekodieren von Strings in Bytes für die Templates ist auch ein Thema, das mehr Zeit bräuchte, da es mit das Schwierigste ist, wo man eigentlich Hilfe vom Rahmenwerk haben will.
Unicode Support für SimpleTemplate ist übrigens in der Mache. Dazu wollte ich mich eh nochmal aus lassen, da ich die Problematik ziemlich kompliziert finde und es meiner Meinung nach keine Perfekte Lösung gibt. Vielleicht habt ihr ja Meinungen und Vorschläge dazu. Folgendes ist der Plan:

SimpleTemplate soll intern mit Unicode arbeiten. Bekommt es Bytes statt Unicode als Quellcode-Input, wird self.encoding (Voreinstellung: utf8) verwendet, um den Kram zu dekodieren. Kommt in den ersten zwei Zeilen der Eingabe ein PEP263 String vor (...coding=latin9...) wird self.encoding entsprechend abgeändert und der Rest der Daten mit dem neuen encoding dekodiert. Templates verhalten sich demnach ähnlich wie normale Python Skripte, was das encoding angeht. Das hat den großen Vorteil, das der App-Entwickler nicht wissen muss, mit welcher Kodierung der Template-Designer seine Templates gespeichert hatte und Templates damit austauschbar und universal einsetzbar werden.

Wird das Template mit Daten gefüllt, funktioniert das genau umgekehrt: Byte Input wird automatisch mit utf8 in Unicode umgewandelt, es sei denn es wird etwas anderes konfiguriert. Leider gibt es keine Möglichkeit, die PEP263 des aufrufenden Programms zur Laufzeit aus zu lesen. Empfohlen wird aber eh, nach Möglichkeit nur Unicode in die Templates zu stopfen.

Am Schluss wirft das Template einen großen Unicode-String aus, der sich recht fix in einem Rutsch in Bytes umwandeln lässt. Das macht Bottle ja schon länger automatisch.

Dieses Konzept ist für Python 3 oder eine Unicode-lastige Python 2 Umgebung optimiert. Sobald Bytes in das Template gestopft werden, wird die Geschichte langsamer, da sie erst einzeln in Unicode umgewandelt werden müssen.

Ein anderer Ansatz wäre, wie bisher die Templates intern als Bytes zu behandeln und den Input in Bytes umzuwandeln. Das spart in python2 Umgebungen ne menge umkodiererei (da die meisten Strings eh Bytes sind) macht aber große Probleme, wenn das Template-Encoding nicht mit dem Laufzeit-Encoding oder dem Output-Encoding überein stimmt.

Der dritte Ansatz wäre, native Strings zu verwenden. Also Bytes unter 2.x und Unicode unter 3.x. Das ist allerdings die Entwickler-Hölle und wäre mir viel zu Bug-Anfällig. Ich weigere mich, so nen Krampf zu programmieren ;)

Zusammenfassend kann man sagen: Welche Variante schneller ist, hängt davon ab, ob die Templates hauptsächlich mit Bytes oder mit Unicode gefüttert werden. Einen klaren Gewinner gibt es nicht. Die Unicode-Variante macht auf mich aber einen saubereren und flexibleren Eindruck, weswegen ich mich dafür entschieden habe. Und spätestens mit Python 3.x ist Unicode eh die erste Wahl.
sma hat geschrieben: Und zum Stopfen: Man merkt da vielleicht, dass mir die Worte fehlten. Aber zu diesem Zeitpunkt hatte ich das ganze gefühlt schon ein Dutzend Male durchgezogen (insgesamt haben mich die 5min etwa 2h Arbeit gekostet) und so fiel dann die Klappe.
Spricht denn etwas gegen das nach-synchronisieren? Ich würde das Getippe mit einer provisorischen Audio-Spur aufzeichnen und dann das ganze nochmal in Ruhe nach sprechen. Oder wirkt das dann nicht mehr live genug?
Bottle: Micro Web Framework + Development Blog
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Unicode-lastiges (und UTF-8 kodiertes) Python 2 oder Python 3 finde ich gut. Mit nackten Bytes zu arbeiten (so wie es ja PHP macht) und dann zu hoffen, es wird schon passen, finde ich nicht gut. Es sollte eine bewusste Entscheidung sein, so wie es Django auch macht: Strings müssen immer echte Strings sein, also unter Python 2.x `unicode`-Objekte.

Das Nachsynchronisieren finde ich noch schwerer als es beim ersten Mal gleich richtig zu machen. Das habe ich einmal versucht und komme nie hin. Da müsste ich schon exakt aufschreiben und dann in richtiger Geschwindigkeit vorlesen, was ich sagen will. Daher bleibe ich lieber bei dem vielleicht nicht ganz so perfekten "live" gesprochenen Screencast.

Stefan
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Hallo Defnull.

Bottle ist Klasse. Läuft einwandfrei mit den OnboardServer.

Probleme habe ich mit der Installation unter Apache.

Ich hab mich an Dein Tutorial bei Paws gehalten.


Von Außen aufgerufen wird aber nur "Index of /todo" angezeigt.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ohne die Apache Konfiguration kann ich dir da nicht helfen. Anscheinend merkt dein Apache gar nicht, das die URL von Bottle gehandhabt werden soll. Es ist also kein Bottle, sondern erst einmal ein Apache-Problem.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Es gibt übrigens nen neues Feature im git: Auto Routes :D

Der @route() Dekorator kann nun auch ohne Parameter aufgerufen werden und generiert dann eine sinnvolle Route anhand der Funktions-Signatur (Funktions-Name und Argument-Namen). Damit spart man sich ne Menge Tipparbeit ;) Bei Argumenten mit Default-Wert werden sogar mehrere alternative Routen erstellt.

Beispiele:

Code: Alles auswählen

#'/a'
@route()
def a(): pass

#'/b/:x/:y'
@route()
def b(x, y): pass

#'/c/:x' and '/c/:x/:y'
@route()
def c(x, y=5): pass

#'/d' and '/d/:x' and '/d/:x/:y'
@route()
def d(x=5, y=6): pass

#/some/deep/path/:id
@route()
def some__deep__path(id): pass
Bottle: Micro Web Framework + Development Blog
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Defnull hat geschrieben:Es gibt übrigens nen neues Feature im git: Auto Routes :D
Ah, sehr schoen, da wollte ich auch mal was zu submitten, aber der Code wurde dann ziemlich unterirdisch, drum liegt das jetzt tot im "archive"-Ordner ;)
Benutzeravatar
snafu
User
Beiträge: 6850
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht wäre es besser, einen seperaten `@autoroute`-Decorator einzuführen und diesen dann ganz ohne Klammern aufrufen zu können. Das Modul [mod]contextlib[/mod] zeigt mit `@contextmanager` IMHO ganz gut, wie man das unter Zuhilfenahme von `@wraps` machen kann. (bzw in der Doku zu functools.wraps wrid das ja auch schon gezeigt)

Wenn dann nach einer Weile deutlich wird, dass das Autoroute-Verhalten der bevorzugte Weg für die Bottle-Nutzer ist, könntest du das ja evtl später zum Standardverhalten für @route machen (also ohne Klammern) und die alte Syntax zu "variant_route", oder was auch immer, machen.

Hihi, "Autoroute" war übrigens mal ein Routenplaner, den ich Anfang/Mitte der 90er auf meinem ersten Rechner hatte. :)

EDIT: Das `some__deep__path`-Beispiel/Verhalten fände ich mit jeweils einem Unterstrich gelungener.
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Defnull hat geschrieben:Ohne die Apache Konfiguration kann ich dir da nicht helfen. Anscheinend merkt dein Apache gar nicht, das die URL von Bottle gehandhabt werden soll. Es ist also kein Bottle, sondern erst einmal ein Apache-Problem.
Habe folgende Meldung im error.log des apache2:

mod_wsgi (pid=16024): Target WSGI script '/var/www/todo/adapter.wsgi' cannot be loaded as Python module.
Exception occurred within WSGI script '/var/www/todo/adapter.wsgi'.
"/var/www/todo/adapter.wsgi", line 9, in <module>
application = default_app()
name 'default_app' is not defined

Was für Conf-Dateien brauchst Du um weiter helfen zu können ?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Warum doppelte Unterstriche bei "foo/bar" und Autorouting? Ich halte es für extrem unwahrscheinlich, das jemand einen "_" in einer URL haben will (meist sind es "-" wie es sich nach der Lisp-Tradition auch gehört) und reicht dann nicht "foo_bar" als Name für "foo/bar"?

Und wie würde man zwischen verschiedenen HTTP-Methoden unterscheiden?

Stefan
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich würde vorschlagen einen autoroute Dekorator einzuführen, damit dekorierte Funktionen kümmern sich um alle HTTP-Methoden.
sma hat geschrieben:Und wie würde man zwischen verschiedenen HTTP-Methoden unterscheiden?
autoroute("post"), autoroute("get") oder autoroute.post, autoroute.get
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

sma hat geschrieben:Warum doppelte Unterstriche bei "foo/bar" und Autorouting? Ich halte es für extrem unwahrscheinlich, das jemand einen "_" in einer URL haben will (meist sind es "-" wie es sich nach der Lisp-Tradition auch gehört) und reicht dann nicht "foo_bar" als Name für "foo/bar"?
Ich persönlich verwende lieber Unterstriche als Bindestriche in URLs, wenn es darum geht, Leerstellen zu markieren. (Auch wenn Leerstellen in URLs möglich sind, das %20 ist hässlich). Außerdem wird in Python der Unterstrich oft in längeren Funktionsnamen verwende. Diese ungefragt in '/' zu übersetzen halte ich für unintuitiv und fehlerträchtig. Die Doppel-Unterstriche sind da expliziter, finde ich.
sma hat geschrieben:Und wie würde man zwischen verschiedenen HTTP-Methoden unterscheiden?
@post() oder @route(method='POST') oder @route(None, 'POST'). Man muss einfach den ersten Parameter frei lassen.
DasIch hat geschrieben:Ich würde vorschlagen einen autoroute Dekorator einzuführen, damit dekorierte Funktionen kümmern sich um alle HTTP-Methoden.
Gegen die Idee mit dem extra-dekorator für autorouten habe ich mich bewusst entschieden, da autorouten früher oder später zum Standard werden sollen. Der bisher übliche Route-String ist dann nichts weiter als ein optionaler Konfigurationsparameter, genau wie 'GET' der Standard ist und mit method='POST' überschrieben werden kann. Ansonsten tun implizite und explizite Routen ja exakt das selbe.

Allerdings plane ich, das @route, @get, ... auch ohne Klammern funktionieren und statt eines einzelnen Route-Strings auch eine Liste übergeben werden darf. Ich hatte auch die Idee, den docstring nach zusätzlichen Routen zu durchsuchen, aber da bin ich mir noch unschlüssig.

Im Endeffekt soll der @route Dekorator noch um einiges mächtiger und intelligenter werden. Schließlich ist das eine der wichtigsten Funktionen von Bottle.

PS: Alle HTTP Methoden abzufangen geht übrigens schon länger mit dem method='ANY' Schlüssel.
Zuletzt geändert von Defnull am Samstag 20. Februar 2010, 13:44, insgesamt 1-mal geändert.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

MrNiceTry hat geschrieben: Habe folgende Meldung im error.log des apache2:

mod_wsgi (pid=16024): Target WSGI script '/var/www/todo/adapter.wsgi' cannot be loaded as Python module.
Exception occurred within WSGI script '/var/www/todo/adapter.wsgi'.
"/var/www/todo/adapter.wsgi", line 9, in <module>
application = default_app()
name 'default_app' is not defined
Na da steht der Fehler doch schon: default_app() ist nicht definiert. Hast du die Funktion richtig importiert?
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Wie wäre es denn mit einer Konfiguration der Slashes durch sowas wie:

Code: Alles auswählen

import bottle
bottle.Router.slash = '_'
#oder
@route(slash='__'):
def a__b():
    return ''
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Defnull hat geschrieben:
MrNiceTry hat geschrieben: Habe folgende Meldung im error.log des apache2:

mod_wsgi (pid=16024): Target WSGI script '/var/www/todo/adapter.wsgi' cannot be loaded as Python module.
Exception occurred within WSGI script '/var/www/todo/adapter.wsgi'.
"/var/www/todo/adapter.wsgi", line 9, in <module>
application = default_app()
name 'default_app' is not defined
Na da steht der Fehler doch schon: default_app() ist nicht definiert. Hast du die Funktion richtig importiert?
Ich habe mich da streng an Dein Tutorial gehalten.
Dort wird in der todo.py wie folgt importiert:

Code: Alles auswählen

# only needed when you run Bottle on mod_wsgi
from bottle import default_app
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Das kann ja irgendwie nicht sein. Wenn du default_app in adapter.wsgi importierst, muss es auch definiert sein, sonst hätte es schon viel früher einen ImportError gegeben.

Edit: Du musst default_app natürlich auch in adapter.wsgi importieren (wie im Tutorial angegeben) und nicht nur in todo.py.
Bottle: Micro Web Framework + Development Blog
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Defnull hat geschrieben:Das kann ja irgendwie nicht sein. Wenn du default_app in adapter.wsgi importierst, muss es auch definiert sein, sonst hätte es schon viel früher einen ImportError gegeben.


adapter.wsgi
(original aus Deinem Tutorial unter http://bottle.paws.de/page/tutorial)

Code: Alles auswählen

import sys
sys.path = ['/var/www/todo/'] + sys.path

import todo
import os

os.chdir(os.path.dirname(__file__))

application = default_app()
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Defnull hat geschrieben:Das kann ja irgendwie nicht sein. Wenn du default_app in adapter.wsgi importierst, muss es auch definiert sein, sonst hätte es schon viel früher einen ImportError gegeben.

Edit: Du musst default_app natürlich auch in adapter.wsgi importieren (wie im Tutorial angegeben) und nicht nur in todo.py.

Ich habe den Import von default_app() in adapter.wsgi vorverlegt, bzw. dort nochmals eingetragen.

Das funktioniert jetzt.

Sorry, ich hab jetzt nochmals gesucht.
Aber die Stelle, wo das im Tutorial steht, kann ich nicht finden.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

MrNiceTry hat geschrieben: Sorry, ich hab jetzt nochmals gesucht.
Aber die Stelle, wo das im Tutorial steht, kann ich nicht finden.
Dann schau dir mal den Code-Schnipsel direkt über dem von dir zitierten Code-Beispiel an. Da steht ne lange import-reihe inklusive default_app
Bottle: Micro Web Framework + Development Blog
Antworten