Better error message if rows_from_file called with StringIO, closes #520

Refs #448
This commit is contained in:
Simon Willison 2023-05-08 15:08:02 -07:00
commit dab23884ae
2 changed files with 16 additions and 2 deletions

View file

@ -303,7 +303,13 @@ def rows_from_file(
elif format is None:
# Detect the format, then call this recursively
buffered = io.BufferedReader(cast(io.RawIOBase, fp), buffer_size=4096)
first_bytes = buffered.peek(2048).strip()
try:
first_bytes = buffered.peek(2048).strip()
except AttributeError:
# Likely the user passed a TextIO when this needs a BytesIO
raise TypeError(
"rows_from_file() requires a file-like object that supports peek(), such as io.BytesIO"
)
if first_bytes.startswith(b"[") or first_bytes.startswith(b"{"):
# TODO: Detect newline-JSON
return rows_from_file(buffered, format=Format.JSON)

View file

@ -1,5 +1,5 @@
from sqlite_utils.utils import rows_from_file, Format, RowError
from io import BytesIO
from io import BytesIO, StringIO
import pytest
@ -44,3 +44,11 @@ def test_rows_from_file_extra_fields_strategies(ignore_extras, extras_key, expec
# We did not expect an error
raise
assert list_rows == expected
def test_rows_from_file_error_on_string_io():
with pytest.raises(TypeError) as ex:
rows_from_file(StringIO("id,name\r\n1,Cleo"))
assert ex.value.args == (
"rows_from_file() requires a file-like object that supports peek(), such as io.BytesIO",
)