Tech-Blog
Technische Artikel zu Themen: Zope, Plone, Python, Pyramid, Django, Exim, Dovecot, Nagios, Shinken, Bacula und weiteren Open Source Themen...
Diazo: CSS Klasse per XSLT in body-Tag einfügen
Plone hat ein 3 Spaltenlayout, sofern rechts und links Portlets vorhanden sind. In einigen Bereichen möchte man aber z.B hin und wieder die rechte Spalte ausblenden um mehr Platz zu haben. Hat man jetzt ein fixes Grid-Layout so bleibt die rechte Spalte leer, die mittle Spalte dehnt sich aber nicht aus. Die Lösung kann eine CSS-Klasse im body-Tag sein, welche dann in den Stylesheets als Marker verwendet werden kann.
CSS-Klasse in body-Tag einfügen
<xsl:attribute name="class"><xsl:value-of select="/html/body/@class" /> three_col</xsl:attribute>
Bedingtes Einfügen
<before theme-children="/html/body" method="raw"> <xsl:attribute name="class"><xsl:value-of select="/html/body/@class" /><xsl:if css:test="#portal-column-one"> col-one</xsl:if><xsl:if css:test="#portal-column-content"> col-content</xsl:if><xsl:if css:test="#portal-column-two"> col-two</xsl:if></xsl:attribute> </before> <drop css:theme="#portal-column-one" css:if-not-content="#portal-column-one" /> <drop css:theme="#portal-column-content" css:if-not-content="#portal-column-content" /> <drop css:theme="#portal-column-two" css:if-not-content="#portal-column-two" />
Plone: Annotations zum speichern von Daten an Objekten
Annotations werden in Zope üblicherweise als __annotations__ (BTree) unterhalb des betreffenden Objektes abgelegt. Das Annotations Objekt verhält sich wie ein Dictionary.
Um Konflikte mit anderen Anwendungen zu vermeiden, sollten Informationen unterhalb eines keys der den Namen der Anwendung enthält abgelegt werden.
Annotatable?
Damit annotations zum speichern von Daten, an einem Objekt verwendet werden können, muss das Objekt das Interface IAttributeAnnotatable implementiert haben. Um dies zu erreichen kann man es direkt in der Klasse implementieren oder wenn man selbst keinen Einfluss auf die Klasse hat, dann kann man es ganz einfach per zcml-Anweisung in der configure.zcml wie folgt definieren.
<class class="Products.CMFCore.MemberDataTool.MemberData"> <implements interface="zope.annotation.interfaces.IAttributeAnnotatable" /> </class>
Daten in Annotations speichern
Wenn wir jetzt z.B. an ein MemberData Objekt Daten als annotations hängen möchten, dann können wir dies wie folgt machen.
from zope.annotation.interfaces import IAnnotations from ZODB.PersistentMapping import PersistentMapping admin = portal.portal_membership.getAuthenticatedMember() admin_annotations = IAnnotations(admin) infos = PersistentMapping({'groesse': '184cm'}) admin_annotations["member.datatest"] = infos
Das betreffende Objekt sollte persistent sein, was hier der Fall ist.
Weitere Informationen sind hier zu finden:
Plone: Password encrypt
Beispiel
Password verschlüsseln
from AccessControl import AuthEncoding def _encryptPassword(self, pw): return AuthEncoding.pw_encrypt(pw, 'SSHA')
Password überprüfen
from AccessControl import AuthEncoding AuthEncoding.pw_validate(saved_pw, entered_pw)
Plone: PloneFormGen readonly fields
Ein verstecktes Feld anlegen
Wir legen ein FormStringField (Zeichenkettenfeld) an, füllen den Default wert mit dem Inhalt der angezeigt werden soll und markieren das Feld als versteckt.
Damit ist das Feld im Formular enthalten und wird beim versenden mit übertragen.
Ein Feld zur Anzeige des versteckten Feldes anlegen
Wir legen ein FormRichLabelField (Bezeichnungsfeld) an und geben in den overrides den folgenden TALES-Ausdruck ein:
string: <strong>My hidden field text:</strong> ${folder/myhiddenfield/getFgDefault}
Das Feld zeigt nun immer den Inhalt des Default-wertes des Feldes myhiddenfield an, kann aber selbst nicht editiert werden.
Text per CSS rotieren mit Compass
HTML Markup
<div id="box"> <h1 id="parent-fieldname-title" class="documentFirstHeading"> Spielplatzinspektion </h1> </div>
Compass SCSS
@import "compass/css3/transform"; #box{ width: 400px; height: 400px; border: 1px solid black; margin: 0 auto; } .verticalHeadline{ font-size: 12pt; margin: 0; text-align: center; border: 1px solid green; @include rotate(270deg); @include apply-origin(top right, false); position: relative; right: 2em; }
Resultat
Plone: Diazo Theme & password_reset: Passwort setzen fehlgeschlagen
Fehlendes base-Tag
Das Problem, im Theme fehlt das base-Tag welches Plone selbst rendert.
<base href="http://inqbus-hosting.de/" />
Dieses sollte mit folgender Regel ins Theme übertragen werden.
<drop theme="/html/head/title" /> <drop theme="/html/head/base" /> <drop theme="/html/head/comment()" /> <after content="/html/head/base | /html/head/comment() | /html/head/title" theme-children="/html/head" />
Plone: persistente Utilities manuell entfernen
Wenn man eine solche fehlerhafte Erweiterung deinstalliert und diese auch aus dem Buildout entfernt, kommt es zu Fehlermeldungen der folgenden Art.
AttributeError: type object 'IWarehouseContainer' has no attribute '__iro__'
Um den Fehler zu beheben, müssen wir die Erweiterung noch einmal im Buildout installieren.
Registrierung finden
Am besten schauen wir uns als erstes den Code der Erweiterung an, der das local utility registriert. Hier zu suchen wir in dem package nach dem Interface 'IWarehouseContainer'.
~/.buildout/eggs/getpaid.warehouse-0.3-py2.7.egg/getpaid/warehouse $ grep -r "IWarehouseContainer" .
Wir finden hier die Registrierung.
sm.registerUtility(component=warehouses, provided=interfaces.IWarehouseContainer )
Dies wird uns helfen das Utility zu entfernen.
Utility entfernen
Um das local utility zu entfernen starten wir die Instanz mit debug.
./bin/instance debug
Nun holen wir uns den site manager.
sm = app.Plone.getSiteManager()
Anschließend importieren wir das Interface IWarehouseContainer und holen uns das Utility.
from getpaid.warehouse.interfaces import IWarehouseContainer warehouse = sm.queryUtility( IWarehouseContainer )
Das Utility können wir jetzt mit sm.unregisterUtility(IWarehouseContainer) aus der Registrierung entfernen. Da das Utility selbst IWarehouseContainer nicht implementiert, muss das Interface in diesem Fall mit angegeben werden.
sm.unregisterUtility(warehouse, provided=IWarehouseContainer)
Reguläre Ausdrücke in Python
Dokumentation zu regulären Ausdrücken in Python
Ich möchte hier nicht die vorhandene Dokumentation wiederholen, daher sei hiermit auf darauf verwiesen:
Beispiele
Zum testen von Regulären Ausdrücken eigent sich folgender Aufruf:
p = re.search(r'(?P<salutation>^Frau|^Herr)\s+(?P<name>.*)', "Herr Conrad Meier")
Hier wird das Modul re direkt verwendet, was zum testen ok ist, später ist es besser den regulären Ausdruck zu Kompelieren, damit die Operationen schneller ausgeführt werden können.
p = re.compile(r'(?P<salutation>^Frau|^Herr)\s+(?P<name>.*)') p.search("Herr Conrad Meier")
Adressblock parsen
Wir wollen folgenden Adressblock parsen und Anrede, Name sowie PLZ und Ort auslesen.
ADDRESSBLOCK = u""" Inqbus GmbH & Co. KG Herr Maik Derstappen Geschäftsführer Karl-Heine-Str. 99 04109 Leipzig Plagwitz Sachsen Deutschland"""
Wir definieren uns nun 2 reguläre Ausdrücke, die die Zeile mit der Anrede und dem Namen, sowie die Zeile mit der PLZ und dem Ort beschreiben. In den Ausdrücken werden benannte Guppen erzeugt, um auf diese später einfach zugreifen zu können.
z.B. erzeugt folgender Ausdruck eine Gruppe mit dem Namen salutation, die die Anrede (Frau/Herr) enthält.
(?P<salutation>^Frau|^Herr)
ReSalutationName = re.compile(r'(?P<salutation>^Frau|^Herr)\s+(?P<name>.*)') ReZipecodeCity = re.compile(r'(?P<zipcode>\d{4,5})\s+(?P<city>.*)')
Im folgenden iterieren wir über die Zeilen des Adressblockes und wenden die regulären ausdrücke auf jede Zeile an. Wenn z.B. der erste Ausdruck ReSalutationName.search(line.strip()) ein Ergebnis zurück liefert, können wir auf die definierten Gruppen (salutation, name) per match_object.group('Gruppenname') zugreifen und bekommen den Teilstring der Gruppe zurück.
for line in ADDRESSBLOCK: salutation_name = ReSalutationName.search(line.strip()) if salutation_name: salutation = salutation_name.group('salutation') name = salutation_name.group('name') continue zipcode_city = ReZipecodeCity.search(line.strip()) if zipcode_city: zipcode = zipcode_city.group('zipcode') city = zipcode_city.group('city') continue
How to install MySQLdb in virtualenv on Debian
If you try to install MySQL-Python with pip as follow:
pip install MySQL-Python
You will get this error, because of missing header files of libmysqlclient:
$ pip install MySQL-Python
Downloading/unpacking MySQL-Python
Downloading MySQL-python-1.2.3.tar.gz (70Kb): 70Kb downloaded
Running setup.py egg_info for package MySQL-Python
sh: 1: mysql_config: not found
Traceback (most recent call last):
File "<string>", line 14, in <module>
File "/home/maik/.virtualenvs/env1/build/MySQL-Python/setup.py", line 15, in <module>
metadata, options = get_config()
File "setup_posix.py", line 43, in get_config
libs = mysql_config("libs_r")
File "setup_posix.py", line 24, in mysql_config
raise EnvironmentError("%s not found" % (mysql_config.path,))
EnvironmentError: mysql_config not found
Complete output from command python setup.py egg_info:
sh: 1: mysql_config: not found
Traceback (most recent call last):
File "<string>", line 14, in <module>
File "/home/maik/.virtualenvs/env1/build/MySQL-Python/setup.py", line 15, in <module>
metadata, options = get_config()
File "setup_posix.py", line 43, in get_config
libs = mysql_config("libs_r")
File "setup_posix.py", line 24, in mysql_config
raise EnvironmentError("%s not found" % (mysql_config.path,))
EnvironmentError: mysql_config not found
This error can be solved by installing the libmysqlclient header files.
aptitude install libmysqlclient-dev