PythonでJSONオブジェクトのフィールドを順不同で比較する
·
Konboi
はじめに
担当しているプロダクトではPython製のコマンドラインツールを提供しています。
サーバーへのリクエストのフォーマット(JSON)が正しい形式になっているかをテストしています。
ただテストのチェック用のデータのJSONのフィールドの順番も全く同じにするのは手間がかかります。ある程度簡単にデータを作成したいです。
そこでフィールドの順番が異なっていてもデータの中身が同じであればOKとするテスト用のユーティリーメソッドとしてassert_json_orderless_equal(a, b)
を用意しています。
このメソッドの中身はこちらで示されているものをほぼ使っていました。
def ordered(obj):
if isinstance(obj, dict):
return sorted((k, ordered(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
ただし、この処理だとdict型のfieldの値がNone
とそれ以外の場合で比較しようとするときにうまく比較できない事象に遭遇しました。
e.g.)
ordered({"array": [
{"name": "a", "data": {"value": 1}},
{"data": None, "name": "b"},
{"name": "c", "data": {"value": 2}}
], "b": 2},
{"b": 2, "array": [
{"data": None, "name": "b"},
{"data": {"value": 2}, "name": "c"},
{"data": {"value": 1}, "name": "a"},
]})
Noneも考慮した実装
そこでsortedの第二引数であるkeyにNoneの扱いをどうするか明示的に指定することで解決しました
def ordered(obj):
if isinstance(obj, dict):
return sorted([(k, ordered(v)) for k, v in obj.items()], key=lambda item: (item[1] is None, item))
if isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
同様の問題で困っている方がいればご活用ください