PyBlogger, guter Code, schlechte Code... das ist hier die...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

PyBlogger, guter Code, schlechte Code... das ist hier die...

Beitragvon Crazed » Samstag 29. November 2008, 13:16

Ganz abgesehen von der [un]witzigen Anspielung im Thread Titel geht es hier noch um was anderes. Ein Freund und Ich habe durch dieses Forum Pflock kennen gelernt.

Pflock ist ein Werkzeug um einen statischen Blog, bzw. viel eher auch, statische Webseiten mittels Python zu generieren. Wir fanden diesen Aspekt sehr interessant, leider gefiel uns die gewählte MarkUp Sprache nicht sonderlich (ReST) und Code-Intern hätten wir einige Dinge anders realisiert.

Nach ein bisschen Arbeit, mehreren Male herumprobieren, Code - Umstrukturierung usw. sind wir dann zu folgenden Ergebnis gekommen:

http://paste.pocoo.org/show/v9x59aXnL0rpuUVceeJP/

Wir haben es probiert so minimalistisch und logisch wie möglich zu halten. Der minimalistische Aspekt ist vielleicht ganz gut gelungen, aber bei dem logischen haben ich noch so meine Zweifel. Die größten Sorgen bereiten mir die Effizienz und die Schönheit bzw. Strukturierung des Codes.

Aber erstmal:
Was passiert überhaupt?
Man hat idealerweise 2 Templates. Ein blog.template und ein post.template. Jeder dieser Templates ist genau genommen eine HTML Seite mit spezillen keywords wie z.b

$author, $title, $content etc.

Beide Templates besitzen nun z.b $content. Im Falle des post.template, wir content mit dem Inhalt des Blogeintrages ersetzt und beim dem blog.template wird z.b $content mit dem Inhalt aller bereits bearbeiteten post.templates ersetzt. (Das wäre dann die index.html)

D.h erst werden die post.template "gerendered" und danach das blog.template das die "gerenderten" post.templates brauch.

Die daten für die Posts werden aus config['input'] geholt, und sind genau genommen Python dateien. Wer sich das ganze genau anschauen will hier gibt es eine zip datei:

http://www.speedyshare.com/824777223.html

Ich hoffe jemand kann mir ein paar Tipps bezüglich des allgemeinen Stils, der Strukturierung, Effizienz und der logischen Aspekte bezüglich des Codes geben.

Ich bin gerne offen für Sachen die man besser machen kann.

MfG,
CracKPod
fred.reichbier
User
Beiträge: 155
Registriert: Freitag 29. Dezember 2006, 18:27

Beitragvon fred.reichbier » Samstag 29. November 2008, 13:33

Hallo,

beim ersten Durchsehen ist mir aufgefallen, dass das hier ziemlich oft vorkommt:

Code: Alles auswählen

        for key, value in assignments.iteritems():
            self.assignments[key] = value

Wäre da nicht self.assignments.update(assignments) angenehmer?

Und zu den Templates mit $blablubb: Python hat sowas schon dabei ;)

Gruß,

Fred
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Beitragvon Crazed » Samstag 29. November 2008, 14:33

Danke! Offensichtlich zwei Sachen die ich einfach nicht kannte. Falls dir noch was auffällt sag mir bitte bescheid. :) Die anderen natürlich auch.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Samstag 29. November 2008, 15:03

Nimm eine richtige Template-Engine wie Jinja oder Mako. Zu _generate_title, würde ich mit einer regex machen. Oder zumindest string.ascii_letters verwenden ;)

- Jonas
My Website - 29a.ch
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Beitragvon Crazed » Samstag 29. November 2008, 15:15

Danke veers! Das es so ausgereifte Template Engines gab wusste ich ja noch gar nicht. Aber wo genau ist der Vorteil gegenüber meiner Template klasse?

Und wenn ich eine nehme, welche dann? Es sahen jetzt die beiden die du gennant hast auf den ersten Blick echt geil aus, aber viel Unterschied gibt es jetzt auf den ersten Blick nicht

Code: Alles auswählen

>>> from jinja2 import Template
>>> template = Template('Hello {{ name }}!')
>>> template.render(name='John Doe')
u'Hello John Doe!'


Code: Alles auswählen

from mako.template import Template
print Template("hello ${data}!").render(data="world")


Und außerdem gibt es noch:

    Myghty
    Cheetah
    Genshi
    Django
    Kid


Laut der mako homepage.

Jetzt hast du mich in eine Ecke getrieben aus die ich ganz schlecht wieder rauskomme. Ich hatte schon immer ein Problem mit Entscheidungen...
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Samstag 29. November 2008, 15:40

Ich persönlich mag Jinja2 und Mako. Diese unterstützen unter anderem Vererbung von Templates, Schleifen, Template Tags, includes, filter ... ;)
Dann gibt es noch die XML basierten Template Systeme wie Genshi, welche mich persönlich aber weniger ansprechen.

Mit Jinja machst du wohl nichts falsch. Wenn dich etwas daran nervt kannst du dir ja immer noch die Alternativen ansehen. ;)

- Jonas
My Website - 29a.ch

"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Beitragvon Crazed » Samstag 29. November 2008, 15:48

An Jinja stört mich ein bisschen das man dort was kompilieren muss damit es schnell wird, ist das bei Mako auch so?
lunar

Beitragvon lunar » Samstag 29. November 2008, 15:52

Vollwertige Template-Engines beherrschen Schleifen und allerhand verschiedener Filter. Dadurch kann man die Aufbereitung für die Präsentation komplett in die Vorlage auslagern, und muss z.B. Zahlenformatierungen oder Wiederholungen nicht im Quellcode ausführen.

Kid und Myghty sind veraltet, Django ist nur ein schlechteres Jinja (und noch dazu an Django gekoppelt). Genshi ist XML basiert, was das Editieren der Templates zu einer sehr undankbaren Aufgabe macht. Jinja2 und Mako sind beide mächtig, schnell und komfortabel, der größte Unterschied liegt in der Syntax. Da mir die Mako-Syntax nicht so gefällt, habe ich mich für Jinja2 entschieden. Ein Vorteil an Jinja2 ist übrigens, dass man die Syntax konfigurieren kann, um sie dem eigenen Markup anzupassen.

Btw, was habt ihr eigentlich gegen ReST? Das ist doch so ziemlich das beste Text-Markup, was es gibt ...
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Beitragvon Crazed » Samstag 29. November 2008, 16:11

Oke, Ich werde Jinja2 nehmen und mir Rest nochmal genauer anschauen. Vielen Dank für die Hilfe bis jetzt. Aber eine Frage am Rande:

Was könnt ihr über die Qualität meines Codes sagen? Würde mich wirklich interessieren.

EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?
EDIT2: Und wenn ich jetzt sowas mit Jinja2 oder Mako und ReST mache, wie gestalte
ich das am besten Objekt Orientiert? Hat jemand eine Idee, mein letzter Versuch war irgendwie nicht _der_ Erfolg.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Samstag 29. November 2008, 19:51

Das musst du nicht selbst kompilieren. Das machen Jinja/Mako transparent für dich. Du siehst eigentlich nur das es danach schneller ist ;)

Und zu ReST, entweder schon kompiliert übergeben oder einen rest Filter schreiben. Gibt es eventuell schon ;)
My Website - 29a.ch

"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
lunar

Beitragvon lunar » Sonntag 30. November 2008, 00:07

Crazed hat geschrieben:EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?

Afaik nicht.

EDIT2: Und wenn ich jetzt sowas mit Jinja2 oder Mako und ReST mache, wie gestalte ich das am besten Objekt Orientiert? Hat jemand eine Idee, mein letzter Versuch war irgendwie nicht _der_ Erfolg.

Sphinx – das Programm, mit dem die neue Python-Dokumentation erstellt wurde – parst das Markup in einem Baum (das erledigt docutils), führt verschiedene Modifkationen an diesem Baum aus, erzeugt dann daraus HTML, und übergibt das dann an das Template, welches das HTML mit Navigationsstruktur versieht.

Die Wahl der Template-Engine würde ich nicht am Kompilieren festmachen. Bei einer statischen Erzeugung der HTML-Dateien ist die Geschwindigkeit des Rendering-Prozesses sowieso eher irrelevant. Bei Sphinx beispielsweise ist der Unterschied zwischen Jinja und Jinja2 beim Buildprozess auch nicht wirklich spürbar, obwohl Jinja2 eigentlich schneller ist.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Sonntag 30. November 2008, 01:13

lunar hat geschrieben:
Crazed hat geschrieben:EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?

Afaik nicht.
Tut es, jedoch auch transparent.
My Website - 29a.ch

"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Beitragvon Crazed » Sonntag 30. November 2008, 01:49

Ja, weil mir halt einfach Sorgen macht, falls ich irgendwann unser Projekt veröffentlichen sollte, das sich nicht jeder erst Jinja2 installieren und ggf. kompilieren muss. Viele Laien werden dann auch nicht wissen (wie ich es mal nicht wusste) das man erst die Python Quellcode Dateien haben muss so wie einen funktionieren Compiler.

Habe aber glaube die Lösung eh gefunden, dank bbfreeze. Ich freeze nicht die ganze Applikation sondern nur Jinja2 mehr oder weniger und kann daraus dann einfach ein sehr kleines, portables site-package erstellen. Sieht dann so aus:

http://www.speedyshare.com/438370518.html

Wäre nett wenn jemand mal probieren könnte Jinja damit zu benutzen. Einfach ein Python script erstellen das jinja2 importiert und den Ordner innerhalb der zip Datei in das gleiche Verzeichnis wie das erstellte Script packen oder auch ggf. irgwo in sys.path.

CracKPod
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 30. November 2008, 02:16

Crazed hat geschrieben:Ja, weil mir halt einfach Sorgen macht, falls ich irgendwann unser Projekt veröffentlichen sollte, das sich nicht jeder erst Jinja2 installieren und ggf. kompilieren muss. Viele Laien werden dann auch nicht wissen (wie ich es mal nicht wusste) das man erst die Python Quellcode Dateien haben muss so wie einen funktionieren Compiler.

Die installieren einfach Jinja mit ihrem Paketmanager. Oder Mako.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Sonntag 30. November 2008, 10:13

Statt der eigenen Klasse Template kannst du string.Template benutzen. Mako und co. brauchst du nur, wenn du auch deren Features haben willst, da die Abhängigkeit von anderen Modulen (gerade wenn man im Fall von Jinja noch einen C-Compiler installiert haben muss, wie ich das aus der Diskussion verstanden hatte) ein Preis ist, der auch Wert sein muss, bezahlt zu werden. Mir wäre er zu hoch.

Wenn du's selbst machen willst, schlage ich folgende Implementierung vor:

Code: Alles auswählen

class Template(object):
    def __init__(self, template):
        self.template = template

    def substitude(self, mapping):
        return re.sub(
            r'\$(?:\{([^}]+)\}|(\w+)|(\$))',
            lambda m: '$' if m.group(3) else mapping[m.group(m.lastindex)],
            self.template)


`_generate_title` ist viel zu komplex. Würdest du zuerst `lower()` aufrufen, könntest du dir schon mal alle Großbuchstaben in `legal` sparen. Auch könntest du einen String benutzen. Die Zuweisung in der Schleife ist alles nur noch elegant. Ich würde `filter` (siehe unten) empfehlen.

Erbe nicht von Template. Das ist kein guter Stil. Und führe nicht alles im Konstruktor aus - das ist ebenfalls schlechter Stil. Übergib ein Template als Argument, nicht nur den String.

Benutze nicht `file`, sondern einfach `open`. Wozu brauchst du eigentlich `imp.load_source`? Das erscheint mir ein komischer Weg zu sein, die Blogartikel einzulesen. Das `post_template` musst du in jedem Fall nicht jedes Mal in der Schleife erneut laden.

Code: Alles auswählen

class Post(object):
    def __init__(self, template, post):
        self.template, self.post = template, post
   
    def render(self):
        self.template.substitude({
            'title': self.post.title,
            'author': self.post.author,
            ...
        })

def generate_title(t):
    valid = lambda c: c.isalpha() or c in '-_'
    return filter(valid, t.lower().replace(' ', '_'))

class Blog(object):
    def __init__(self, template, posts):
        self.template, self.posts = template, posts
   
    def render(self):
        self.template.substitude({'content': '\n'.join(posts)})

def render(config):
    ...
    blog = Blog(
        Template(open(config['blog_template']).read()),
        [post.render() for post in posts])
    open(..., "w").write(blog.render())

Stefan

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder