Anzeige einer besseren Fehlermeldung als "Kein JSON-Objekt konnte dekodiert werden"

128

Python-Code zum Laden von Daten aus einer langen, komplizierten JSON-Datei:

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

(Hinweis: Die beste Codeversion sollte sein:

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

aber beide zeigen ein ähnliches Verhalten)

Bei vielen Arten von JSON-Fehlern (fehlende Trennzeichen, falsche Backslashes in Zeichenfolgen usw.) wird eine nette hilfreiche Nachricht gedruckt, die die Zeilen- und Spaltennummer enthält, in der der JSON-Fehler gefunden wurde.

Für andere Arten von JSON-Fehlern (einschließlich des Klassikers "Verwenden von Komma für das letzte Element in einer Liste", aber auch für andere Dinge wie Groß- und Kleinschreibung von wahr / falsch) lautet die Python-Ausgabe jedoch nur:

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

Wie kann Python bei dieser Art von ValueError feststellen, wo der Fehler in der JSON-Datei liegt?

ABl
quelle
Könnten Sie einen Auszug aus Ihrer Datei sichern?
Ketouem
Ich versuche jetzt nicht, den Fehler in einer bestimmten Datei zu finden. Ich versuche, mein Programm so zu ändern, dass es den Fehler in jeder zukünftigen Datei hervorhebt, die es liest.
ABl.
2
Nicht direkt verwandt, aber Sie könnten einfach tun, json.load(f)anstattjson.loads(f.read())
Martin Samson
@OJW auf welcher Python-Version war dieses Verhalten?
Jxramos
Python 3.8.1 gibt jetzt die Fehlerposition "Erwarteter Wert: Zeile 1, Spalte 21 (Zeichen 20)" an
ABl.

Antworten:

173

Ich habe festgestellt, dass das simplejsonModul in vielen Fällen, in denen das integrierte jsonModul vage ist, aussagekräftigere Fehler enthält . Zum Beispiel für den Fall, dass nach dem letzten Element in einer Liste ein Komma steht:

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

das ist nicht sehr beschreibend. Die gleiche Operation mit simplejson:

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

Viel besser! Ebenso für andere häufige Fehler wie Großschreibung True.

Tom
quelle
18
Zukünftige Versionen von Python werden diese Verbesserungen enthalten. Es ist das gleiche Projekt darunter.
Martijn Pieters
1
@ user2016290 Das direkte Bearbeiten von Kern- / Paketdateien ist eine schlechte Idee. Python lässt sich leicht mit Affen patchen, daher ist es besser, dies im Code zu tun.
Rebs
2
@jxramos: Das OP verwendete Python 2.7, wie aus dem Traceback hervorgeht. Ein schneller Test auf ideone.com (Python 3.7.3) zeigt, dass die stdlib- jsonBibliothek aktualisiert wurde und das neue Fehlermeldungsformat enthält. Ich habe jedoch momentan keine Zeit, genaue Veröffentlichungen zu verfolgen.
Martijn Pieters
1
@jxramos hat es gefunden, Python 3.5 hat die Ausnahmen aktualisiert: bugs.python.org/issue19361 (über docs.python.org/3/whatsnew/3.5.html#improved-modules ).
Martijn Pieters
15

Sie können Python nicht dazu bringen, Ihnen mitzuteilen, wo der JSON falsch ist. Sie erhalten eine Linter irgendwo online wie verwenden , müssen diese

Dies zeigt Ihnen einen Fehler in dem JSON, den Sie dekodieren möchten.

myusuf3
quelle
2
Gibt es Offline-Tools, die dies für vertrauliche JSON-Dateien tun können?
ABl.
@OJW nicht das ich weiß, aber das sollte das Problem lösen, das Sie haben, oder zumindest Sie Ihren kaputten json reparieren lassen.
Myusuf3
12
Meine JSON-Datei ist in Ordnung - ich versuche, mein Programm nützliche Fehlermeldungen drucken zu lassen, die für jeden verständlich sind. Es ist gut, ihnen zu sagen, dass sie dieses Komma in Zeile 13, Spalte 32, entfernen sollen. Es ist schlecht, ihnen zu sagen, dass irgendwo in Ihrer Datei ein Fehler vorliegt. Laden Sie ihn ins Internet hoch, wo Ihnen die Leute helfen.
ABl.
7

Sie können die hier gefundene rson-Bibliothek ausprobieren: http://code.google.com/p/rson/ . Ich habe es auch auf PYPI: https://pypi.python.org/pypi/rson/0.9, so dass Sie easy_install oder pip verwenden können, um es zu bekommen.

für das Beispiel von Tom:

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

RSON wurde als Obermenge von JSON entwickelt, sodass JSON-Dateien analysiert werden können. Es hat auch eine alternative Syntax, die für Menschen viel schöner anzusehen und zu bearbeiten ist. Ich benutze es ziemlich oft für Eingabedateien.

Was die Großschreibung von Booleschen Werten betrifft: Es scheint, dass rson falsch großgeschriebene Boolesche Werte als Zeichenfolgen liest.

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

Ich hatte ein ähnliches Problem und es lag an einfachen Anführungszeichen. Der JSON-Standard ( http://json.org ) spricht nur von der Verwendung von doppelten Anführungszeichen, daher muss es sein, dass die Python- jsonBibliothek nur doppelte Anführungszeichen unterstützt.

Ritter Samar
quelle
3

Für meine spezielle Version dieses Problems habe ich die Funktionsdeklaration load_json_file(path)in der packaging.pyDatei durchsucht und dann eine printZeile hineingeschmuggelt:

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))

Auf diese Weise wurde der Inhalt der JSON-Datei gedruckt, bevor der Try-Catch eingegeben wurde, und auf diese Weise konnte ich - trotz meiner kaum vorhandenen Python-Kenntnisse - schnell herausfinden, warum meine Konfiguration die JSON-Datei nicht lesen konnte.
(Es war, weil ich meinen Texteditor so eingerichtet hatte, dass er eine UTF-8-Stückliste schreibt… dumm)

Ich erwähne dies nur, weil dies zwar keine gute Antwort auf das spezifische Problem des OP ist, dies jedoch eine ziemlich schnelle Methode war, um die Quelle eines sehr unterdrückenden Fehlers zu bestimmen. Und ich wette, dass viele Leute auf diesen Artikel stoßen werden, die nach einer ausführlicheren Lösung für a suchen MalformedJsonFileError: No JSON object could be decoded when reading …. Das könnte ihnen also helfen.

WoodrowShigeru
quelle
Sie sollten den Kontextmanager für Datei-E / A ( with open(fn) as f) verwenden. Er behandelt das Schließen der Datei in einer Ausnahme für Sie. en.wikibooks.org/wiki/Python_Programming/...
Rebs
1
+1. Wenn Sie ein Beispiel dafür zeigen könnten, wie man das auf das Standardverhalten überträgt, wäre das ziemlich ordentlich
Craig Brett,
Entschuldigung, ich habe keinen Python-Code berührt, nachdem dieses Problem herausgefunden wurde. Vielleicht kann jemand anderes helfen?
WoodrowShigeru
3

Was mich betrifft, ist meine JSON-Datei sehr groß. Wenn sie jsonin Python verwendet wird, wird der obige Fehler angezeigt.

Nach der Installation simplejsonvon sudo pip install simplejson.

Und dann habe ich es gelöst.

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 __name__ == '__main__':
    test_parse_json()
Jayhello
quelle
1

Ich hatte ein ähnliches Problem, dies war mein 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

Das Problem war, dass ich vergessen hatte, es zu file.close() tun und das Problem zu beheben.

Habib Kazemi
quelle
Hat auch für mich gearbeitet, weiß nicht, warum ich dieses Problem vorher nicht hatte.
Pceccon
Sie sollten den Kontextmanager für Datei-E / A ( with open(fn) as f) verwenden. Er behandelt das Schließen der Datei in einer Ausnahme für Sie. en.wikibooks.org/wiki/Python_Programming/...
Rebs
0

Die akzeptierte Antwort ist die einfachste, um das Problem zu beheben. Für den Fall, dass Sie den simplejson aufgrund Ihrer Unternehmensrichtlinien nicht installieren dürfen, schlage ich die folgende Lösung vor, um das spezielle Problem "Verwenden von Komma für das letzte Element in einer Liste" zu beheben :

  1. Erstellen Sie eine untergeordnete Klasse "JSONLintCheck", um von der Klasse "JSONDecoder" zu erben, und überschreiben Sie die Init- Methode der Klasse "JSONDecoder" wie folgt:

    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 ist eine neue Funktion, mit der die 'scan_once'-Methode der obigen Klasse überschrieben wurde. Und hier ist Code dafür:
  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. Fügen Sie die Funktion 'make_scanner' besser zusammen mit der neuen untergeordneten Klasse in dieselbe Datei ein.
Jeremy Li
quelle
0

Treffen Sie einfach das gleiche Problem und in meinem Fall war das Problem mit BOM(Byte Order Mark) am Anfang der Datei verbunden.

json.tool Ich würde mich weigern, auch leere Dateien (nur geschweifte Klammern) zu verarbeiten, bis ich die UTF-Stücklistenmarkierung entfernt habe.

Was ich getan habe ist:

  • öffnete meine json datei mit vim,
  • Byte Order Mark ( set nobomb) entfernt
  • Datei speichern

Dies löste das Problem mit json.tool. Hoffe das hilft!

Tomasz W.
quelle
-1

Wenn Ihre Datei erstellt wird. Anstatt eine Datei mit Inhalt zu erstellen, ist diese leer. Ersetzen mit:

json.dump({}, file)
Hoang Duong
quelle
-3

Sie könnten cjson verwenden , das behauptet, bis zu 250-mal schneller zu sein als reine Python-Implementierungen, da Sie "eine lange, komplizierte JSON-Datei" haben und diese wahrscheinlich mehrmals ausführen müssen (Decoder schlagen fehl und melden den ersten Fehler, den sie verursachen nur Begegnung).

yahe
quelle