「JSONオブジェクトをデコードできませんでした」よりも優れたエラーメッセージを表示する


128

いくつかの長く複雑な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について、JSONファイルのどこにエラーがあるかをPythonにどのように通知しますか?


ファイルの抜粋をダンプできますか?
Ketouem 2013

現在、特定のファイルでエラーを見つけようとはしていません。プログラムを変更して、それが読み取る将来のファイルのエラーを強調表示するようにしています。
OJW 2013

2
直接関係はありませんが、json.load(f)代わりに行うことができますjson.loads(f.read())
Martin Samson

@OJWこの動作はどのバージョンのpythonでしたか?
jxramos

Python 3.8.1でエラー位置「期待値:行1列21(文字20)」
OJW

回答:


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の将来のバージョンには、これらの改善が含まれる予定です。下のプロジェクトと同じです。
Martijn Pieters


1
@ user2016290コア/パッケージファイルを直接編集することは悪い考えです。Pythonは簡単にパッチを修正できるので、コードで行う方がよいでしょう。
Rebs

2
@jxramos:トレースバックから明らかなように、OPはPython 2.7を使用しました。ideone.com(Python 3.7.3)の簡単なテストでは、stdlib jsonライブラリが更新され、新しいエラーメッセージ形式が示されています。現在、正確なリリースを追跡する時間はありません。
Martijn Pieters

1
@jxramosがそれを見つけ、Python 3.5が例外を更新しました:bugs.python.org/issue19361docs.python.org/3/whatsnew/3.5.html#improved-modules経由)。
Martijn Pieters

15

JSONが正しくない場所をPythonに通知することはできません。このような場所でオンラインでリンターを使用する必要があります

これにより、デコードしようとしているJSONのエラーが表示されます。


2
機密のJSONファイルに対してこれを行うことができるオフラインツールはありますか?
OJW 2013

@OJW私が知っているわけではありませんが、あなたが抱えている問題を解決するか、少なくともあなたの壊れたjsonを修正させます。
myusuf3 2013

12
私のJSONファイルは問題ありません-私は私のプログラムが誰にも理解できる有用なエラーメッセージを出力するようにしています。「コンマを13行32列で取り除く」と伝えるのは良いことです。「ファイルのどこかにエラーがあります。他の人が助けてくれるインターネットにアップロードしてください」と伝えるのは悪いことです。
OJW 2013

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の特定の問題に対する適切な回答ではないかもしれませんが、非常に抑圧的なバグの原因を特定するためのかなり迅速な方法であるためです。そして、私はこの記事に出くわして、より冗長な解決策を探している人がいると思いMalformedJsonFileError: No JSON object could be decoded when reading …ます。だから彼らを助けるかもしれない。


ファイルI / O(with open(fn) as f)には、コンテキストマネージャーを使用する必要があります。これは、例外でファイルのクローズを処理します。en.wikibooks.org/wiki/Python_Programming/...
Rebs

1
+1。それを標準的な動作にサルパッチングする例を示すことができれば、それはかなりきちんとしているでしょう
Craig Brett

申し訳ありませんが、その問題が判明した後は、Pythonコードに触れたことはありません。多分誰かが助けることができますか?
WoodrowShigeru 2017

3

私に関しては、私のjsonファイルは非常に大きく、jsonPythonで一般的に使用すると上記のエラーが発生します。

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 2016年

ファイルI / O(with open(fn) as f)には、コンテキストマネージャーを使用する必要があります。これは、例外でファイルのクローズを処理します。en.wikibooks.org/wiki/Python_Programming/...
Rebs

0

受け入れられた答えは、問題を修正する最も簡単なものです。ただし、会社のポリシーによりsimplejsonのインストールが許可されていない場合は、「リストの最後の項目でカンマを使用する」という特定の問題を解決するための解決策を以下に示します。

  1. 以下のように、クラス「JSONDecoder」から継承する子クラス「JSONLintCheck」を作成し、クラス「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マークを削除するまで、空のファイル(中かっこのみ)の処理も拒否されます。

私がしたことは:

  • 私のjsonファイルをvimで開いた、
  • バイトオーダーマーク(set nobomb)を削除
  • ファイルを保存

これにより、json.toolの問題が解決しました。お役に立てれば!


-1

ファイルが作成されたとき。コンテンツを含むファイルを作成する代わりに、空です。と置換する:

json.dump({}, file)

-3

「いくつかの長く複雑なJSONファイル」があり、おそらくそれを数回実行する必要がある場合(純粋にPythonの実装よりも最大250倍高速であると主張するcjsonを使用できます(デコーダーは失敗し、最初のエラーを報告します)遭遇のみ)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.