it-swarm.com.ru

Отображение лучшего сообщения об ошибке, чем "Не удалось декодировать ни один объект JSON"

Код Python для загрузки данных из какого-то длинного сложного файла JSON:

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

(примечание: лучшая версия кода должна быть:

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

но оба демонстрируют похожее поведение)

Для многих типов ошибок JSON (отсутствующие разделители, неправильные обратные косые черты в строках и т.д.) Выводится полезное полезное сообщение, содержащее номер строки и столбца, в котором была обнаружена ошибка JSON.

Однако для других типов ошибок JSON (включая классическое «использование запятой в последнем элементе списка», но также и для других вещей, таких как использование заглавных букв «истина/ложь»), вывод Python просто:

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

Для этого типа ValueError, как вы получаете Python, чтобы сказать вам, где ошибка в файле JSON?

118
OJW

Я обнаружил, что модуль simplejson дает больше описательных ошибок во многих случаях, когда встроенный модуль json является расплывчатым. Например, для случая с запятой после последнего элемента в списке:

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

что не очень наглядно. Та же операция с simplejson:

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

Намного лучше! Аналогично для других распространенных ошибок, таких как использование заглавных букв True.

161
tom

Вы не сможете заставить python сказать вам, где JSON неверен. Вам нужно будет использовать онлайн линтер где-то вроде это

Это покажет вам ошибку в JSON, который вы пытаетесь декодировать. 

14
myusuf3

Вы можете попробовать библиотеку rson, найденную здесь: http://code.google.com/p/rson/ . Это также касается PYPI: https://pypi.python.org/pypi/rson/0.9 , чтобы вы могли использовать easy_install или pip, чтобы получить его.

для примера, приведенного Томом:

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

RSON разработан как расширенный набор JSON, поэтому он может анализировать файлы JSON. Он также имеет альтернативный синтаксис, который много приятнее людям смотреть и редактировать. Я использую это совсем немного для входных файлов.

Что касается заглавных букв логических значений: кажется, что rson читает неверно заглавные логические значения в виде строк.

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

У меня была похожая проблема, и это было связано с одиночными кавычками. Стандарт JSON ( http://json.org ) говорит только об использовании двойных кавычек, поэтому должно быть так, что библиотека python json поддерживает только двойные кавычки.

4
Knight Samar

Для моей конкретной версии этой проблемы я продолжил поиск объявления функции load_json_file(path) в файле packaging.py, а затем ввел в него строку print:

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

Таким образом, он будет печатать содержимое файла json перед входом в try-catch, и таким образом - даже с моими едва существующими знаниями Python - я смог быстро выяснить, почему моя конфигурация не может прочитать файл json.
(Это потому, что я настроил свой текстовый редактор для написания спецификации UTF-8… глупо)

Просто упомянув об этом, потому что, хотя, возможно, это не очень хороший ответ на конкретную проблему ОП, это был довольно быстрый метод определения источника очень удручающей ошибки. И я держу пари, что многие люди будут сталкиваться с этой статьей, которые ищут более подробное решение для MalformedJsonFileError: No JSON object could be decoded when reading …. Так что это может помочь им.

2
WoodrowShigeru

У меня была похожая проблема, это был мой код:

    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

проблема была в том, что я забыл file.close() я сделал это и исправил проблему.

2
HabibKazemi

Что касается меня, мой json-файл очень большой, и при использовании общего json в python возникает вышеуказанная ошибка.

После установки simplejson с помощью Sudo pip install simplejson.

И тогда я решил это.

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

Когда ваш файл создан. Вместо создания файла с содержимым пусто. Заменить:

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

Просто нажмите на ту же проблему, и в моем случае проблема была связана с BOM (метка порядка байтов) в начале файла. 

json.tool отказывался обрабатывать даже пустой файл (только фигурные скобки), пока я не убрал метку спецификации UTF.

Что я сделал, это:

  • открыл мой файл JSON с VIM,
  • удаленная метка порядка байтов (set nobomb)
  • сохранить файл

Это решило проблему с json.tool. Надеюсь это поможет!

0
Tomasz W

Принятый ответ является самым простым для решения проблемы. Но в случае, если вам не разрешено устанавливать simplejson из-за политики вашей компании, я предлагаю решение ниже, чтобы исправить конкретную проблему с «использование запятой в последнем элементе в списке» :

  1. Создайте дочерний класс "JSONLintCheck" для наследования от класса "JSONDecoder" и переопределите метод init класса "JSONDecoder", как показано ниже: 

    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 это новая функция, которая используется для переопределения метода 'scan_once' вышеприведенного класса. И вот код для этого:
  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. Лучше поместить функцию 'make_scanner' вместе с новым дочерним классом в один файл. 
0
Jeremy Li