diff --git a/sqlite_utils/utils.py b/sqlite_utils/utils.py index 91fd24ddd..0e631ddc2 100644 --- a/sqlite_utils/utils.py +++ b/sqlite_utils/utils.py @@ -9,6 +9,7 @@ import json import os import sys +from codecs import BOM_UTF8 from collections.abc import Callable, Generator, Iterable, Iterator from typing import ( TYPE_CHECKING, @@ -382,7 +383,7 @@ class Format(enum.Enum): if not first_bytes: buffered.close() return (), Format.CSV - if first_bytes.startswith((b"[", b"{")): + if first_bytes.removeprefix(BOM_UTF8).lstrip().startswith((b"[", b"{")): # JSON is read eagerly, so the detection wrapper can close now, # including when parsing raises an error. # TODO: Detect newline-JSON diff --git a/tests/test_rows_from_file.py b/tests/test_rows_from_file.py index a8e7f9d76..4dc933b8c 100644 --- a/tests/test_rows_from_file.py +++ b/tests/test_rows_from_file.py @@ -1,5 +1,6 @@ import io import json +from codecs import BOM_UTF8 from io import BytesIO, StringIO import pytest @@ -13,6 +14,9 @@ (b"id,name\n1,Cleo", Format.CSV), (b"id\tname\n1\tCleo", Format.TSV), (b'[{"id": "1", "name": "Cleo"}]', Format.JSON), + (BOM_UTF8 + b'[{"id": "1", "name": "Cleo"}]', Format.JSON), + (BOM_UTF8 + b'\n{"id": "1", "name": "Cleo"}', Format.JSON), + (BOM_UTF8 + b"id,name\n1,Cleo", Format.CSV), ), ) def test_rows_from_file_detect_format(input, expected_format):