显示比“无JSON对象可以解码”更好的错误消息

问题描述 投票:120回答:11

用于从一些冗长复杂的JSON文件加载数据的Python代码:

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

(注意:最好的代码版本应该是:

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

但都表现出类似的行为)

对于许多类型的JSON错误(缺少分隔符,字符串中的错误反斜杠等),这会打印一条很有用的消息,其中包含发现JSON错误的行号和列号。

但是,对于其他类型的JSON错误(包括经典的“在列表中的最后一项上使用逗号”,还有其他内容,如大写true / false),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文件中的错误在哪里?

python json
11个回答
167
投票

我发现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


0
投票

创建文件时。而不是创建包含内容的文件是空的。用。。。来代替:

set nobomb

-3
投票

你可以使用json.dump({}, file) ,它声称比pure-python实现快250倍,因为你有“一些很复杂的JSON文件”,你可能需要多次运行它(解码器失败并报告第一个错误他们只遇到)。


14
投票

你不能让python告诉你JSON不正确的地方。你需要在网上使用像this这样的linter

这将显示您尝试解码的JSON中的错误。


7
投票

您可以尝试在这里找到的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']

3
投票

我有一个类似的问题,这是由于单引号。 JSON标准(http://json.org)仅讨论使用双引号,因此必须是python json库仅支持双引号。


2
投票

对于我这个问题的特定版本,我继续在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))

这样它会在进入try-catch之前打印json文件的内容,这样 - 即使我几乎没有Python知识 - 我能够快速找出为什么我的配置无法读取json文件。 (那是因为我设置了我的文本编辑器来编写UTF-8 BOM ...愚蠢的)

刚提到这一点,因为虽然对OP的具体问题可能不是一个好的答案,但这是确定一个非常压迫的bug的来源的一种相当快速的方法。而且我敢打赌,很多人会偶然发现这篇文章正在为MalformedJsonFileError: No JSON object could be decoded when reading …寻找更详细的解决方案。这可能对他们有所帮助。


1
投票

我遇到了类似的问题,这是我的代码:

    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()我做了它并解决了问题。


1
投票

至于我,我的json文件非常大,当在python中使用常见的json时会出现上述错误。

之后由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 __name__ == '__main__':
    test_parse_json()

0
投票

接受的答案是解决问题最容易的答案。但是,如果由于您的公司政策而不允许您安装simplejson,我建议在下面的解决方案中修复“在列表中的最后一项上使用逗号”的特定问题:

  1. 创建子类“JSONLint Check”以从类“JSONDecoder”继承并覆盖类“JSONDecoder”的init方法,如下所示: qazxsw poi
  1. make_scanner是一个新函数,用于覆盖上述类的'scan_once'方法。以下是代码:
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'函数与新子类一起放入同一个文件中。

0
投票

刚刚遇到同样的问题,在我的情况下,问题与文件开头的 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 (字节顺序标记)有关。

BOM拒绝处理甚至空文件(只是花括号),直到我删除了UTF BOM标记。

我所做的是:

  • 用vim打开我的json文件,
  • 删除字节顺序标记(json.tool
  • 保存存档

这解决了json.tool的问题。希望这可以帮助!

© www.soinside.com 2019 - 2024. All rights reserved.