i und j sollte auch nicht so dicht auf der Tastatur beieinander liegen
Mein erster Post war nicht seeehr ausführlich; das gebe ich zu

Mir ging es in erster Linie um diesen Monkey Patch. Ich wollte euch nicht gleich mit seitenlangen Text erschlagen... Das kommt dafür jetzt
Der Aufruf von dieser Klasse geschieht Paketintern im Modul id3.
Der prinzipielle Vorgang sieht so in meinem Skript aus (das ist nur für Anschauungszwecke zusammengebastelt):
Code: Alles auswählen
import mutagen.id3
### ID3 object
audio = mutagen.id3.ID3(r"C:\audio.mp3")
### Text für den ID3-Titel vorbereiten
# Text für den ID3-Titel als Unicode
id3_title_unicode = u'0001 \u9677\u843d \u91cc\u6839 \u7535\u89e3\u94dd'
# Encoding des Textes für den ID3-Title mit gb18030
id3_title_gb18030 = id3_title_unicode.encode('gb18030')
### Titel-Frame object
# Text übergebe ich bei der Initialisierung zuerst nicht, da er sonst gleich in Unicode umgewandelt wird
# Für TextFrames muss das Encoding angegeben werden. encoding=0 ist latin-1
# Die ID3v2.3-Spec erlaubt offiziell nur latin-1 und utf16
# Als Trick wird für chinesische Encodings trotzdem latin-1 für das encoding angegeben
# Blöderweise encodiert aber mutagen im späteren Ablauf dann auf latin-1, was in meinem Fall auch der Fehler ist
title_frame = mutagen.id3.TIT2(encoding=0, text="")
# Dem Text-Attribut den Titel als Liste (wird so gefordert) übergeben. Encoding bleibt bestehen und wird nicht in Unicode gecastet.
title_frame.text = [id3_title_gb18030]
### TitleFrame an das ID3-object übergeben
audio['TIT2'] = title_frame
### ID3-Tag speichern
# hier tritt auch der Fehler auf
audio.save()
Hier der Traceback, der geschmissen wird:
Code: Alles auswählen
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
audio.save()
File "C:\Python27\lib\site-packages\mutagen\id3.py", line 370, in save
framedata = [self.__save_frame(frame) for (key, frame) in frames]
File "C:\Python27\lib\site-packages\mutagen\id3.py", line 461, in __save_frame
framedata = frame._writeData()
File "C:\Python27\lib\site-packages\mutagen\id3.py", line 1060, in _writeData
data.append(writer.write(self, getattr(self, writer.name)))
File "C:\Python27\lib\site-packages\mutagen\id3.py", line 773, in write
data.append(self.specs[0].write(frame, v))
File "C:\Python27\lib\site-packages\mutagen\id3.py", line 748, in write
return value.encode(enc) + term
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u017e' in position 12: ordinal not in range(256)
Der ganze Ablauf findet also nur in dem id3-Modul statt.
Und hier die für den Fehler verantwortliche Klasse im Modul mutagen.id3:
Code: Alles auswählen
class EncodedTextSpec(Spec):
# Okay, seriously. This is private and defined explicitly and
# completely by the ID3 specification. You can't just add
# encodings here however you want.
_encodings = ( ('latin1', '\x00'), ('utf16', '\x00\x00'),
('utf_16_be', '\x00\x00'), ('utf8', '\x00') )
def read(self, frame, data):
enc, term = self._encodings[frame.encoding]
ret = ''
if len(term) == 1:
if term in data:
data, ret = data.split(term, 1)
else:
offset = -1
try:
while True:
offset = data.index(term, offset+1)
if offset & 1: continue
data, ret = data[0:offset], data[offset+2:]; break
except ValueError: pass
if len(data) < len(term): return u'', ret
return data.decode(enc), ret
def write(self, frame, value):
enc, term = self._encodings[frame.encoding]
return value.encode(enc) + term ################ line 748!
def validate(self, frame, value): return unicode(value)
In der write-Methode wird der Text für ein Frame auf das im Frame angegebene Encoding kodiert und zurückgegeben.
Das ist aber in meinem Fall nicht erwünscht.
Wenn ich den Rückgabewert wie folgt ändere...
Code: Alles auswählen
def write(self, frame, value):
enc, term = self._encodings[frame.encoding]
return value + term
...dann kann der ID3-Tag in der mp3-Datei gespeichert werden, ohne Fehlermeldung.
Diese Änderung möchte ich jetzt aber nicht im Paket selbst vornehmen.
Daher habe ich auch die Schritte durchgeführt, die ich im ersten Posting erklärt habe. Also erst die Klassendefinition, dann den Monkey Patch und danach den gleichen Code zum Bearbeiten des ID3-Tags.
Das hat bei mir aber leider nicht funktioniert. Es erscheint derselbe Traceback wie oben. Das Modul mutagen.id3 verwendet also nicht die neu definierte Klasse.
Komischerweise ist es so, wenn ich meiner Klasse eine weitere Methode hinzufüge...
Code: Alles auswählen
import mutagen.id3
class EncodedTextSpec2(mutagen.id3.Spec):
...
def test(self): print 'irgendetwas'
mutagen.id3.EncodedTextSpec = EncodedTextSpec2
...dann kann diese Methode auch aufgerufen werden:
Also funktioniert der Monkey Patch ja doch.
Mich verwirrt das nur
Wie gesagt, ich bin um jeden Ratschlag dankbar.