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
PyBlogger, guter Code, schlechte Code... das ist hier die...
-
- User
- Beiträge: 155
- Registriert: Freitag 29. Dezember 2006, 18:27
Hallo,
beim ersten Durchsehen ist mir aufgefallen, dass das hier ziemlich oft vorkommt:
Wäre da nicht self.assignments.update(assignments) angenehmer?
Und zu den Templates mit $blablubb: Python hat sowas schon dabei
Gruß,
Fred
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
Und zu den Templates mit $blablubb: Python hat sowas schon dabei
Gruß,
Fred
- veers
- User
- Beiträge: 1219
- Registriert: Mittwoch 28. Februar 2007, 20:01
- Wohnort: Zürich (CH)
- Kontaktdaten:
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
- Jonas
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
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
Und außerdem gibt es noch:
Jetzt hast du mich in eine Ecke getrieben aus die ich ganz schlecht wieder rauskomme. Ich hatte schon immer ein Problem mit Entscheidungen...
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")
- Myghty
Cheetah
Genshi
Django
Kid
Jetzt hast du mich in eine Ecke getrieben aus die ich ganz schlecht wieder rauskomme. Ich hatte schon immer ein Problem mit Entscheidungen...
- veers
- User
- Beiträge: 1219
- Registriert: Mittwoch 28. Februar 2007, 20:01
- Wohnort: Zürich (CH)
- Kontaktdaten:
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
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
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
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 ...
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 ...
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.
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.
- veers
- User
- Beiträge: 1219
- Registriert: Mittwoch 28. Februar 2007, 20:01
- Wohnort: Zürich (CH)
- Kontaktdaten:
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
Und zu ReST, entweder schon kompiliert übergeben oder einen rest Filter schreiben. Gibt es eventuell schon
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Afaik nicht.Crazed hat geschrieben:EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?
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.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.
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.
- veers
- User
- Beiträge: 1219
- Registriert: Mittwoch 28. Februar 2007, 20:01
- Wohnort: Zürich (CH)
- Kontaktdaten:
Tut es, jedoch auch transparent.lunar hat geschrieben:Afaik nicht.Crazed hat geschrieben:EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
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
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
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Die installieren einfach Jinja mit ihrem Paketmanager. Oder Mako.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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
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:
`_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.
Stefan
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)
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())
@Leonidas, genau das will aber ich aber nicht. Ich möchte das es einfach "out-of-the-box" funktioniert ohne irgendwas zusätzliches installieren zu müsen.
@sma, Ich kenne mich leider kaum mit RegEx aus, wäre eventuell mal ganz gut wenn ich
mich ein bisschen mit der Materie auseinandersetze.
"Erbe nicht von Template. Das ist kein guter Stil." -> Wozu kann man dann erben? bzw. in welcher Situation ist es angebracht? Ich hielt das für sehr elegant.
"Benutze nicht `file`, sondern einfach `open`." -> Wo ist der Vorteil? Meines erachtens machen die beiden Funktionen fast das gleiche.
"Wozu brauchst du eigentlich `imp.load_source`?" -> Ich habe eine komische Art entwickelt blog-posts zu schreiben. Diese sind genau genommen einfach Python dateien in denen ein paar Variablen definiert werden, wie z.b content, author, date und title
"Übergib ein Template als Argument, nicht nur den String." -> Tue ich das nicht bereits?
Ich glaube fast ich packe einfach den nur knapp den Ordner mit der Jinja distribution einfach mit darein und benutze jinja2. Warum denn auch nicht? Dort gibt es viele und sehr komfortable features die ich gebrauchen kann. Außerdem hat man innerhalb des Templates viel mehr freiheit.
Trotzdem vieelen Dank. Ich finde deinen Coding Stil übrigens sehr hübsch und werde mich an einigen von deinen Ideen halten.
Wenn ich mich etwas doof anstelle, tut mir das Leid ^^.
@sma, Ich kenne mich leider kaum mit RegEx aus, wäre eventuell mal ganz gut wenn ich
mich ein bisschen mit der Materie auseinandersetze.
"Erbe nicht von Template. Das ist kein guter Stil." -> Wozu kann man dann erben? bzw. in welcher Situation ist es angebracht? Ich hielt das für sehr elegant.
"Benutze nicht `file`, sondern einfach `open`." -> Wo ist der Vorteil? Meines erachtens machen die beiden Funktionen fast das gleiche.
"Wozu brauchst du eigentlich `imp.load_source`?" -> Ich habe eine komische Art entwickelt blog-posts zu schreiben. Diese sind genau genommen einfach Python dateien in denen ein paar Variablen definiert werden, wie z.b content, author, date und title
"Übergib ein Template als Argument, nicht nur den String." -> Tue ich das nicht bereits?
Ich glaube fast ich packe einfach den nur knapp den Ordner mit der Jinja distribution einfach mit darein und benutze jinja2. Warum denn auch nicht? Dort gibt es viele und sehr komfortable features die ich gebrauchen kann. Außerdem hat man innerhalb des Templates viel mehr freiheit.
Trotzdem vieelen Dank. Ich finde deinen Coding Stil übrigens sehr hübsch und werde mich an einigen von deinen Ideen halten.
Wenn ich mich etwas doof anstelle, tut mir das Leid ^^.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Wo ist der Vorteil?Crazed hat geschrieben:@Leonidas, genau das will aber ich aber nicht. Ich möchte das es einfach "out-of-the-box" funktioniert ohne irgendwas zusätzliches installieren zu müsen.
``open()`` ist zum Öffnen von Dateien gedacht, ``file`` zum Erben um ``file``-like-Objekte zu erzeugen.Crazed hat geschrieben:"Benutze nicht `file`, sondern einfach `open`." -> Wo ist der Vorteil? Meines erachtens machen die beiden Funktionen fast das gleiche.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Kid kannst du mal getrost vergessen. Es ist einer der Vorgänger von Genshi und teilweise broken by design. Ich habe über die Unterschiede seinerzeit mal einen kleinen Beitrag auf meiner Website geschrieben, der über das Genshi-Wiki zu finden ist.
ReST benutze ich für die editierbaren Inhalte meiner persönlichen Website ebenfalls mit großer Zufriedenheit und habe damit Markdown abgelöst. Auf einer anderen benutze ich wiederum gewollt Markdown (natürlich mit diversen eigenen, anwendungsspezifischen Erweiterungen) statt ReST, da dort auch weniger technisch versierte und geübte Benutzer Inhalte schreiben und mit der Mächtigkeit von ReST doch ein wenig überfordert wären.
ReST benutze ich für die editierbaren Inhalte meiner persönlichen Website ebenfalls mit großer Zufriedenheit und habe damit Markdown abgelöst. Auf einer anderen benutze ich wiederum gewollt Markdown (natürlich mit diversen eigenen, anwendungsspezifischen Erweiterungen) statt ReST, da dort auch weniger technisch versierte und geübte Benutzer Inhalte schreiben und mit der Mächtigkeit von ReST doch ein wenig überfordert wären.
Mmmh, reden wir hier beide über das gleiche Kompilieren? Jinja2 compiliert eine _speedups.so, beim – zugegebenermaßen groben – Durchsehen des Mako-Eggs hab ich aber keine Binaries entdecken können.veers hat geschrieben:Tut es, jedoch auch transparent.lunar hat geschrieben:Afaik nicht.Crazed hat geschrieben:EDIT: Was mir wirklich noch interessiert, muss Mako auch irgendwas kompilieren?
File ist eine Klasse die ein File Objekt repräsentiert, open eine Funktion, die File benutzt. Im Grunde ist es egal, welche du nutzt, da die __init__ von file die gleichen Argumente entgegennimmt wie open, aber die Dokumentation empfiehlt die Nutzung von open(). Warum auch immer."Benutze nicht `file`, sondern einfach `open`." -> Wo ist der Vorteil? Meines erachtens machen die beiden Funktionen fast das gleiche.
Template teilt zwar mit allen Unterklassen die Eigenschaften, es ist aber rein logisch ein wenig eigenartig. Das ist in etwa so, als würdest du beim Versuch des Darstellens eines Raumes die Objekte Stuhl, Tisch und Tür von "Holz" erben lassen."Erbe nicht von Template. Das ist kein guter Stil." -> Wozu kann man dann erben? bzw. in welcher Situation ist es angebracht? Ich hielt das für sehr elegant.
Ich würde in vorliegendem Fall das mittels Komposition lösen, dh alles was mit Templates zu tun hat in einer wohlgeformten Template Klasse unterbringen, und jeder "Page" dann einde Instanz von "Template" geben. Zumindest so auf den ersten Blick.
Vererben sollte man imho wirklich nur Dinge, die zueinander gehören. Sobald du mittels Vererbung die eigentliche Logik der Superklasse in zig andere Klassen schleppst, die so direkt mit einem Template nichts zu tun haben, brichst du die Kapselung.