Keine Highlevel-Webrahmenwerke?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Es gibt für Python ja nicht gerade wenige Webrahmenwerke. Dennoch folgen sie eigentlich alle dem selben einfachen Prinzip. Wieso gibt es eigentlich keine stärker abstrahierenden Systeme, z.B. welche, die einem Komponentenansatz folgen?

Vorbilder könnten IMHO Seaside, Wicket und ja, auch JSF oder ASP.NET sein.

Nehmen wir einmal die "Arc-Challenge" als Beispiel. Eine Webanwendung soll nach einem Namen fragen, danach eine Seite mit einem Link anzeigen und nach Klick auf den Link den Namen wieder anzeigen. Der Zustand der Webanwendung (der Name) soll dabei unsichtbar bleiben.

Wer Wicket kennt, dem wird dieses adhoc-Beispiel vertraut vorkommen:

Code: Alles auswählen

class Start(web.Page):
    def setup(self):
        return web.Form('f', 'submit')

    def submit(name=None):
        self.session.name = name
        self.goto(Delay)
        
class Delay(web.Page):
    def setup(self):
        return web.Link('l', Display)
        
class Display(web.Page):
    def setup(self):
        return web.Label('l', self.session.name)
Die Idee ist, von Dingen wir URLs komplett zu abstrahieren. Ich habe Seiten, repräsentiert durch web.Page-Objekte, die angezeigt werden können und aus Komponenten (z.B. web.Form, web.Link oder web.Label) bestehen, die den dynamischen Teil repräsentieren. Der statische Teil wäre jeweils ein Template der folgenden Art:

Code: Alles auswählen

<html><body><a web:id="l" href="#">Weiter</a></body></html>
Das Rahmenwerk (ein Begriff, der hier sogar zutrifft, weil es nicht nur eine Sammlung von Klassen und Funktionen ist, sondern etwas, das meine Klassen einbettet und aufruft) erzeugt abhängig von einer URL das passende Seitenobjekt, stellt ggf. dessen internen Zustand wieder her und führt dann passenden Code aus. Weil ich mir leider keine Programmzustände in Form von continuations merken kann (wie bei Seaside und Lisp-Rahmenwerken) muss ich dafür sorgen, dass ich mit einem wiederhergestellten Seitenobjekt weitermachen kann.

Die Anwendung startet, indem `Start` erzeugt wird, was eine Seite darstellt, die ein Formular enthält, welches über "f" mit der Methode `submit` assoziiert wird, sodass beim Absenden der Formulardaten dann in der wiederhergestellten Seite `submit` aufgerufen wird. Der Name wird gespeichert und die Kontrolle wird an ein anderes Seitenobjekt übergeben, welches dann auch gebaut wird und welches nur einen Link anzeigt. Gleichzeitig wird eine URL generiert und derart gespeichert, dass später ein Link auf den Link dazu führt, dass `Display` dargestellt wird.

Man könnte es noch extremer machen und (wie Seaside) auf Templates verzichten:

Code: Alles auswählen

class Start(web.Component):
    def render(self, html):
        with html.form('submit'):
            html.text("Name: ")
            html.input('name')
            html.submit()
    
    def submit(self, name=None):
        self.session.name = name
        self.goto(Link)
        
class Link(web.Component):
    def render(self, html):
        html.a(Display, 'Weiter')
        
class Display(web.Component):
    def render(self, html):
        html.text("Hallo, ", self.session.name)
Zu fremdartig?

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

Wie würde mein Beispiel mit Zope und/oder Grok aussehen?

Stefan
lunar

Frag gerold oder lies das Grok-Tutorial, ich bin weder ein Zope- noch ein Grok-Entwickler. Allerdings habe ich mal einen Vortrag über Grok und Zope gehört, und das war ziemlich abstrakt. Imho zu abstrakt, aber ich bin ja nicht das Maß aller Dinge ;)
BlackJack

Ging der Trend in letzter Zeit nicht dahin, das URLs wichtig sind, sprich nicht aus automatisch generiertem, unverständlichen Zeug bestehen sollten, sondern etwas in dem der Anwender auch einen Sinn sieht? In dem Licht macht das komplette Abstrahieren von URLs die Sache komplizierter, weil man zusätzlich dann doch wieder konkrete URLs mit den "abstrakten" Objekten verbinden muss.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Zope / Webware Serverlets oder wie die hießen. Gott sei Dank sind diese Zeiten hinter uns ;-)
TUFKAB – the user formerly known as blackbird
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich für meinen Teil muss sagen, dass ich Webware ohne zu bereuen habe fallen lassen. Damals war noch 0.8.1 aktuell und später ist davon WSGIKit geforkt um schließlich Python Paste zu werden. Ich glaube, das nehme ich Paste noch heute übel.

Ansonsten, ja, Zope. Könnte man sich ansehen, ich war auch auf einem Zope/Grok-Vortrag. Ich denke Zope würde dir, sma wohl besser passen, Grok ist meiner Empfindung nach eher mit den "üblichen" Frameworks vergleichbar.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Hast du mal im Käseladen die Regale durchwühlt? Ich meine da hin und wieder von Paketen gelesen zu haben, die Ideen und Konzepte anderer Frameworks (z.B. Cocoon und/oder(?) andere kontinuitätsbasierte) in Python abzubilden versuchten.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

@Y0Gi: Ich empfinde PyPi als recht unübersichtlich und habe dort eben nur Wareweb und Webware gefunden, was ich mir mal anschauen werde. Continuation-based wäre genau, was mich interessieren würde, kann mir aber nicht vorstellen, wie das mit einem normalen Python geht. Vielleicht nur für Stackless? Cocoon als Vorbild wäre für mich nicht so wichtig, das mochte ich auch unter Java nicht ;)

@BlackJack: Es gibt solche und solche Anwendungen. Für "klassische" Informationssysteme, die eher seitenorientiert sind, ist es natürlich hilfreich, wenn ich jede Seite per Google finden kann. Reden wir aber eher von einer klassischen Anwendung, dann sollen die internen Zustände vielleicht gar nicht in der URL sichtbar sein oder aber die spielen keine Rolle. In diesem Fall sind automatische URLs IMHO von Vorteil, weil sie dem Entwickler Entscheidungen abnehmen.

Das Grok-Tutorial fand ich recht unzugänglich und gleichzeit recht lang. Mir würde mehr helfen, genau mein Beispiel zum Vergleich zu sehen. Das Wort "session" kommt in dem Tutorial gar nicht vor. Wie funktionieren die dort?

Update: Bei wareweb/webware scheint es mir so zu sein, dass sie sich auf die untersten Schichten des APIs beschränken. WSGI ist für mich gesetzt. Mir geht es darum, wie ich jetzt einfach eine Anwendung bauen kann, nicht wie ich HTTP sprechen kann. Die Doku von wareweb erscheint mir unbrauchbar und webware macht auch keinen Spaß zu lesen.

Ich glaube, ich träume dann lieber weiter von eigenen Ideen ;)

Stefan
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

sma hat geschrieben:@Y0Gi: Ich empfinde PyPi als recht unübersichtlich und habe dort eben nur Wareweb und Webware gefunden, was ich mir mal anschauen werde. Continuation-based wäre genau, was mich interessieren würde, kann mir aber nicht vorstellen, wie das mit einem normalen Python geht. Vielleicht nur für Stackless? Cocoon als Vorbild wäre für mich nicht so wichtig, das mochte ich auch unter Java nicht ;)
Greenlets reichen für sowas vollkommen aus.
TUFKAB – the user formerly known as blackbird
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

mitsuhiko hat geschrieben:Greenlets reichen für sowas vollkommen aus.
Tun sie nicht. Ich habe ein Deja vu. Continuations können mehrfach fortgesetzt werden. Greenlets nicht. Damit sind nur One-Shot-Continuations möglich, was zu wenig ist.

Stefan
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

sma hat geschrieben:
mitsuhiko hat geschrieben:Greenlets reichen für sowas vollkommen aus.
Tun sie nicht. Ich habe ein Deja vu. Continuations können mehrfach fortgesetzt werden. Greenlets nicht. Damit sind nur One-Shot-Continuations möglich, was zu wenig ist.
Warum ist das zu wenig?
TUFKAB – the user formerly known as blackbird
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Nehmen wir diese Funktion als Beispiel:

Code: Alles auswählen

def app(self):
    a = self.read("Zahl 1")
    b = self.read("Zahl 2")
    self.write("Summe: " + (a + b))
`read` soll ein Formular anzeigen und auf die Eingabe einer Zahl warten. `write` soll den übergebenen String anzeigen. Auf der Console könnte das so aussehen:

Code: Alles auswählen

def read(self, prompt): return raw_input(prompt)
def write(self, message): print message
Webanwendungen haben jedoch einen anderen Kontrollfluss. Hierzu muss das Programm immer wieder unterbrochen werden. Das, was nach einer Unterbrechung weiterlaufen soll, nennt man Continuation. Ich binde nun Continuations an URLs. Eine URL kann mehrfach aufgerufen werden und daher muss eine Continuation mehrfach durchlaufen werden können.

Die Continuation beim ersten `read` ist:

Code: Alles auswählen

def k1(self, r):
    a = r
    b = self.read("Zahl 2")
    self.write("Summe: " + (a + b))
    
def app(self):
    self.k1(self.read("Zahl 1"))
Habe ich `k1` an URL1 gebunden und wird durch das Abschicken eines Formulars URL1 aufgerufen, kann `r` bestimmt werden und dann kann `k1` aufgerufen werden. Drückt der Benutzer jetzt "back" und schickt das Formular nochmal ab, wird wieder `k1` aufgerufen.

Der Kontrollfluss ist nicht mehr linear. Und damit kommen greenlets nicht klar.

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

Habe mir jetzt kurz nochmal Grok angeschaut. Was mich abschreckt ist, dass man laufend Zope neu starten muss. Da kann ich ja auch gleich Java benutzen :) Ansonsten ist der Python-Anteil recht kurz.

Code: Alles auswählen

class App(grok.Application, grok.Container): pass
    
class Index(grok.View):
    def update(self, name=""):
        self.context.name = name
    
class Delay(grok.View): pass
class Display(grok.View): pass
Ein `grok.Container` definiert automatisch Persistenz und Session, wenn ich das richtig verstanden habe. Die `grok.View`s finden einen einzelnen Container automatisch und Formulardaten werden über eine `update`-Methode verarbeitet. Es geht automatisch mit `Index` los. Die Templates sind weniger schön, weil hier recht umständliche Python-Ausdrücke stehen:

Code: Alles auswählen

# index.pt    
<form tal:attributes="action python:view.url()" method="post">...</form>

# delay.pt
<a tal:attributes="href python:view.url('display')">Weiter</a>

# display.pt
<span tal:content="python: context.name">...</span>
Bin nicht wirklich überzeugt...

Stefan
Antworten