web-dev-qa-db-fra.com

Affichage d'un meilleur message d'erreur que "Aucun objet JSON n'a pu être décodé"

Code Python pour charger des données depuis un fichier JSON long et compliqué:

with open(filename, "r") as f:
  data = json.loads(f.read())

(note: la meilleure version du code devrait être:

with open(filename, "r") as f:
  data = json.load(f)

mais les deux présentent un comportement similaire)

Pour de nombreux types d'erreur JSON (délimiteurs manquants, barres obliques inverses incorrectes dans les chaînes, etc.), cela affiche un message utile de Nice contenant la ligne et le numéro de colonne où l'erreur JSON a été trouvée.

Cependant, pour d'autres types d'erreur JSON (y compris le classique "utiliser une virgule sur le dernier élément d'une liste", mais aussi d'autres choses comme la majuscule vrai/faux), la sortie de Python est simplement:

Traceback (most recent call last):
  File "myfile.py", line 8, in myfunction
    config = json.loads(f.read())
  File "c:\python27\lib\json\__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "c:\python27\lib\json\decoder.py", line 360, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "c:\python27\lib\json\decoder.py", line 378, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Pour ce type de ValueError, comment obtenez-vous que Python vous indique où se trouve l'erreur dans le fichier JSON?

118
OJW

J'ai constaté que le module simplejson génère davantage d'erreurs descriptives dans les cas où le module intégré json est vague. Par exemple, dans le cas d'une virgule après le dernier élément d'une liste:

json.loads('[1,2,]')
....
ValueError: No JSON object could be decoded

ce qui n'est pas très descriptif. La même opération avec simplejson:

simplejson.loads('[1,2,]')
...
simplejson.decoder.JSONDecodeError: Expecting object: line 1 column 5 (char 5)

Beaucoup mieux! De même pour d'autres erreurs courantes telles que la majuscule True.

161
tom

Vous ne pourrez pas obtenir de python pour vous dire où le JSON est incorrect. Vous devrez utiliser un linter en ligne quelque part comme this

Cela vous montrera une erreur dans le JSON que vous essayez de décoder. 

14
myusuf3

Vous pouvez essayer la bibliothèque rson trouvée ici: http://code.google.com/p/rson/ . Je le trouve aussi sur PYPI: https://pypi.python.org/pypi/rson/0.9 afin que vous puissiez utiliser easy_install ou pip pour l'obtenir.

pour l'exemple donné par tom:

>>> rson.loads('[1,2,]')
...
rson.base.tokenizer.RSONDecodeError: Unexpected trailing comma: line 1, column 6, text ']'

RSON est conçu pour être un sur-ensemble de JSON, afin de pouvoir analyser les fichiers JSON. Il a également une syntaxe alternative qui est beaucoup plus agréable pour les humains à regarder et éditer. Je l'utilise assez souvent pour les fichiers d'entrée.

En ce qui concerne la capitalisation des valeurs booléennes: il apparaît que rson lit les booléens mal capitalisés sous forme de chaînes.

>>> rson.loads('[true,False]')
[True, u'False']
7
Brad Campbell

J'ai eu un problème similaire et c'était dû à une seule citation. Le standard JSON ( http://json.org ) parle uniquement de l'utilisation de doubles guillemets; il est donc normal que la bibliothèque python json ne prenne en charge que les guillemets doubles.

4
Knight Samar

Pour ma version particulière de ce problème, je suis allé de l'avant et ai recherché la déclaration de fonction de load_json_file(path) dans le fichier packaging.py, puis j'ai inséré une ligne print dans ce fichier:

def load_json_file(path):
    data = open(path, 'r').read()
    print data
    try:
        return Bunch(json.loads(data))
    except ValueError, e:
        raise MalformedJsonFileError('%s when reading "%s"' % (str(e),
                                                               path))

De cette façon, le contenu du fichier json serait imprimé avant de saisir le test, et ainsi, même avec mes connaissances en Python à peine existantes, je pouvais rapidement comprendre pourquoi ma configuration ne pouvait pas lire le fichier json.
.__ (c’est parce que j’avais configuré mon éditeur de texte pour écrire une nomenclature UTF-8… stupide)

Mentionnons simplement ceci parce que, même si ce n’était peut-être pas une bonne réponse au problème spécifique du PO, c’était une méthode assez rapide pour déterminer la source d’un bogue très oppressant. Et je parie que beaucoup de gens tomberont sur cet article qui recherchent une solution plus verbeuse pour un MalformedJsonFileError: No JSON object could be decoded when reading …. Cela pourrait donc les aider.

2
WoodrowShigeru

J'ai eu un problème similaire c'était mon code:

    json_file=json.dumps(pyJson)
    file = open("list.json",'w')
    file.write(json_file)  

    json_file = open("list.json","r")
    json_decoded = json.load(json_file)
    print json_decoded

le problème était que j'avais oublié de file.close() je l'ai fait et résolu le problème.

2
HabibKazemi

Quant à moi, mon fichier json est très volumineux. Lorsqu’il utilise json en python, il obtient l’erreur ci-dessus.

Après avoir installé simplejson par Sudo pip install simplejson.

Et puis je l'ai résolu.

import json
import simplejson


def test_parse_json():
    f_path = '/home/hello/_data.json'
    with open(f_path) as f:
        # j_data = json.load(f)      # ValueError: No JSON object could be decoded
        j_data = simplejson.load(f)  # right
    lst_img = j_data['images']['image']
    print lst_img[0]


if __== '__main__':
    test_parse_json()
1
Jayhello

Lorsque votre fichier est créé. Au lieu de créer un fichier dont le contenu est vide. Remplacer par:

json.dump({}, file)
0
Hoang Duong

Cliquez simplement sur le même problème et dans mon cas, le problème était lié à BOM (marque d'ordre des octets) au début du fichier. 

json.tool refuserait de traiter même un fichier vide (entre accolades seulement) jusqu'à ce que je supprime la marque de nomenclature UTF.

Ce que j'ai fait c'est:

  • ouvert mon fichier json avec vim,
  • marque d'ordre d'octet supprimée (set nobomb)
  • sauvegarder le fichier

Cela a résolu le problème avec json.tool. J'espère que cela t'aides!

0
Tomasz W

La réponse acceptée est la plus simple pour résoudre le problème. Mais au cas où vous n'êtes pas autorisé à installer simplejson en raison de la politique de votre entreprise, je propose la solution ci-dessous pour résoudre le problème particulier de "en utilisant une virgule sur le dernier élément d'une liste" :

  1. Créez une classe enfant "JSONLintCheck" à hériter de la classe "JSONDecoder" et substituez la méthode init de la classe "JSONDecoder" comme ci-dessous: 

    def __init__(self, encoding=None, object_hook=None, parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)        
            super(JSONLintCheck,self).__init__(encoding=None, object_hook=None,      parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)
            self.scan_once = make_scanner(self)
    
  1. make_scanner est une nouvelle fonction qui remplaçait la méthode 'scan_once' de la classe ci-dessus. Et voici le code pour cela:
  1 #!/usr/bin/env python
  2 from json import JSONDecoder
  3 from json import decoder
  4 import re
  5
  6 NUMBER_RE = re.compile(
  7     r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
  8     (re.VERBOSE | re.MULTILINE | re.DOTALL))
  9
 10 def py_make_scanner(context):
 11     parse_object = context.parse_object
 12     parse_array = context.parse_array
 13     parse_string = context.parse_string
 14     match_number = NUMBER_RE.match
 15     encoding = context.encoding
 16     strict = context.strict
 17     parse_float = context.parse_float
 18     parse_int = context.parse_int
 19     parse_constant = context.parse_constant
 20     object_hook = context.object_hook
 21     object_pairs_hook = context.object_pairs_hook
 22
 23     def _scan_once(string, idx):
 24         try:
 25             nextchar = string[idx]
 26         except IndexError:
 27             raise ValueError(decoder.errmsg("Could not get the next character",string,idx))
 28             #raise StopIteration
 29
 30         if nextchar == '"':
 31             return parse_string(string, idx + 1, encoding, strict)
 32         Elif nextchar == '{':
 33             return parse_object((string, idx + 1), encoding, strict,
 34                 _scan_once, object_hook, object_pairs_hook)
 35         Elif nextchar == '[':
 36             return parse_array((string, idx + 1), _scan_once)
 37         Elif nextchar == 'n' and string[idx:idx + 4] == 'null':
 38             return None, idx + 4
 39         Elif nextchar == 't' and string[idx:idx + 4] == 'true':
 40             return True, idx + 4
 41         Elif nextchar == 'f' and string[idx:idx + 5] == 'false':
 42             return False, idx + 5
 43
 44         m = match_number(string, idx)
 45         if m is not None:
 46             integer, frac, exp = m.groups()
 47             if frac or exp:
 48                 res = parse_float(integer + (frac or '') + (exp or ''))
 49             else:
 50                 res = parse_int(integer)
 51             return res, m.end()
 52         Elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
 53             return parse_constant('NaN'), idx + 3
 54         Elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
 55             return parse_constant('Infinity'), idx + 8
 56         Elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
 57             return parse_constant('-Infinity'), idx + 9
 58         else:
 59             #raise StopIteration   # Here is where needs modification
 60             raise ValueError(decoder.errmsg("Expecting propert name enclosed in double quotes",string,idx))
 61     return _scan_once
 62
 63 make_scanner = py_make_scanner
  1. Mieux vaut placer la fonction 'make_scanner' avec la nouvelle classe enfant dans un même fichier. 
0
Jeremy Li