Background: J'écris un programme python qui devrait gérer mes fichiers musicaux. Il explore des répertoires et place les fichiers et leurs métadonnées (via mutagen), codés en JSON , dans un fichier en tant que simple "base de données". Je recherche très bien le répertoire, mais lorsque j'essaie d'enregistrer la base de données ou de l'encoder au format JSON, un "TypeError: {...} n'est pas sérialisable JSON" (le ... y a quelques clés et valeurs d'un dict, plus sur cela ci-dessous)
Le problème: Le programme crée un objet dictionnaire volumineux au format suivant:
{
"<song id>":{
"artist":"<song artist>",
"album":"<song album>",
"title":"<song title>"},
...
}
Chaque fichier de chanson est indexé via ce format. Lorsque j'essaie de vider la base de données dans un fichier, je reçois ceci:
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
sit()
File "D:\workbench\ideas\musicmanager\v0\spider.py", line 116, in sit
json.dump(js.db,f,True)
File "C:\Python27\lib\json\__init__.py", line 181, in dump
for chunk in iterable:
File "C:\Python27\lib\json\encoder.py", line 428, in _iterencode
for chunk in _iterencode_dict(o, _current_indent_level):
File "C:\Python27\lib\json\encoder.py", line 402, in _iterencode_dict
for chunk in chunks:
File "C:\Python27\lib\json\encoder.py", line 402, in _iterencode_dict
for chunk in chunks:
File "C:\Python27\lib\json\encoder.py", line 436, in _iterencode
o = _default(o)
File "C:\Python27\lib\json\encoder.py", line 178, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: {'album': [u"Rooney's Lost Album"], 'title': [u'The Kids
After Sunset'], 'artist': [u'Rooney']} is not JSON serializable
Avec la clé pour cette entrée de chanson particulière étant
Rooney|Rooney's Lost Album|The Kids After Sunset|The Kids After Sunset.iTunes.mp3
(Le format de l'identifiant est un peu volumineux, je pourrais finir par hacher ça ...)
Alors j'ai essayé de
json.dumps({'album': [u"Rooney's Lost Album"], 'title': [u'The Kids
After Sunset'], 'artist': [u'Rooney']})
qui a bien fonctionné, tout comme
json.dumps({"Rooney|Rooney's Lost Album|The Kids After Sunset|The Kids
After Sunset.iTunes.mp3":""})
Et puis j'ai essayé ceci:
rooney = "Rooney|Rooney's Lost Album|The Kids After Sunset|The Kids
After Sunset.iTunes.mp3"
json.dumps({rooney:js.db['songsbyid'][rooney]})
Ce qui a échoué avec l'erreur de type à nouveau.
Pourquoi cet objet échoue-t-il avec json.dump? J'ai plein d'autres objets avec des clés contenant des tuyaux "|" et apostrophes "'" ... Pour le moment, je n'ai aucun moyen de le tester, dois-je poster une version en conserve de la base de données?
Notes complémentaires
L'objet résultant sous json.dumps est correct. Je me demande donc si le problème concerne la taille de la base de données.
{rooney: js.db ['songsbyid'] [rooney]} {"Rooney | L'album perdu de Rooney | Les enfants après le coucher du soleil | Les enfants après le coucher du soleil.iTunes.mp3": {'album': [u "L'album perdu de Rooney" ], 'titre': [les enfants après le coucher du soleil], 'artiste': [u'Rooney ']}}
Si j'exclus la chanson en renommant l'extension pour que le script l'ignore, une autre chanson arbitraire provoque la même erreur. J'ai renommé et exclu cette nouvelle chanson et j'ai rencontré une autre chanson ... Je ne sais pas combien il y en a.
J'ai changé de programme pour explorer le sous-répertoire le plus éloigné contenant le morceau problème à l'origine, et json.dump a généré une erreur TypeError sur un morceau complètement différent ...
Parce que ce n'est pas vraiment un dictionnaire; c'est un autre type de mapping qui ressemble à un dictionnaire. Utilisez type()
pour vérifier. Passez-le à dict()
pour en tirer un dictionnaire réel.
Dans mon cas, les valeurs booléennes dans mon Python dict étaient le problème. Les valeurs booléennes JSON sont en minuscules ("true", "false") alors que dans Python ils sont en majuscule ("Vrai", "Faux"). Impossible de trouver cette solution en ligne, mais j'espère que cela aidera.
J'ai écrit un cours pour normaliser les données de mon dictionnaire. L'élément de la classe NormalizeData ci-dessous doit être de type dict. Et vous devez remplacer dans __iterate () par votre objet de classe personnalisé ou tout autre type d'objet que vous souhaitez normaliser.
class NormalizeData:
def __init__(self, element):
self.element = element
def execute(self):
if isinstance(self.element, dict):
self.__iterate()
else:
return
def __iterate(self):
for key in self.element:
if isinstance(self.element[key], <ClassName>):
self.element[key] = str(self.element[key])
node = NormalizeData(self.element[key])
node.execute()