creole2html und Unicode

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.
Antworten
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Und wieder mal ein Problem mit Unicode. Ich möchte einen Text aus einer CouchDB Datenbank durch den Creole Parser schicken. Wenn der Text zum Beispiel ein ß enthält bekomme ich einen UnicodeDecodeError, wenn ich creole2html aufrufe.

Code: Alles auswählen

c = creole.creole2html(u"äöüß")
Ich habe schon alles mit .encode() durchprobiert, was ich gefunden habe, aber es scheitert spätestens an dem 'ß'. Wie muss ich das umwandeln, damit der Creole Parser das frisst?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Iirc frisst der ``creoleparser`` keinen Unicode. Ich hatte mir immer eine Wrapperfunktion gebaut, die meine Unicode-Strings temporär in utf-8 wandelt, diese dann an den creoleparser übergibt und danach wieder zurückwandelt.

Allerdings arbeitet doch Jens afaik an einem fork? Oder zumindest meine ich, dass er genau diesen Bottleneck beheben wollte... such doch mal danach!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich hatte deinen alten Beitrag schon gefunden. Und ich verwende genau genommen flask-creole. Das normale Creole Modul habe ich anscheinend gar nicht installiert. Kann zumindest das Modul nicht laden

Code: Alles auswählen

>>> from creole import creole2html
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named creole
PS: ach ja, das "encoding" Argument scheint flask-creole gar nicht zu kennen.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Bugs beim Autor melden oder selbst Patches einschicken?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
noisefloor
User
Beiträge: 4262
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wenn ich mich nicht völlig irre, erwartet und liefert CouchDB UTF-8.

Oder wandelt couchdb-python das noch in Unicode?

Gruß, noisefloor
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Wenn ich mir mit "print type()" den Typ des Rückgabewertes einer CouchDB Abfrage ausgeben lasse erhalte ich <type 'unicode'>

Wie es scheint verwendet Flask-Creole diesen creoleparser
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

burli hat geschrieben: Wie es scheint verwendet Flask-Creole diesen creoleparser
Sicher? Ich habe aus dieser Seite interpretiert, dass python-creole benutzt wird! Und das kennt in der Tat keinen `encoding`-Parameter... (und ist das von Jens erstellte, wie ich oben schrieb ;-) )

Edit: Hieraus ersehe ich, dass die Funktionen Bytestrings fressen aber Unicode zurückliefern? Das wäre ja strange... Ich denke ich werde das mal installieren und selber austesten!

Edit2: Ok, habs mal ausprobiert. Scheint ein Fehler auf der Seite zu sein. `creole2html` nimmt Unicode und spuckt auch Unicode wieder aus:

Code: Alles auswählen

In [4]: from creole import creole2html

In [5]: creole2html(u"''hallo''")
Out[5]: u"<p>''hallo''</p>"

In [6]: creole2html("''hallo''")
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)

/home/nelson/<ipython console> in <module>()

/usr/local/lib/python2.7/dist-packages/creole/__init__.pyc in creole2html(markup_string, debug, parser_kwargs, emitter_kwargs, block_rules, blog_line_breaks, macros, verbose, stderr)                                                                                                                                                      
     58     Info: parser_kwargs and emitter_kwargs are deprecated
     59     """
---> 60     assert isinstance(markup_string, TEXT_TYPE), "given markup_string must be unicode!"
     61 
     62     parser_kwargs2 = {

AssertionError: given markup_string must be unicode!
Also alles in Butter.

Bleibt die Frage, welches Modul jetzt Flask-Creole wirklich nutzt? Also doch mal den Source genauer angucken und / oder beim Autor anfragen. Als letztes kann man sich diese Extension für Jinja2 ja auch leicht selber bauen...

Edit3: Ok, also laut `setup.py` nutzt das Ding also doch das `creoleparser`-Modul. Da bleibt dann wohl nur eines: Bug melden!
Zuletzt geändert von Hyperion am Dienstag 13. Dezember 2011, 15:17, insgesamt 1-mal geändert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Also wenn ich Flask-Creole installiere (oder upgrade) wird der Creole Parser von hier geholt.

http://pypi.python.org/packages/source/C/Creoleparser mit einem Verweis auf diese Seite http://pypi.python.org/simple/Creoleparser/

Also offensichtlich nicht der von Jens http://code.google.com/p/python-creole/
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hyperion hat geschrieben:

Code: Alles auswählen

In [4]: from creole import creole2html

In [5]: creole2html(u"''hallo''")
Out[5]: u"<p>''hallo''</p>"

Also alles in Butter.
Probiere mal Zeichen wie ein ß
Hyperion hat geschrieben: Edit3: Ok, also laut `setup.py` nutzt das Ding also doch das `creoleparser`-Modul. Da bleibt dann wohl nur eines: Bug melden!
Was für einen Bug soll ich da melden? Und an wen? An den Programmierer von Flask-Creole, dass er den falschen Parser verwendet?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

burli hat geschrieben: Probiere mal Zeichen wie ein ß
Ja hab ich - klappt alles wunderbar!
burli hat geschrieben: Was für einen Bug soll ich da melden? Und an wen? An den Programmierer von Flask-Creole, dass er den falschen Parser verwendet?
Nee, dass er es versäumt hat, seine Jinja2-Filter-Funktion auf Unicode umzustellen. Laut Doku vom creoleparser-Modul kann ich der `__init__`-Methode der `Parser`-Klasse ein `encoding`-Argument übergeben und muss dieses auf `None` setzen, um Unicode zu übergeben und wieder zu erhalten. Wie man in Zeile 34 des `creole`-Moduls vom Flask-Creole Projekt erkennen kann, fehlt diese Angabe:

Code: Alles auswählen

self.creole = Parser(dialect=self.dialect, method=parser_method)
Patche das doch mal so um:

Code: Alles auswählen

self.creole = Parser(dialect=self.dialect, method=parser_method, encoding=None)
Das sollte das Problem lösen.

Da Jinja2 afaik intern mit Unicode arbeitet und dies in der Anbindung an Flask sicherlich auch der Fall ist, sollte doch jedes Plugin dieses per default unterstützen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Der Creole Parser selbst verwendet doch kein Jinja. Und die Fehler treten auch dann auf, wenn ich den Parser nicht im Template sondern direkt im Programm aufrufe.

Ich werde mal deinen Vorschlag testen, aber das hilft mir später nicht bei meinem Provider, da ich da die Änderungen nicht machen kann, weil die Bibliotheken systemweit installiert sind. Ich hab da leider kein virtualenv
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

So, ich habe mir mal die Mühe gemacht und einen kleinen Test durchgeführt:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

"""
    Put Template 'test.html' in 'templates' like this:
        {{ data|creole2html }}
"""

from flask import Flask, render_template
from flaskext.creole import Creole

app = Flask(__name__)
Creole(app)

DATA = u'üöä**ß**!'

@app.route('/test')
def test():
    return render_template('test.html', data=DATA)
    
@app.route('/patched')
def patched():
    res = Creole(app).creole2html(DATA)
    return u"Res: {}".format(res)
    
@app.route('/')
def hello_world():
    res = Creole(app).creole2html(DATA).decode("utf-8")
    return u"Res: {}".format(res)

if __name__ == '__main__':
    app.debug = True
    app.run()
Mit diesem kleinen Flask-Script kann man meine Annahmen leicht verifizieren. In der default-Route werden die Zeichen ohne Probleme angezeigt. `creole2html` liefert tatsächlich einen `utf-8`-codierten Bytestring zurück. Das liegt an der - imho fehlerhaften - Initialisierung des Flask-Creole-Moduls (s. mein letztes Posting). Ich kann das in meiner Applikation leicht decodieren und damit wieder mit Unicode weiterarbeiten. Für dieses Verhalten könnte ich mir also eine Wrapper-Funktion schreiben.

In der Route `test` benutze ich nun den Jinja2-Filter und falle böse mit einem `UnicodeDecodeError` auf die Nase - vermutlich versucht Jijna2 bei Byte-Strings in Unicode zu wandeln und nimmt dabei eben ASCII an. Wenn ich meinen oben vorgeschlagenen Patch anwende, so klappt es :-) Nur ist die Extension imho so nicht zu gebrauchen - der eigentliche Vorteil des Filters ist so momentan nicht nutzbar ohne Patch. Und innerhalb meiner Anwendung kann ich ja locker einen anderen Creole-Parser (z.B. den von Jens) einbinden.

Die Route `patched` bestätigt die Annahme ebenfalls - ohne Pathc fällt die auf die Nase, mit geht es.

Imho also ein Fehler der Flask-Extension!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Jap, mit dem Patch funktioniert es. Jetzt muss es nur noch der Entwickler ändern und mein Provider muss die Änderung einspielen

EDIT: oh, Bug schon eingetragen, danke.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

burli hat geschrieben:Jap, mit dem Patch funktioniert es. Jetzt muss es nur noch der Entwickler ändern und mein Provider muss die Änderung einspielen

EDIT: oh, Bug schon eingetragen, danke.
Naja, wenn Du den Jinja2-Filter nicht verwendest, kannst Du ja auch mit einer Work-around-Wrapper-Funktion glücklich werden - oder eben einen anderen Creole-Parser einsetzen.

Bei der Aktivität in dem Projekt halte ich es irgend wie für tot ehrlich gesagt...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Burli: Man kann die Funktionalität des Plugins übrigens leicht nachbilden. Diese paar Zeilen reichen, um das Modul von Jens zu nutzen:

Code: Alles auswählen

from creole import creole2html

@app.template_filter('creole2html')
def creole2html_(text):
    return creole2html(text)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Danke für die Vorschläge. Ich werde mir überlegen, wie ich vorgehe.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich habe jetzt umgestellt auf Markdown. Ich habe einen Filter gebastelt

Code: Alles auswählen

import markdown

@app.template_filter('markdown2html')
def markdown2html_(text):
    return markdown.markdown(text)
Im Template muss man allerdings noch |safe anhängen

Code: Alles auswählen

text|markdown2html|safe
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Antworten