"Hiçbir JSON nesnesinin kodu çözülemedi" den daha iyi hata mesajı görüntüleme


128

Bazı uzun karmaşık JSON dosyasından veri yüklemek için Python kodu:

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

(not: en iyi kod sürümü şöyle olmalıdır:

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

ancak ikisi de benzer davranış sergiler)

Birçok JSON hatası türü için (eksik sınırlayıcılar, dizelerde yanlış eğik çizgiler, vb.), Bu, JSON hatasının bulunduğu satır ve sütun numarasını içeren güzel ve yararlı bir mesaj yazdırır.

Bununla birlikte, diğer JSON hatası türleri için (klasik "bir listedeki son öğede virgül kullanmak" ve ayrıca doğru / yanlışı büyük harfle yazmak gibi diğer şeyler dahil), Python'un çıktısı şu şekildedir:

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

Bu tür ValueError için, Python'un JSON dosyasındaki hatanın nerede olduğunu size söylemesini nasıl sağlarsınız?


Dosyanızdan bir alıntı yapabilir misiniz?
Ketouem

Şu anda belirli bir dosyada hatayı bulmaya çalışmıyorum; Programımı, okuyacağı herhangi bir dosyada hatayı vurgulayacak şekilde değiştirmeye çalışıyorum.
OJW

2
Doğrudan ilgili değil, json.load(f)bunun yerine yapabilirsinjson.loads(f.read())
Martin Samson

@OJW Bu davranış python'un hangi sürümündeydi?
jxramos

Python 3.8.1 artık "Beklenen değer: satır 1 sütun 21 (karakter 20)" hata konumunu veriyor
OJW,

Yanıtlar:


173

Yerleşik modülün belirsiz simplejsonolduğu birçok durumda modülün daha açıklayıcı hatalar verdiğini buldum json. Örneğin, bir listedeki son öğeden sonra bir virgül kullanılması durumunda:

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

bu çok açıklayıcı değil. Aynı işlem simplejson:

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

Çok daha iyi! Büyük harf kullanımı gibi diğer yaygın hatalar için de aynı şekilde True.


18
Python'un gelecekteki sürümleri bu geliştirmeleri içerecektir; altındaki aynı proje.
Martijn Pieters


1
@ user2016290 Çekirdek / paket dosyalarını doğrudan düzenlemek kötü bir fikirdir. Python'a yama uygulamak kolaydır, bu yüzden bunu kodla yapmak daha iyidir.
Rebs

2
@jxramos: OP, traceback'ten anlaşılacağı üzere Python 2.7 kullandı. İdeone.com (Python 3.7.3) üzerinde hızlı bir test , stdlib jsonkitaplığının güncellendiğini gösterir ve yeni hata mesajı formatını verir. Ancak şu anda tam sürümleri takip edecek vaktim yok.
Martijn Pieters

1
@jxramos buldu, Python 3.5 istisnaları güncelledi: bugs.python.org/issue19361 ( docs.python.org/3/whatsnew/3.5.html#improved-modules aracılığıyla ).
Martijn Pieters

15

Python'un size JSON'un nerede yanlış olduğunu söyleyemeyeceksiniz. Sen gibi bir yerde çevrimiçi bir linter kullanmanız gerekecektir bu

Bu size, kodunu çözmeye çalıştığınız JSON'daki hatayı gösterecektir.


2
Gizli JSON dosyaları için bunu yapabilen çevrimdışı araçlar var mı?
OJW

@OJW bildiğimden değil ama bu, yaşadığınız sorunu çözmeli veya en azından bozuk json'unuzu düzeltmenize izin vermelidir.
myusuf3

12
JSON dosyam yeterli - Programımın, herkes tarafından anlaşılabilir, yararlı hata mesajları yazdırmasını sağlamaya çalışıyorum. Onlara "satır 13, sütun 32'deki virgülden kurtulun" demek iyi olur. Onlara "dosyanızın bir yerinde bir hata var, lütfen insanların size yardım edeceği internete yükleyin" demek kötüdür.
OJW

7

Burada bulunan rson kitaplığını deneyebilirsiniz: http://code.google.com/p/rson/ . Ben de PYPI: https://pypi.python.org/pypi/rson/0.9'da yayınladım, böylece easy_install veya pip'i kullanabilirsiniz.

tom tarafından verilen örnek için:

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

RSON, JSON'un bir üst kümesi olacak şekilde tasarlanmıştır, bu nedenle JSON dosyalarını ayrıştırabilir. Ayrıca, insanların bakması ve düzenlemesi için çok daha hoş olan alternatif bir sözdizimi vardır . Giriş dosyaları için epeyce kullanıyorum.

Boole değerlerinin büyük harfle yazılmasına gelince: rson, dizeler olarak yanlış büyük harfle yazılmış boole'leri okuyor gibi görünüyor.

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

4

Benzer bir sorun yaşadım ve tek alıntılardan kaynaklanıyordu. JSON standardı ( http://json.org ) yalnızca çift ​​tırnak kullanımından bahseder, bu nedenle python jsonkitaplığının yalnızca çift tırnak işaretlerini desteklemesi gerekir .


3

Bu problemin kendi özel versiyonum için, devam ettim load_json_file(path)ve packaging.pydosyanın içindeki fonksiyon bildirimini araştırdım , sonra printiçine bir satır kaçakçılığı yaptım:

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

Bu şekilde, dene-yakalamaya girmeden önce json dosyasının içeriğini yazdırırdı ve bu şekilde - az var olan Python bilgimle bile - yapılandırmamın neden json dosyasını okuyamadığını çabucak anlayabildim.
(Metin düzenleyicimi UTF-8 BOM yazacak şekilde ayarladığım içindir… aptal)

Bundan bahsetmek gerekirse, OP'nin özel sorununa belki de iyi bir cevap olmasa da, bu çok baskıcı bir hatanın kaynağını belirlemede oldukça hızlı bir yöntemdi. Ve bahse girerim ki, a için daha ayrıntılı bir çözüm arayan pek çok kişi bu makaleye rastlayacaktır MalformedJsonFileError: No JSON object could be decoded when reading …. Bu onlara yardımcı olabilir.


Dosya G / Ç ( with open(fn) as f) için bağlam yöneticisini kullanmalısınız, sizin için bir istisna olarak dosyayı kapatmayı yönetir. en.wikibooks.org/wiki/Python_Programming/…
Rebs

1
+1. Sonra standart davranışı üzerine o monkeypatching bir örneğini göstermek olsaydı, bu oldukça düzgün olurdu
Craig Brett

Üzgünüm, bu sorun çözüldükten sonra hiçbir Python koduna dokunmadım. Belki başka biri yardım edebilir?
WoodrowShigeru

3

Bana gelince, json dosyam çok büyük, python'da ortak kullanıldığında jsonyukarıdaki hatayı alıyor.

Sonra yüklemek simplejsontarafından sudo pip install simplejson.

Ve sonra çözdüm.

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

1

Benzer bir sorun yaşadım, bu benim kodumdu:

    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

sorun, file.close() bunu yaptığımı unutmuştum ve sorunu çözmüştüm.


Benim için de çalıştı, neden daha önce bu problemi yaşamadım bilmiyorum.
pceccon

Dosya G / Ç ( with open(fn) as f) için bağlam yöneticisini kullanmalısınız, sizin için bir istisna olarak dosyayı kapatmayı yönetir. en.wikibooks.org/wiki/Python_Programming/…
Rebs

0

Kabul edilen cevap, sorunu çözmek için en kolay olanıdır. Ancak şirket politikanız nedeniyle simplejson'u kurmanıza izin verilmiyorsa, "listedeki son öğede virgül kullanma" sorununu çözmek için aşağıdaki çözümü öneriyorum :

  1. "JSONDecoder" sınıfından miras almak için bir "JSONLintCheck" alt sınıfı oluşturun ve "JSONDecoder" sınıfının init yöntemini aşağıdaki gibi geçersiz kılın:

    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 , yukarıdaki sınıfın 'scan_once' yöntemini geçersiz kılmak için kullanılan yeni bir işlevdir. Ve işte bunun kodu :
  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. Yeni alt sınıfla birlikte 'make_scanner' işlevini aynı dosyaya koyun.

0

Sadece aynı sorunu çözdüm ve benim durumumda sorun BOMdosyanın başlangıcındaki (bayt sırası işareti) ile ilgiliydi .

json.tool UTF BOM işaretini kaldırana kadar boş bir dosyayı (sadece küme parantezleri) işlemeyi reddederdim.

Yaptığım şey:

  • json dosyamı vim ile açtım,
  • bayt sırası işareti kaldırıldı ( set nobomb)
  • dosyayı kaydet

Bu, json.tool ile ilgili sorunu çözdü. Bu yardımcı olur umarım!


-1

Dosyanız oluşturulduğunda. İçeriği olan bir dosya oluşturmak yerine boştur. İle değiştirin:

json.dump({}, file)

-3

Saf python uygulamalarından 250 kat daha hızlı olduğunu iddia eden cjson kullanabilirsiniz , çünkü "bazı uzun karmaşık JSON dosyanız" vardır ve muhtemelen birkaç kez çalıştırmanız gerekecektir (kod çözücüler başarısız olur ve ilk hatayı bildirirler. yalnızca karşılaşma).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.