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


128

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错误(包括经典的“在列表中的最后一项上使用逗号”,以及其他诸如大写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文件中的错误在哪里?


您可以转储文件摘录吗?
Ketouem

我现在不尝试在特定文件中查找错误;我正在尝试修改程序,以便它将在以后读取的任何文件中突出显示该错误。
OJW

2
没有直接关系,但是您可以json.load(f)代替json.loads(f.read())
Martin Samson 2013年

@OJW此行为针对的是什么版本的python?
jxramos

Python 3.8.1现在给出错误位置“期望值:第1行第21列(字符20)”
OJW

Answers:


173

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


18
未来的Python版本将包括这些改进。这是下面的同一个项目。
马丁·彼得斯


1
@ user2016290直接编辑核心/软件包文件是一个坏主意。Python很容易打补丁,因此最好用代码来实现。
Rebs

2
@jxramos:从追溯可以明显看出,OP使用了Python 2.7。在ideone.com(Python 3.7.3)上进行的快速测试表明,stdlib json库已更新,并提供了新的错误消息格式。我现在没有时间跟踪确切的发布。
马丁·彼得斯

1
@jxramos找到了它,Python 3.5更新了例外:bugs.python.org/issue19361(通过docs.python.org/3/whatsnew/3.5.html#improved-modules)。
马丁·彼得斯

15

您将无法获得python来告诉您JSON不正确的地方。您将需要在这样的地方在线使用棉绒

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


2
是否有离线工具可以对机密JSON文件执行此操作?
OJW

@OJW不是我所知道的,但是应该可以解决您遇到的问题,或者至少可以让您修复损坏的json。
myusuf3

12
我的JSON文件很好-我正在尝试使程序打印有用的错误消息,任何人都可以理解。告诉他们“在第13行的第32栏中删除该逗号”是很好的。告诉他们“您的文件中某处存在错误,请将其上传到互联网上,人们会为您提供帮助”是不好的。
OJW

7

您可以尝试在以下位置找到rson库:http : //code.google.com/p/rson/。我还在PYPI上:https ://pypi.python.org/pypi/rson/0.9,所以您可以使用easy_install或pip来获取它。

对于tom给出的示例:

>>> 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']

4

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


3

对于这个问题的特定版本,我继续搜索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 …。这样可能对他们有帮助。


您应该将上下文管理器用于文件I / O(with open(fn) as f),它会为您处理异常中的关闭文件。en.wikibooks.org/wiki/Python_Programming/...
个篮板

1
+1。如果您可以显示一个示例,然后将其猴子修补到标准行为上,那将非常整齐
Craig Brett

抱歉,找出该问题后,我再也没有碰过任何Python代码。也许有人可以帮忙吗?
WoodrowShigeru

3

对我来说,我的json文件很大,json在python中使用common 时会出现上述错误。

安装后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()

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() 做到这一点并解决了问题。


也为我工作,不知道为什么以前没有这个问题。
pceccon'6

您应该将上下文管理器用于文件I / O(with open(fn) as f),它会为您处理异常中的关闭文件。en.wikibooks.org/wiki/Python_Programming/...
个篮板

0

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

  1. 创建一个子类“ JSONLintCheck”以从类“ JSONDecoder”继承,并覆盖类“ JSONDecoder”的init方法,如下所示:

    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

只是遇到了同样的问题,在我的情况下,问题与BOM文件开头的(字节顺序标记)有关。

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

我所做的是:

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

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


-1

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

json.dump({}, file)

-3

您可以使用cjson,它声称比纯python实现快250倍,因为您有“某个较长且复杂的JSON文件”,并且可能需要运行几次(解码器失败并报告第一个错误)仅遇到)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.