From 27101dcee351258d08e58aedc0eed6d50fc140aa Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Fri, 14 Aug 2026 23:59:09 +0530 Subject: [PATCH 1/2] Raise UnsupportedFormat for a malformed DBF stream Importing a malformed or truncated DBF let the vendored dbfpy parser raise a variety of low-level errors (struct.error, IndexError, UnicodeDecodeError, KeyError, ...) straight out of load(). Wrap the parse in import_set and raise UnsupportedFormat instead, consistent with detect() which already treats any DBF parsing error as 'not a valid DBF'. --- src/tablib/formats/_dbf.py | 21 +++++++++++++++++---- tests/test_tablib.py | 13 +++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/tablib/formats/_dbf.py b/src/tablib/formats/_dbf.py index 167370373..dd55245d5 100644 --- a/src/tablib/formats/_dbf.py +++ b/src/tablib/formats/_dbf.py @@ -12,6 +12,7 @@ import os import tempfile +from ..exceptions import UnsupportedFormat from .._vendor.dbfpy import dbf, dbfnew from .._vendor.dbfpy import record as dbfrecord @@ -58,10 +59,22 @@ def import_set(cls, dset, in_stream): """Returns a dataset from a DBF stream.""" dset.wipe() - _dbf = dbf.Dbf(in_stream) - dset.headers = _dbf.fieldNames - for record in range(_dbf.recordCount): - row = [_dbf[record][f] for f in _dbf.fieldNames] + # A malformed DBF makes the vendored parser raise a variety of low-level + # errors (struct.error, IndexError, UnicodeDecodeError, ...). Report + # them as UnsupportedFormat, consistent with detect() treating any + # parsing error as "not a valid DBF". + try: + _dbf = dbf.Dbf(in_stream) + headers = _dbf.fieldNames + rows = [[_dbf[record][f] for f in headers] + for record in range(_dbf.recordCount)] + except Exception as e: + raise UnsupportedFormat( + 'Error parsing DBF: the stream is not a valid DBF file.' + ) from e + + dset.headers = headers + for row in rows: dset.append(row) @classmethod diff --git a/tests/test_tablib.py b/tests/test_tablib.py index ca8ac05ec..019fec882 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1910,6 +1910,19 @@ def test_dbf_import_set(self): ) index += 1 + def test_dbf_import_malformed(self): + """A malformed DBF stream raises UnsupportedFormat rather than a raw + struct.error / IndexError from the vendored parser.""" + data.append(self.john) + data.headers = self.headers + good = data.dbf + # truncate the DBF inside its header + truncated = good[:16] + with self.assertRaises(UnsupportedFormat): + tablib.Dataset().load(truncated, format='dbf') + with self.assertRaises(UnsupportedFormat): + tablib.Dataset().load(b'not a dbf file', format='dbf') + def test_dbf_export_set(self): """Test DBF import.""" data.append(self.john) From dd252ded0b2a356189b3a3325eeaf3ec8f0be41b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 18:30:08 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/tablib/formats/_dbf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tablib/formats/_dbf.py b/src/tablib/formats/_dbf.py index dd55245d5..b51ef940f 100644 --- a/src/tablib/formats/_dbf.py +++ b/src/tablib/formats/_dbf.py @@ -12,9 +12,9 @@ import os import tempfile -from ..exceptions import UnsupportedFormat from .._vendor.dbfpy import dbf, dbfnew from .._vendor.dbfpy import record as dbfrecord +from ..exceptions import UnsupportedFormat class DBFFormat: