Bottle: Micro Web Framework

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
orschiro
User
Beiträge: 60
Registriert: Donnerstag 11. Dezember 2008, 16:10
Kontaktdaten:

So ich bedanke mich für eure Hilfe. Das schaut schon sehr gut aus. Nginx ist nun mit mod_wsgi kompiliert. Hierzu habe ich diesen Patch verwendet.

Greife ich allerdings nun auf die Seite zu, erhalte ich einen 500 Internal Server Error. Ich denke, es liegt an der /home/foo/bar.wsgi. Wie hat diese denn auszusehen? Meine momentan wie folgt:

Code: Alles auswählen

# -*- coding: utf-8 -*-
from bottle import *
[...Programm-Code...]
#debug(True)
#run(host='0.0.0.0', reloader=True)

application = bottle.default_app()
Habe ich da etwas falsch verstanden?

Grüße
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Schau mal in die nginx-Logs und suche die Fehlermeldung. :)
orschiro
User
Beiträge: 60
Registriert: Donnerstag 11. Dezember 2008, 16:10
Kontaktdaten:

Der Tip war Gold wert. :)

Er scheint Probleme mit dem Statement "from bottle import *" zu haben. Das ist die Fehlermeldung aus dem log.

http://paste.pocoo.org/show/183926/
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Füge mal deiner wsgi-Datei noch ein `sys.path.append("/pfad/zu/bottle/")` hinzu. Und eines mit dem Pfad zum Package deiner Webanwendung.

Außerdem brauchst du in der wsgi-Datei überhaupt kein `import *` sondern nur ein `from bottle import default_app`. Das Beispiel das du da gepostet hattest würde nicht funktionieren, da es keinen Namen "bottle" gibt.
orschiro
User
Beiträge: 60
Registriert: Donnerstag 11. Dezember 2008, 16:10
Kontaktdaten:

Vielen Dank für deine Hilfe. Es funktioniert nun, auch dank der hilfreichen Erwähnung im Tutorial, welche ich zuerst übersehen hatte. :)

Grüße
MrNiceTry
User
Beiträge: 80
Registriert: Samstag 7. November 2009, 10:32

Hallo Defnull.

Teilweise machen bei mir die Umlaute ein Problem.

Ob es mit Bottle zu tun hat, weiß ich nicht.

Umlaute im Template werden korrekt in der Webseite angezeigt.
Umlaute die aus der MySQLDB kommen werden nur als Ersatzzeichen in der Webseite angezeigt.

Muß ich noch was einstellen?


Danke.
Benutzeravatar
snafu
User
Beiträge: 6831
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bottle 0.6.4 hat übrigens den Weg in die nächste Ubuntu-Version gefunden: http://packages.ubuntu.com/lucid/python-bottle
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Coole Sache das. Auch wenn Entwickler sich wohl lieber gleich die 0.7er holen sollten, oder?

Ich habe an besagter Version ein wenig geschraubt, um custom filter für jinja2 nutzen zu können:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bottle import route, run, debug
from bottle import jinja2_template as template
from markdown import markdown

TEMPLATE = u"""
<html>
<head><title>Custom Filter Test mit bottle</title>
<body>
<h1>Custom Filter Test</h1>
{{ text|md }}
</body>
</html>
"""

TEXT = u"Kleiner **Markdown** Text."

@route("/")
def hello():
    return template(TEMPLATE, text=TEXT, filters={"md": markdown})

debug(True)
run(reloader=True)
Wenn jemand Interesse daran hat, würde ich das mal versuchen als Patch anzubieten. Allerdings wird bottle ja auf github gehostet, für das ich keinen Account habe. Aber ein manuelles diff könnte ich wohl fertig bringen :-)
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Man braucht bei github keinen account, um an das Repository zu kommen.

Code: Alles auswählen

git clone git://github.com/defnull/bottle.git
...edit...
git commit -a
git format-patch ...
Alternativ kannst du dein git repository auch anderwertig frei geben und ich pulle direkt von dir. Wenn es unbedingt sein muss, geht auch ein normaler diff. In den meisen Fällen ist es dann aber einfacher, es schnell selbst zu coden.

@ubuntu: Ja, die haben einfach 1zu1 von Debian geklaut ;) Nun gibt es bottle in debian, ubuntu, NetBSD, ArchLinux und noch ein paar die ich vergessen habe. Ging schneller als erwartet :)

@MrNiceTry: Kaputte Umlaute haben nichts mit Bottle zu tun, sondern damit, das du kein utf8 aus lieferst und den charset nicht anpasst. UnicodeError exceptions hätten was mit Bottle zu tun, aber die kommen hoffentlich nicht mehr vor.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Defnull hat geschrieben:Man braucht bei github keinen account, um an das Repository zu kommen.

Code: Alles auswählen

git clone git://github.com/defnull/bottle.git
...edit...
git commit -a
git format-patch ...
Alternativ kannst du dein git repository auch anderwertig frei geben und ich pulle direkt von dir. Wenn es unbedingt sein muss, geht auch ein normaler diff. In den meisen Fällen ist es dann aber einfacher, es schnell selbst zu coden.
Ok, daran hatte ich nicht gedacht. Danke für den Hinweis. Werde ich nachher mal probieren; dann kannst Du ja gucken, ob es ins Konzept passt (ich weiß nicht, ob man so was nur für jinja brauchen kann, oder es "ähnliche" Fälle auch bei den anderen Template Engines sinnvoll sein könnte).

Kurze Frage noch zum Coding-Sytle: Du nutzt **args statt **kwargs; gibts dafür nen Grund? insofern müßte ich das dann noch anpassen ;-)
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Hyperion hat geschrieben: Kurze Frage noch zum Coding-Sytle: Du nutzt **args statt **kwargs; gibts dafür nen Grund? insofern müßte ich das dann noch anpassen ;-)
Solange dein Code sauber, kompakt, schnell und fehlerfrei ist, sind mir die Bezeichnernamen egal :) Ich selbst bin da leider etwas undiszipliniert.

Ganz allgemein, der ideale Patch ist:
- Wie gesagt: Sauber, kompakt, schnell und fehlerfrei.
- Per git erreichbar (github oder was privates). Alles Andere ist für mich recht umständlich.
- Konfliktfrei beim merge mit dem aktuellen master branch. Sonst kann ich es auch gleich selbst implementieren.
- Eingegrenzt auf ein ganz bestimmtes Problem. Bitte für jeden logisch unabhängigen Patch einen neuen, sauberen branch auf machen. Nichts ist ätzender als aus einer riesen Patch-Liste die richtigen commits raus zu suchen. (Der fork von sgala auf github z.B. ist leider nahezu unbrauchbar für mich geworden...)
Bottle: Micro Web Framework + Development Blog
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Zum Encoding ist mir noch was aufgefallen. Der IE erkennt als Charset UTF-8 nicht, wenn dieses nicht explizit im content-type angegeben wird.

Code: Alles auswählen

# funktioniert
response.content_type = 'text/html; charset=utf-8'
# funktioniert nicht
response.charset = 'utf-8'
Ohne erkennt er es selbstverständlich auch nicht.

Ist vermutlich eher ein IE spezifisches Problem, aber ich wollte es auf jeden Fall mal berichten. (Tritt außerdem mit IE6 und IE8 auf, also kein versionsspezifisches Problem.)
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

(Hinweise zum obigen Post: Habe gesehen, dass das in der neuen Version gefixt ist.)

Habe einen Vorschlag für bottle. Ausgangspunkt ist meine App um statische Dateien bereitzustellen:

Code: Alles auswählen

class StaticFileApp(object):
    def __init__(self, base=''):
        self.base = base
    
    def static_css(self):
        bottle.send_file('style.css', root=self.base)
        
    def static_ico(self):
        bottle.send_file('favicon.ico', root=self.base)

    def static_image(self, filename):
        bottle.send_file(filename, root=os.path.join(self.base, 'img'))
        
    def register_routes(self):
        route_add('/style.css', self.static_css)
        route_add('/favicon.ico', self.static_ico)
        route_add('/img/:filename#.*\.gif#', self.static_image)
Wie man sieht, muss man immer wieder fast die gleichen Funktionen/Methoden schreiben, was sehr umständlich ist.

Mein Wunsch wäre jetzt eine Funktion, die diesen Vorgang automatisiert, z.B. mit dem Namen "static_file_route" oder ähnliches. Diese sollte dann aus der übergebenen Route automatisch einen entsprechenden Callback mit "static_file" generieren und registrieren.
Ein sinnvoller Parameter für diese Funktion wäre dann noch ein Boolwert, der aussagt, ob "root" automatisch um die Pfade der Route erweitert werden soll oder nicht.
Bsp.

Code: Alles auswählen

#Paramater wahr:
# input:
route = '/img/blog/:filename'
root = ''
# output
root = 'img/blog'
Dürfte eine relative kleinere, aber IHMO sehr sinnvolle Erweiterung sein.

Edit: Im Prinzip wäre das dann eine Umkehrfunktion zu deinem "yieldroutes".
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Euch ist aber schon klar, dass das jetzt fast CherryPy entspricht und Defnull doch gerade erst irgendwo schrieb, dass er das nicht so gut findet :)

Stefan
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Ich schon wieder...
Bottle + CherryPy friert ein nach Strg+C bei folgendem Minimalbeispiel

Code: Alles auswählen

from bottle import route, run, CherryPyServer

@route('/')
def index():
    return 'Hello World'
    
run(host='0.0.0.0', server=CherryPyServer)
"Shutting Down" kommt noch, dann bleibt der Prozess offen. In Kombination mit dem reloader gibt es seltsamerweise keine Probleme.

Edit: OS ist WinXP.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

print "Shutting Down..." ist die aller letzte Anweisung von bottle.run(). Wenn der Prozess offen bleibt, dann liegt das entweder am aufrufenden Programm oder am CherryPy Thread pool. Auf manchen Systemen wird der Prozess erst vollständig beendet, wenn alle Threads beendet wurden. Wahrscheinlich funktioniert es mit dem reloader, weil dieser den Prozess mittels sys.exit() zur Beendigung zwingt. Nachvollziehen kann ich den Fehler auf meinem System allerdings nicht.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Bei mir es es so, dass sich bei Paste und Reloader nach einem KeyboardIntrrupt das Programm ebenfalls nicht beendet. Ebenfalls unter Windows (7).
[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]
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Defnull hat geschrieben:print "Shutting Down..." ist die aller letzte Anweisung von bottle.run(). Wenn der Prozess offen bleibt, dann liegt das entweder am aufrufenden Programm oder am CherryPy Thread pool. Auf manchen Systemen wird der Prozess erst vollständig beendet, wenn alle Threads beendet wurden. Wahrscheinlich funktioniert es mit dem reloader, weil dieser den Prozess mittels sys.exit() zur Beendigung zwingt. Nachvollziehen kann ich den Fehler auf meinem System allerdings nicht.
Ja, es liegt definitiv an CherryPy. Ein HTTP Request lässt sich noch durchführen, führt dann zu einem Timeout. Bekomme also keine "Server not found" Error-Page. Am aufrufenden Programm kann es ja nicht liegen, oder siehst du etwas merkwürdiges in meinem Minimalbeispiel?!

Edit: Was hälst du eigentlich von meinem Vorschlag? ("route_static_file")
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

@route_static_file: Ich weis jetzt nicht, warum bottle dafür ne extra Funktion braucht. Ist doch ein Zweizeiler (ungetestet).

Code: Alles auswählen

for filename in filelist:
  bottle.route('/%s'%filename)(lambda: bottle.static_file(filename, root='/var/www/static/'))
Wobei ich die Lösung mit einer einzigen dynamischen Route für mehr als 10 Dateien schon sinnvoller finde.
Bottle: Micro Web Framework + Development Blog
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Defnull hat geschrieben:Wobei ich die Lösung mit einer einzigen dynamischen Route für mehr als 10 Dateien schon sinnvoller finde.
Und wenn ich verschiedene Pfade habe? Darum geht es mir ja.
Es sollen also dynamische Routen aufgelöst werden. Deshalb der Wunsch einer Integration von bottle, ich will ja nicht noch in meiner App anfangen, die Routen zu parsen.

Bsp:

Code: Alles auswählen

route_list = ['/img/:filename', '/style/:filename', '/favicon.ico']
Edit: Oder kann ich wenigstens tief verschachtelte Ordnerstrukturen mit einer einzigen Route definieren? Z.B. sieht ein typischer Pfad bei mir so aus:

Code: Alles auswählen

app\gwt\standard\images\ie6

In jedem liegen natürlich auch noch Dateien, die bereitgestellt werden sollen.
Für jeden Pfad jetzt eine Route anzulegen, ist doch sehr lästig.

Da wäre eine Lösung mit glob oder os.walk + dein Beispiel-Code sogar viel eleganter.

Edit2: Mit so einer Funktion könnte ich mich natürlich auch anfreunden:

Code: Alles auswählen

set_static_folder(folder, root='', recursive=True, filter='.*')

Ich versuch mich mal selber daran, vielleicht ist sie es dann Wert, aufgenommen zu werden ;)
Antworten