Seite 1 von 3
QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 15:47
von Sophus
Hallo Leute,
ich weiß, dass dieses leidige Thema schon mehrfach behandelt wurde, jedoch steige ich einfach nicht dahinter, wie man mit dem unicode - decode und encode - hantieren soll. Ich habe schon einiges gelesen, aber dennoch komme ich einfach nicht dahinter. In meinem Fall wird eine
File Dialog geöffnet. Es gibt ja auch Pfade mit Umlaute oder Zeichen, die außerhalb von ASCII-Zeichen sind. Ich ging davon aus, dass das Rahmenwerk QT (QFileDialog) sich um solche Belange kümmert.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from os.path import expanduser
import sys
def get_new_path():
QMessageBox.about(None, 'No folder', "Nur ein Text")
folder = QFileDialog.getExistingDirectory(None, "Open folder",
expanduser("~"),
QFileDialog.ShowDirsOnly)
return folder
def show_path():
folder_path = get_new_path()
print folder_path
if __name__ == "__main__":
app = QApplication(sys.argv)
show_path()
sys.exit(app.exec_())
Führe ich dieses ausführbare Programm aus, dann erhalte ich folgende Fehlermeldung:
AttributeError: 'QString' object has no attribute 'decode'
Ich bewege also mit meinem Pfad außerhalb des ASCII-Zeichen. Nun eine Frage an dieser Stelle. Was genau muss ich machen? Ich habe schon versucht die Variable
folder_path mit der
encode()-Methode und mit der
decode()-Methode zu behandeln. QStrings haben solche Methoden nicht. Oder brauche ich diese Kodierung gar nicht, wenn ich die Variable
folder_path zum Inhalt von lineEdit mache? Also, den Pfad über lineEdit ausgeben.
Ich freue mich über konkrete Vorschläge. Vielleicht kann es mir mal jemand an Hand meines Beispiels vernünftig erklären, denn ich möchte es auch verstehen. Danke euch.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 16:47
von Sophus
Ich bins nochmal:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from os.path import expanduser
import sys
def get_new_path():
QMessageBox.about(None, 'No folder', "Nur ein Text")
folder = QFileDialog.getExistingDirectory(None, "Open folder",
expanduser("~"),
QFileDialog.ShowDirsOnly)
return folder
def show_path():
folder_path = get_new_path()
print unicode(folder_path, 'latin-1')
if __name__ == "__main__":
app = QApplication(sys.argv)
show_path()
sys.exit(app.exec_())
Nach vielem Probieren hat es auf einmal scheinbar geklappt. Ich habe die Variable folder_path
unicode(folder_path, 'latin-1') wie folgt enkodiert. Nun wollte ich wissen, ob das nur ein "Zufall" ist, dass es bei mir klappt und es eine andere, bzw. bessere Lösung gibt?
Gruß
Sophus
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 17:02
von Sirius3
@Sophus: Du verwendest nirgends `decode` also kann der Fehler so nicht auftreten. QString sind QT-Unicode-Strings. Das Encoding bei "unicode" ist also absoluter Blödsinn. Der wird bei Python Unicode-Strings sogar mit einer Fehlermeldung belohnt.
Das mit Unicode ist doch eigentlich ganz einfach. Intern wird nur mit Unicode gearbeitet, wenn Du aber irgendetwas aus einem Byte-orientierten Gerät liest oder schreibst, mußt Du de- bzw. encodieren.
Python2 encodigert dabei Unicode-Strings an manchen Stellen automatisch, wenn er z.B. das Encoding des Terminals kennt. Da QStrings aber kein encode kennen, gibts in diesen Fällen Probleme.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 17:20
von Sophus
@Sirius3: Von einem
absoluten Blödsinn zu reden ist ein wenig zu weit gegriffen. Erst dadurch, dass ich Unicode auf die Variable
folder_path mit
latin-1 angewendet habe, taucht keinerlei Fehlermeldung auf, und der Pfad, auch die mit den Umlauten werden über die print-Anweisung ordentlich ausgegeben. Also augenscheinlich hat dieser
absolute Blödsinn also etwas bewirkt. Und ich kann auf die Variable
folder_path keine
decode()-Methode verwenden, da diese Variable vom Typ ein QString ist. Wo also sollte ich in meinem Code die
decode()-Methode verwenden?
Ohne diesen unicode() bekomme ich die Fehlermeldung:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xdc' in position 9: ordinal not in range(128)
Mit diesem unicode und dazu 'latin-1' bekomme ich über die print-Anweisung:
C:\Users\Übergang\Contacts
Also hat der
absolute Blödsinn also was gebracht? Oder aber ich bilde mir das ein, dass die print-Anweisung mir das ausgibt, und in Wirklichkeit wäre das eine Fehlermeldung. Aber dann wären wir bei der Philosophie von Plato angekommen. Soweit müssen wir nicht gehen.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 17:34
von Sirius3
@Sophus: richtig, Du hast nirgends `decode` verwendet, also woher kommt dann die Fehlermeldung in Deinem ersten Beitrag?
QtStrings sind Unicode-Strings, deshalb können sie mit "unicode" in Python-Unicode-Strings konvertiert werden. Da aber beides Unicode ist, braucht man kein Encoding anzugeben. Daher ist die Angabe eines Encodings Blödsinn, und wie ich gerade getestet habe, sogar gefährlich, weil intern Qt alles erst nach Latin1 konvertiert, alles was nicht mit Latin1 darstellbar ist durch "?" ersetzt, um es dann in Python wieder nach Unicode zu decodieren.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 17:41
von Sophus
@Sirius3: Ich verwende genau den gleichen Quelltext wie hier. Kein zusätzlicher Quelltext. Ich verstehe ja selbst nicht, wieso ich eine Fehlermeldung ohne diesen unicode() bekomme. Hast du vielleicht eine Ahnung? Ich benutze Python 2.7.6, Windows 7. Ich habe deshalb keinen decode() angewendet, weil ich davon ausging, dass das QT-Rahmenwerk das für mich erledigt. Und QFileDialog gehört ja dazu, richtig?
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 18:04
von Sirius3
@Sophus: da Du nicht weiter auf das überflüssige Encoding bei "unicode(...)" eingehst, gehe ich mal davon aus, dass Du meine Antwort jetzt verstanden hast.
Alle Argumente, die print bekommt und kein String oder Unicode-String sind, werden mit str(...) in einen String umgewandelt. Das geht bei QStrings mit Umlauten schief mit der Fehlermeldung
Code: Alles auswählen
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
QStrings kann man aber mit unicode in Python-Unicode-Strings umwandeln, die dann von print auf magische Weise ins Encoding des Terminals encodiert werden.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 18:10
von Sophus
@Sirius3:
Das Umwandeln von QStrings mit unicode in Python-Unicode-Strings sieht dann wie folgt aus?
Etwa so?
Ich glaube kaum, dass du das so meinst. Sicherlich liege ich gänzlich falsch.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 18:39
von Sirius3
@Sophus: genau so meine ich das.
Re: QString im Unicode?
Verfasst: Mittwoch 24. Juni 2015, 19:01
von Sophus
@Sirius3: Vielen Dank. Es klappt.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 02:29
von Sophus
Irgendwie verfolgt mich das Unicode-Problem. Ich habe hier eine Funktion, der bestimmte Argumente von einer anderen Funktion übergeben werden. Aus der
log_in()-Funktion werden Daten aus einem QlineEdit entnommen, und diese dann als Parameter an die
connect_to_mysql()-Funktion übergeben. Sobald aber zum Beispiel im Passwort ein Umlaut vorhanden ist, bekomme ich eine Fehlermeldung, selbst das Argument in Python-Unicode umgewandelt wird.
Code: Alles auswählen
def log_in(self):
dbms='pymysql'
server_host = str(self.ui_login.lineEdit_sevrer_host.text())
username = str(self.ui_login.lineEdit_username.text())
password = unicode(self.ui_login.lineEdit_password.text())
database_name = str(self.ui_login.lineEdit_database_name.text())
port = str(self.ui_login.lineEdit_port.text())
mysql_connection_result = manage_mysql.connect_to_mysql(dbm_system,
dbms_driver,
username,
password,
server_host,
port,
database_name)
def connect_to_mysql(dbm_system, dbm_driver, db_user, db_passwd, db_host, db_port, db_name):
engine = create_engine('{db_sys}+{db_driver}://{user}:{password}@{host}:{port}/{db}'.format(
db_sys=unicode(dbm_system),
db_driver=unicode(dbm_driver),
user=unicode(db_user),
password=unicode(db_passwd),
host=unicode(db_host),
port=unicode(db_port),
db=unicode(db_name),
connect_args = {'time_zone': '+00:00'},
encoding='utf8',
echo=True))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 05:39
von Sirius3
@Sophus: Du versuchst da Unicode-Zeichen in einen Byte-String hineinzuformatieren. Das will Python nicht. Du mußt den Format-String auch als Unicode-String angeben. Außerdem handelt es sich um eine URL, das heißt, Du mußt Sonderzeichen (die ja v.a. in Passwörtern vorkommen können) kodieren.
Was soll eigentlich die ständige Konvertiererei von QString nach str nach unicode? Alles überflüssig.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 09:11
von snafu
@Sophus: Ich unterstreiche jetzt nochmal, was Sirius3 mehrfach erläutert hat: Wandle Qt-Strings unter Python 2 stets mittels ``unicode(dein_qt_string)`` direkt in einen Unicode-String um. Die Verwendung von `str()` beim Konvertieren von Qt-Strings in Python-Strings ist nur unter Python 3 sinnvoll. Du befolgst das nach wie vor nicht konsequent und wirst dir damit nach wie vor Fehler einhandeln. Sicherlich auch, weil du (mutmaßlich) das Konzept von Unicode noch nicht verstanden hast.
Übrigens empfehle ich dir, die Zeile ``from __future__ import unicode_literals`` an den Anfang deines Programms zu setzen. Damit ist garantiert, dass alle Vorkommen von ``'dein_text'`` zu Unicode umgewandelt werden. Hierdurch wird in deinem Fall auch der Aufruf von `create_engine()` funktionieren. Oder zumindest wird dann kein `UnicodeEncodeError` mehr für diese Zeile geworfen. Was du möglicherweise sonst noch an Fehlern in deinem Quelltext hast, weiß ich natürlich nicht.
Übrigens würde es enorm helfen, wenn du bei Fehlermeldungen den kompletten Traceback reinkopiert, oder mindestens den Teil, woraus hervorgeht, in welcher Zeile der Fehler aufgetreten ist. Dann muss man die Zeile nämlich nicht raten.
Hier übrigens nochmal ganz deutlich:
Code: Alles auswählen
inhalt = str(dein_widget.text())
print unicode(inhalt)
# ... wird zu:
print unicode(dein_widget.text())
Der `str()`-Schritt fällt also weg.
Wahlweise könnte man auch eine kleine Hilfsfunktion definieren:
Code: Alles auswählen
def print_content(text_widget):
print unicode(text_widget.text())
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 10:30
von BlackJack
@snafu: `unicode_literals` würde ich nicht importieren, da gibt es wohl einige Stellen die dann kaputt gehen können oder nur scheinbar funktionieren bis dann mal irgendwo etwas ausserhalb von ASCII in die Daten kommt. Unicode ist ja ”ansteckend”, das heisst bei Operationen die eigentlich mit Bytestrings arbeiten sorgt ein Unicode-Operand dafür dass das Ergebnis zu Unicode wird. Und damit rechnen dann vielleicht nicht alle Aufrufer.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 12:01
von snafu
@BlackJack: Du beziehst dich vermutlich auf betriebssystemnahe Anwendungen und auf Interaktionen in Netzwerken bzw ganz generell die Kommunikation mit externen Systemen? Ich würde erwarten, dass der Anwender dafür selbst unter Python 2 explizit angibt, dass er mit Bytestrings (``b'spam'``) arbeiten möchte.
Grundsätzlich kann für Programmierer, die nicht so recht wissen, was sie tun, die Verwendung von `unicode_literals` aber eine Fehlerquelle sein - das stimmt schon. Andererseits ist Code, der sich *nicht* auf Python-2-Verhalten verlässt, schon mal in Bezug auf Strings in aller Regel leichter auf Python 3 portierbar.
Ich persönlich verwende den Import unter Python 2 immer dann, wenn ich in einer Situation bin, wo ich explizit angeben muss, dass ich einen Unicode-String mittels String-Literalen erzeugen möchte. Dann nutze ich statt ``u'spam'`` eben gleich den Import. Ich gebe zu, dass ich da eigentlich nicht ganz konsequent bin. Aber der Import für jedes einzelne Modul nervt halt irgendwie und die Verwendung von Unicode-Strings wird in Python 2 ja oftmals auch nicht zwingend benötigt.
EDIT: Zu der obigen Aufzählungen gehört als wichtiger Punkt noch die Verwendung von Bibliotheken, die schlichtweg nicht auf Unicode eingestellt sind. Da muss man natürlich auch aufpassen, dass man denen nicht versehentlich Unicode übergibt.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 12:34
von BlackJack
@snafu: Fehlerquelle über die man sehr leicht stolpern kann sind Dateinamen. Ist das betriebssystemnah? Ich denke auch es ist einfach sauberer wenn man beim/vorm Portieren nach Python 3 jede Zeichenkette explizit als b'' oder u'' markiert, damit kann man dann sicher sein dass man sich alles mal angeschaut hat und nicht einfach nur hofft das die Umstellung schon funktionieren wird.
Zu den Bibliotheken die nicht auf Unicode eingestellt sind gehören auch Teile der Standardbibliothek. `pack()` und `unpack()` aus dem `struct`-Modul mögen als erstes Argument keine Unicodezeichenkette. Was ich auf den ersten Blick etwas überraschend fand, aber dann dachte ich es gibt sicher noch mehr Module die in C geschrieben sind und kein Unicode erwarten bei Argumenten die für den Programmierer auf den ersten Blick aber nach Zeichenkette und nicht nach Bytes aussehen.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 14:23
von Sophus
Hallo Leute, ich habe jetzt konseqenterweise alle QStrings in Unicode() umgewandelt, jedoch ergibt sich weiterhin das Problem:
Code: Alles auswählen
# function from frm_log_in.py
def log_in(self):
dbms='pymysql'
server_host = unicode(self.ui_login.lineEdit_sevrer_host.text())
username = unicode(self.ui_login.lineEdit_username.text())
password = unicode(self.ui_login.lineEdit_password.text())
database_name = unicode(self.ui_login.lineEdit_database_name.text())
port = unicode(self.ui_login.lineEdit_port.text())
dbms_driver = 'pymysql'
dbm_system = 'mysql'
mysql_connection_result = manage_mysql.connect_to_mysql(dbm_system,
dbms_driver,
username,
password,
server_host,
port,
database_name)
# function from a core-module
def connect_to_mysql(dbm_system, dbm_driver, db_user, db_passwd, db_host, db_port, db_name):
try:
engine = create_engine('{db_sys}+{db_driver}://{user}:{password}@{host}:{port}/{db}'.format(
db_sys=dbm_system,
db_driver=dbm_driver,
user=db_user,
password=db_passwd,
host=db_host,
port=db_port,
db=db_name,
connect_args = {'time_zone': '+00:00'},
encoding='utf8',
echo=True))
self.log_in()
File "D:\Dan\Python\xarphus\xarphus\frm_db_login.py", line 203, in log_in
database_name)
File "D:\Dan\Python\xarphus\xarphus\core\manage_mysql.py", line 152, in connect_to_mysql
echo=True))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
Er zeigt mir zu letzt auf
echo=True.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 14:44
von Sirius3
@Sophus: Du hast ja auch nichts von dem, was ich geschrieben habe, umgesetzt.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 14:55
von Sophus
@Sirius3: Du wolltest, dass die Strings im Format, also in der connect_to_mysql()-Funktion in unicode() umgewandelt werden. Nicht dass ich deine Anmerkung überlese. Ich dachte nur, wenn ich die Strings schon weit vorher in unicode() umgewandelt habe, dann brauche ich die hinterher nicht nochmal in unicode() umzuwandeln. Vielleicht sollte ich nicht erst versuchen selbstständig zu denken.
Re: QString im Unicode?
Verfasst: Montag 20. Juli 2015, 15:25
von snafu
Die Aussage war:
Sirius3 hat geschrieben:@Sophus: Du versuchst da Unicode-Zeichen in einen Byte-String hineinzuformatieren. Das will Python nicht. Du mußt den Format-String auch als Unicode-String angeben.
Und der Format-String ist nach wie vor ein Bytestring. Setze entweder ein "u" vor den String oder verwende den von mir empfohlenen Import. Wie schon angesprochen wurde, kann es sein, dass du bei Nutzung der Import-Variante noch andere Veränderungen im Quelltext vornehmen musst.
Dies ist der Format-String, falls das noch nicht klargeworden ist:
Code: Alles auswählen
'{db_sys}+{db_driver}://{user}:{password}@{host}:{port}/{db}'