Seite 23 von 30
Verfasst: Mittwoch 7. April 2010, 22:26
von DasIch
@snafu So ein Dekorator macht durchaus Sinn, allerdings sollte es Teil des Routing Systems sein. Eine Route /archive/:year/:month/:day/ soll z.B. /archive/2010/10/03 matchen aber nicht /archive/2010/15/123/ oder gar /archive/foo/bar/baz, da soll ein 404 bei rum kommen ohne dass ich mich da drum weiter kümmern muss.
Verfasst: Donnerstag 8. April 2010, 08:29
von Defnull
Der @validate dekorator ist in der neuen Doku schon undokumentiert und in zukünftigen Versionen wohl auch bald nicht mehr drin. Er tut nichts, was man nicht besser innerhalb der Applikation lösen könnte und so gut wie niemand nutzt ihn.
Die Idee von DasIch ist witzig, aber wohl etwas magisch.
Verfasst: Donnerstag 8. April 2010, 08:56
von snafu
Defnull hat geschrieben:Er tut nichts, was man nicht besser innerhalb der Applikation lösen könnte
Genau das.
Defnull hat geschrieben:Die Idee von DasIch ist witzig, aber wohl etwas magisch.
Naja, Datumsparsen nimmt vielleicht nochmal einen Sonderfall ein. Wäre doch witzig, wenn beim gezeigten Beispiel direkt ein (eben mit strptime() geparstes) Datetime-Objekt an die verarbeitende Funktion übergeben würde. kA wie oft das in der Praxis gebraucht wird. Dafür sollte man sich aber besser was für innerhalb der Route-Syntax ausdenken. Ich glaube, so war das auch von DasIch gemeint.
Verfasst: Donnerstag 8. April 2010, 12:34
von DasIch
Defnull hat geschrieben:Die Idee von DasIch ist witzig, aber wohl etwas magisch.
Man bräuchte natürlich eine andere Syntax wie sie z.B. werkzeug.routing hat.
Verfasst: Donnerstag 8. April 2010, 19:40
von noisefloor
Hallo,
Er tut nichts, was man nicht besser innerhalb der Applikation lösen könnte
Wohl war. Ich nutze ihn auch nicht - wenn ich gezielt was prüfen will, dann schreibe ich dafür lieber einen eigene kleine Funktion im Programm. Außerdem ist es so, dass man @validate eigentlich nur sinnvoll mit einem @error(403) nutzen kann - sonst wirft's eine Fehlermeldung, und der Nutzer ist auch nicht schlauer.
Erschwerend kommt dann noch dazu, dass @validate bestimmte Sachen konvertiert...
und so gut wie niemand nutzt ihn
Ist das so?
Gruß, noisefloor
Verfasst: Donnerstag 8. April 2010, 20:15
von Defnull
noisefloor hat geschrieben:und so gut wie niemand nutzt ihn
Ist das so?
Ich schaue mir eigentlich jedes Projekt, jedes Code Fragment und jede Frage in den Newsgroups und Mailinglisten, die Bottle betreffen, sehr genau an und versuche zu verstehen, wie Bottle benutzt wird und was die Anwender wollen oder brauchen. @validate wird fast nie und wenn dann falsch genutzt. Außerdem sagt niemand "Bottle ist cool, schau dir den @validate dekorator an". Daher meine Vermutung, das es überflüssig ist
@validate() gehört zu den Features, die nie perfekt sein werden. In allen einfachen Szenarien kann man ähnliche oder bessere Lösungen ohne großen Aufwand selbst implementieren. In den meisten komplexen Szenarien ist das Feature zu eingeschränkt oder umständlich, um es sinnvoll einsetzen zu können. Es wirkt wie gewollt aber nicht gekonnt. Ähnlich wie die Datenbank-Implementierung in frühen Bottle-Versionen. So etwas hat keinen Platz in Bottle und fliegt irgendwann raus

Dafür bin ich zu sehr Perfektionist

Verfasst: Freitag 9. April 2010, 00:50
von snafu
Ein Vorschlag, der mir noch eingefallen ist, zur Annahme/Validierung bestimmter Typen ohne den Code unnötig aufzublähen (wie es ja durch @validate leider passiert): Man könnte den Typen wie ähnlich wie beim String-Formatting integrieren:
Passt etwas nicht, gibt es logischerweise einen Fehler. Die Argumente werden dabei in der gleichen Reihenfolge "anonym" an die Handler-Funktion übergeben, welche sich eben selbst um die Benennung kümmert. Man müsste sich natürlich überlegen, ob das beispielhaft genannte %s grundsätzlich alles annimmt und in seiner String-Form belässt oder ob seine Verwendung impliziert, dass an dieser Stelle keine Zahlen erlaubt sind. Insgesamt könnte das unter Umständen ganz schön komplizierte Ausmaße annehmen, womit sich wieder die Frage stellt, ob man das wirklich einbauen sollte. Die Sache mit dem Datetime-Objekt finde ich aber nach wie vor gut.

Verfasst: Freitag 9. April 2010, 03:10
von snafu
Andererseits: Routen könnten Bezeichner *und* Datumsteile haben, so dass ein einfaches Weitereichen an strptime() wieder schwierig wird. Die mögliche Lösung: Auslagerung des kompletten Codes, der den Routen-String parst, in eine eigene Funktion, dann `parser` als Keyword-Argument für @route, welcher standardmäßig auf `bottle.route` eingestellt ist. Möchte man also individuelles Parsen, so weist man `parser` eine eigene Funktion zu. Nehmen wir also an, man hat ein Wiki und dort die formatierten Artikel und den zugehörigen Wikitext abgelegt. Dann könnte ich mir sowas vorstellen:
Code: Alles auswählen
def wikiparse(route_string):
date, title = bottle.parse(route_string)
struct = strptime(date, '%Y%m%d')
return struct.tm_year, struct.tm_mon, struct.tm_mday, title
Es wird also zunächst alles ermittelt, was der Bottle-Parser versteht und dann das eigene Parsing angewendet. Die zurückgegebenen Objekte bekommt dann wiederum die Handler-Funktion übergeben, so wie es auch normalerweise ist. Ich hab's nicht getestet, aber rein theoretisch sollte dann sowas gehen:
Code: Alles auswählen
wikiroute = partial(bottle.route, parser=wikiparse)
@wikiroute('/articles/:date/:title/'):
def article(year, month, day, title):
[...]
@wikiroute('/wikitext/:date/:title/'):
def wikitext(year, month, day, title):
[...]
Neben der Wiederverwendbarkeit hätte man damit auch den Parser-Code seperat und könnte die Funktion nur mit "internetspezifischem" Kram füllen. Das mag auf dem ersten Blick kompliziert erscheinen, aber ist andererseits IMHO sehr flexibel, erspart dir das Nachdenken über spezielle Syntax mitsamt dem Handling und bei "normalen" Routen merkt der Programmierer ja eh nichts davon.
Die Meinung von DasIch, dass ein Framework automatisch seine Routen auf Typen prüfen soll, teile ich nämlich an sich nicht. Man sieht ja, welche Probleme da bei der Implementierung entstehen können. Auch wenn es natürlich erstmal toll klingt, dass Eingaben wie Objekte behandelt werden und Teile mit Zahlen z.B. direkt als Zahlen übergeben werden. Hier könnte man - wenn's denn unbedingt sein soll - höchstens eine rudimentäre Auto-Erkennung einbauen, die meintetwegen reine "Zahl-Verzeichnisse" erkennt und umwandelt.
Naja, das sind so meine Einwürfe. Du bist ja zum Glück relativ offen, was neue Ideen angeht. Und vielleicht gibt es ja noch weitere Meinungen dazu...

Verfasst: Freitag 9. April 2010, 08:28
von nemomuk
Ich finde nicht, dass eine automatische Typumwandlung direkt in die URL-patterns gehört. Das macht die weitere Verarbeitung der Daten in einer view-Funktion sehr undurchsichtig und teilweise auch fehleranfällig, wie ich finde.
Bei snafus wikiparse frage ich mich, wo der Vorteil dabei sein soll? Das macht das ganze ziemlich undurchsichtig und kompliziert. Außerdem erspart es einem auch nicht wirklich Arbeit...
Code: Alles auswählen
@route('/articles/:date/:title/')
def article(date, title):
struct = strptime(date, '%Y%m%d')
[...]
Lasse mich natürlich auch gerne vom Gegenteil überzeugen, aber dieses Beispiel ist dafür irgendwie nicht sonderlich passend und konnte mir auch keine geeignete Situation dafür vorstellen.
@defnull: habe den reloader mal etwas verbessert, siehe Pull-Request
Verfasst: Freitag 9. April 2010, 09:04
von snafu
Na, sagen wir mal du hast ein Nachrichtenportal und ordnest dort nach Rubriken. Will ich den heutigen Artikel vom Sport lesen, erreiche ich ihn mit `/articles/sport/20100409/`, den zu Stars & Sternchen mit `/articles/vip/20100409/`, den für Computerthemen mit `/articles/it/20100409/`, usw. Hier würde man doch vermutlich in jeder Handler-Funktion den Prozess des Datumsparsens und die Zerlegung in `year`, `month`, `day` durchlaufen, oder nicht? Selbst, wenn man das in eine eigene Funktion packt, müsste diese Funktion jedes Mal am Anfang aufgerufen werden.
Wenn man es aber - wie gezeigt - mittels `functools.partial()` an einen wiederverwendbaren Namen bindet, der als Dekorator benutzt werden kann, dann hat man zwar einmal die Mehraufwand, kann sich aber bei seinen 15 Rubriken darauf verlassen, dass bei Verwendung des eigenen Dekorators, der immer wieder gebrauchte Validierungs-/Umwandlungsprozess automatisch durchgeführt wird. Ich gebe zu, die Beispiele sind etwas utopisch. Vielleicht braucht man sowas auch überhaupt nicht. Das war gestern nur so ein Gedankenblitz. Und ich betone, dass das als eine Art syntaktischer Zucker für Sonderfälle gemeint ist. Eben Fälle, bei denen man seine Routen wie beschrieben strukturieren will.
Verfasst: Freitag 9. April 2010, 10:05
von nemomuk
Ja, das ist alles Geschmackssache, wobei in deinem neuen Fall, die URL sowieso so besser strukturiert wäre:
und sich damit die Funktion wieder erübrigt.
Grundsätzlich denke ich, dass URLs nie so kompliziert sind um sie in extra Funktionen auseinandernehmen zu müssen - wenn, dann denke ich hat man da etwas falsch designt.
Verfasst: Freitag 9. April 2010, 10:08
von BlackJack
@snafu: Was meinst Du mit "jeder Handlerfunktion"? Ich hoffe doch mal es gibt nur eine Handlerfunktion für alle Kategorien und nicht für jede eine einzelne. Worin würden die sich denn Unterscheiden? Schlechtes Beispiel IMHO.
Verfasst: Freitag 9. April 2010, 10:30
von snafu
Ich denke, das war so ein Fall, wo man eine fixe Idee hat und krampfhaft (auch für sich) versucht, zu begründen, warum die Idee sinnvoll ist. Ich glaube aber, ihr habt Recht. ^^
Bottle auf Ohloh
Verfasst: Montag 12. April 2010, 13:24
von webwurst
Bottle ist noch nicht auf
https://www.ohloh.net/ eingetragen. Fänd ich aber gut!

Verfasst: Montag 12. April 2010, 14:48
von lunar
Dann trage es ein.
Verfasst: Montag 12. April 2010, 15:14
von Defnull
Ich habe den Sinn von ohloh noch nicht ganz begriffen, aber ich hab mich (und bottle) mal angemeldet. Solange ohloh keine Arbeit macht oder Leute erwarten, das ich da besonders aktiv bin, kann das auch so bleiben
(bottle ist $ 31,904 wert? aha O.o)
Verfasst: Montag 12. April 2010, 15:33
von lunar
Defnull hat geschrieben:(bottle ist $ 31,904 wert? aha O.o)
Da hast Du denn Sinn von Ohloh: Du erfährst allerlei Nutzloses über Deinen Quelltext, was Du im Regelfall eh vorher bereits wusstest („mostly written in Python“) oder mit "sloccount" (was Dir btw $ 71,957 für bottle bezahlen würde) selbst hättest herausfinden können

Verfasst: Dienstag 4. Mai 2010, 10:21
von uKev
Es gibt ja jetzt die (bisher undokumentierte) Möglichkeit auf basic auth zuzugreifen.
Benutzen würde ich das so:
Code: Alles auswählen
try:
user, passw = request.auth
return "user: %s, pass: %s" % (user, passw)
except TypeError:
return "not authorized"
Entspricht das grob der Intention?
Wie kann ich jetzt einen Login-Prompt triggern?
Verfasst: Dienstag 4. Mai 2010, 11:05
von nemomuk
Verfasst: Dienstag 4. Mai 2010, 12:05
von uKev
Ah, schön - danke, dann funktioniert mein Beispiel jetzt
Hier mein vollständiges Listing:
Code: Alles auswählen
import bottle
from bottle import TornadoServer, route, request, HTTPError
@route('/')
def index():
return 'no auth required'
@route("/auth")
def auth():
try:
(user, password) = request.auth
return "user: %s, pass: %s" % (user, password)
except TypeError:
return HTTPError(401, 'Access denied!', header={'WWW-Authenticate': 'Basic realm="%s"' % "Login erfordert"})
bottle.debug(True)
bottle.run(server=TornadoServer, reloader=True)
Wäre aber schön, wenn das ganze in irgend einer optimalen Form in Bottle integriert wird.
Nächster Schritt:
Wie loggt man sich wieder aus

?