Menampilkan pesan kesalahan yang lebih baik daripada "Tidak ada objek JSON yang dapat diterjemahkan"

128

Kode python untuk memuat data dari beberapa file JSON yang rumit:

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

(catatan: versi kode terbaik harus:

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

tetapi keduanya menunjukkan perilaku yang sama)

Untuk banyak jenis kesalahan JSON (pembatas yang hilang, kesalahan backslash dalam string, dll), ini mencetak pesan bermanfaat yang bagus yang berisi baris dan nomor kolom tempat kesalahan JSON ditemukan.

Namun, untuk jenis kesalahan JSON lainnya (termasuk klasik "menggunakan koma pada item terakhir dalam daftar", tetapi juga hal-hal lain seperti kapitalisasi benar / salah), output Python hanyalah:

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

Untuk jenis ValueError, bagaimana Anda mendapatkan Python untuk memberi tahu Anda di mana kesalahan dalam file JSON?

OJW
sumber
Bisakah Anda membuang kutipan file Anda?
Ketouem
Saya tidak mencoba menemukan kesalahan dalam file tertentu sekarang; Saya mencoba untuk memodifikasi program saya sehingga akan menyoroti kesalahan pada setiap file di masa depan yang dibacanya.
OJW
2
Tidak terkait langsung, tetapi Anda bisa melakukannya json.load(f)sebagai gantinyajson.loads(f.read())
Martin Samson
@ OJW versi python apa perilaku ini?
jxramos
Python 3.8.1 sekarang memberikan posisi kesalahan "Nilai yang diharapkan: baris 1 kolom 21 (char 20)"
OJW

Jawaban:

173

Saya telah menemukan bahwa simplejsonmodul memberikan lebih banyak kesalahan deskriptif dalam banyak kasus di mana jsonmodul built-in tidak jelas. Misalnya, untuk kasus koma setelah item terakhir dalam daftar:

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

yang tidak terlalu deskriptif. Operasi yang sama dengan simplejson:

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

Jauh lebih baik! Demikian juga untuk kesalahan umum lainnya seperti memanfaatkan True.

tom
sumber
18
Versi Python yang akan datang akan mencakup peningkatan tersebut; itu adalah proyek yang sama di bawahnya.
Martijn Pieters
1
@ user2016290 Mengedit file inti / paket secara langsung adalah ide yang buruk. Python mudah untuk ditambal, jadi lebih baik melakukannya dalam kode.
Rebs
2
@ jxramos: OP menggunakan Python 2.7, terbukti dari traceback. Tes cepat pada ideone.com (Python 3.7.3) menunjukkan bahwa jsonperpustakaan stdlib telah diperbarui dan memberikan format pesan kesalahan baru. Saya tidak punya waktu untuk melacak rilis yang tepat sekarang.
Martijn Pieters
1
@jxramos menemukannya, Python 3.5 memperbarui pengecualian: bugs.python.org/issue19361 (via docs.python.org/3/whatsnew/3.5.html#improved-modules ).
Martijn Pieters
15

Anda tidak akan bisa mendapatkan python untuk memberi tahu Anda di mana JSON salah. Anda perlu menggunakan linter online di suatu tempat seperti ini

Ini akan menunjukkan Anda kesalahan dalam JSON yang Anda coba decode.

myusuf3
sumber
2
Apakah ada alat offline yang dapat melakukan ini untuk file JSON rahasia?
OJW
@ OJW bukan yang saya tahu tapi itu harus menyelesaikan masalah yang Anda alami atau setidaknya membiarkan Anda memperbaiki json Anda yang rusak.
myusuf3
12
File JSON saya baik-baik saja - Saya mencoba membuat program saya mencetak pesan kesalahan yang berguna yang dapat dimengerti oleh siapa saja. Memberi tahu mereka "singkirkan koma di baris 13 kolom 32" itu bagus. Memberitahu mereka "ada kesalahan di suatu tempat di file Anda, harap unggah ke internet tempat orang lain akan membantu Anda" itu buruk.
OJW
7

Anda dapat mencoba perpustakaan rson yang ditemukan di sini: http://code.google.com/p/rson/ . Saya juga menggunakan PYPI: https://pypi.python.org/pypi/rson/0.9 sehingga Anda dapat menggunakan easy_install atau pip untuk mendapatkannya.

untuk contoh yang diberikan oleh tom:

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

RSON dirancang untuk menjadi superset dari JSON, sehingga dapat mem-parsing file JSON. Ini juga memiliki sintaks alternatif yang banyak lebih baik bagi manusia untuk dilihat dan diedit. Saya menggunakannya sedikit untuk input file.

Adapun kapitalisasi nilai boolean: tampaknya rson membaca huruf boolean yang ditulis dengan huruf kapital sebagai string.

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

Saya memiliki masalah serupa dan itu karena singlequotes. Standar JSON ( http://json.org ) hanya berbicara tentang menggunakan tanda kutip ganda sehingga harus bahwa jsonperpustakaan python hanya mendukung tanda kutip ganda.

Ksatria Samar
sumber
3

Untuk versi khusus masalah ini, saya melanjutkan dan mencari deklarasi fungsi load_json_file(path)di dalam packaging.pyfile, lalu menyelundupkan satu printbaris ke dalamnya:

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

Dengan cara itu akan mencetak konten file json sebelum memasukkan try-catch, dan dengan cara itu - bahkan dengan pengetahuan Python saya yang belum ada - saya dapat dengan cepat mencari tahu mengapa konfigurasi saya tidak dapat membaca file json.
(Itu karena saya telah mengatur editor teks saya untuk menulis BOM UTF-8 ... bodoh)

Hanya menyebutkan ini karena, walaupun mungkin bukan jawaban yang baik untuk masalah khusus OP, ini adalah metode yang agak cepat dalam menentukan sumber bug yang sangat menindas. Dan saya bertaruh bahwa banyak orang akan menemukan artikel ini yang mencari solusi yang lebih jelas untuk a MalformedJsonFileError: No JSON object could be decoded when reading …. Sehingga bisa membantu mereka.

WoodrowShigeru
sumber
Anda harus menggunakan manajer konteks untuk file I / O ( with open(fn) as f), itu menangani penutupan file sebagai pengecualian untuk Anda. en.wikibooks.org/wiki/Python_Programming/…
Rebs
1
+1. Jika Anda dapat menunjukkan contoh kemudian monkeypatching itu ke perilaku standar, itu akan sangat rapi
Craig Brett
Maaf, saya tidak pernah menyentuh kode Python setelah masalah itu dipecahkan. Mungkin orang lain bisa membantu?
WoodrowShigeru
3

Bagi saya, file json saya sangat besar, ketika menggunakan common jsondi python mendapat kesalahan di atas.

Setelah menginstal simplejsonoleh sudo pip install simplejson.

Dan kemudian saya memecahkannya.

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
sumber
1

Saya punya masalah serupa ini adalah kode saya:

    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

masalahnya adalah saya lupa file.close() saya melakukannya dan memperbaiki masalahnya.

Habib Kazemi
sumber
Bekerja untuk saya juga, tidak tahu mengapa tidak memiliki masalah ini sebelumnya.
pceccon
Anda harus menggunakan manajer konteks untuk file I / O ( with open(fn) as f), itu menangani penutupan file sebagai pengecualian untuk Anda. en.wikibooks.org/wiki/Python_Programming/…
Rebs
0

Jawaban yang diterima adalah yang paling mudah untuk memperbaiki masalah. Tetapi jika Anda tidak diizinkan menginstal simplejson karena kebijakan perusahaan Anda, saya mengusulkan solusi di bawah ini untuk memperbaiki masalah khusus "menggunakan koma pada item terakhir dalam daftar" :

  1. Buat kelas anak "JSONLintCheck" untuk mewarisi dari kelas "JSONDecoder" dan ganti metode init dari kelas "JSONDecoder" seperti di bawah ini:

    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 adalah fungsi baru yang digunakan untuk mengganti metode 'scan_once' dari kelas di atas. Dan di sini adalah kode untuk itu:
  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. Lebih baik menempatkan fungsi 'make_scanner' bersama dengan kelas anak baru ke dalam file yang sama.
Jeremy Li
sumber
0

Tekan saja masalah yang sama dan dalam kasus saya masalahnya terkait dengan BOM(tanda urutan byte) di awal file.

json.tool akan menolak untuk memproses file bahkan kosong (hanya kurung kurawal) sampai saya menghapus tanda BOM UTF.

Apa yang telah saya lakukan adalah:

  • membuka file json saya dengan vim,
  • tanda pesanan byte yang dihapus ( set nobomb)
  • menyimpan file

Ini menyelesaikan masalah dengan json.tool. Semoga ini membantu!

Tomasz W
sumber
-1

Ketika file Anda dibuat. Alih-alih membuat file dengan konten kosong. Ubah dengan:

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

Anda dapat menggunakan cjson , yang mengklaim hingga 250 kali lebih cepat daripada implementasi pure-python, mengingat Anda memiliki "beberapa file JSON yang rumit" dan Anda mungkin perlu menjalankannya beberapa kali (decoder gagal dan melaporkan kesalahan pertama yang mereka lakukan) hanya bertemu).

yahe
sumber