From 15afe874efaa72eac81af32cf13fba2ff0c9af17 Mon Sep 17 00:00:00 2001 From: Qrytics Date: Tue, 10 Nov 2026 04:13:15 -0600 Subject: [PATCH] Read CLI JSON inputs as utf-8-sig so BOM files do not crash --- jsonpatch_cli.py | 8 ++++---- tests.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/jsonpatch_cli.py b/jsonpatch_cli.py index e3697e3..f0d5bf2 100644 --- a/jsonpatch_cli.py +++ b/jsonpatch_cli.py @@ -13,8 +13,8 @@ jsondiff_parser = argparse.ArgumentParser( prog='jsondiff', description='Diff two JSON files') -jsondiff_parser.add_argument('FILE1', type=argparse.FileType('r', encoding='utf-8')) -jsondiff_parser.add_argument('FILE2', type=argparse.FileType('r', encoding='utf-8')) +jsondiff_parser.add_argument('FILE1', type=argparse.FileType('r', encoding='utf-8-sig')) +jsondiff_parser.add_argument('FILE2', type=argparse.FileType('r', encoding='utf-8-sig')) jsondiff_parser.add_argument('--indent', type=int, default=None, help='Indent output by n spaces') jsondiff_parser.add_argument('-u', '--preserve-unicode', action='store_true', @@ -51,9 +51,9 @@ def diff_files(): jsonpatch_parser = argparse.ArgumentParser( prog='jsonpatch', description='Apply a JSON patch on a JSON file') -jsonpatch_parser.add_argument('ORIGINAL', type=argparse.FileType('r', encoding='utf-8'), +jsonpatch_parser.add_argument('ORIGINAL', type=argparse.FileType('r', encoding='utf-8-sig'), help='Original file') -jsonpatch_parser.add_argument('PATCH', type=argparse.FileType('r', encoding='utf-8'), +jsonpatch_parser.add_argument('PATCH', type=argparse.FileType('r', encoding='utf-8-sig'), nargs='?', default=sys.stdin, help='Patch file (read from stdin if omitted)') jsonpatch_parser.add_argument('--indent', type=int, default=None, diff --git a/tests.py b/tests.py index e124a96..0149225 100644 --- a/tests.py +++ b/tests.py @@ -3148,6 +3148,29 @@ def test_jsondiff_utf8_files_without_utf8_mode(self): self.assertEqual(jsonpatch.apply_patch(self.read(src), patch), self.read(dst)) + def test_jsondiff_utf8_bom_files(self): + for path, value in (('a.json', {'a': 1}), ('b.json', {'a': 2})): + with open(os.path.join(self.dir, path), 'w', encoding='utf-8-sig') as f: + json.dump(value, f) + src = os.path.join(self.dir, 'a.json') + dst = os.path.join(self.dir, 'b.json') + res = self.run_script('jsondiff', src, dst) + # like diff, it exits with 1 if the files differ + self.assertEqual(res.returncode, 1, res.stderr) + patch = json.loads(res.stdout) + self.assertEqual(jsonpatch.apply_patch({'a': 1}, patch), {'a': 2}) + + def test_jsonpatch_utf8_bom_files(self): + doc = os.path.join(self.dir, 'doc.json') + patch = os.path.join(self.dir, 'patch.json') + with open(doc, 'w', encoding='utf-8-sig') as f: + json.dump({'a': 1}, f) + with open(patch, 'w', encoding='utf-8-sig') as f: + json.dump([{'op': 'replace', 'path': '/a', 'value': 2}], f) + res = self.run_script('jsonpatch', doc, patch) + self.assertEqual(res.returncode, 0, res.stderr) + self.assertEqual(json.loads(res.stdout), {'a': 2}) + def test_jsonpatch(self): doc = self.write('doc.json', {'a': [1, 2], 'b': 0}) patch = self.write('patch.json', [{'op': 'add', 'path': '/a/-', 'value': 3},