From aa1c6f09560b7a90ffbe5d3aa7bb8c9409042a2f Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Fri, 24 Jul 2026 18:48:54 -0700 Subject: [PATCH] Don't let the default delimiter override a caller-supplied dialect CSVFormat.import_set and export_stream_set unconditionally applied DEFAULT_DELIMITER via kwargs.setdefault. A caller passing dialect= but no explicit delimiter= therefore got the default ',' injected alongside the dialect, and csv gives the standalone delimiter precedence, so the dialect's delimiter was silently ignored. Only apply the default when no dialect was supplied. Adds a regression test covering both the import and export paths with a sniffed ':' dialect. Fixes #622 --- src/tablib/formats/_csv.py | 6 ++++-- tests/test_tablib.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/tablib/formats/_csv.py b/src/tablib/formats/_csv.py index e57e1d9ed..46299d127 100644 --- a/src/tablib/formats/_csv.py +++ b/src/tablib/formats/_csv.py @@ -18,7 +18,8 @@ def export_stream_set(cls, dataset, **kwargs): """Returns CSV representation of Dataset as file-like.""" stream = StringIO() - kwargs.setdefault('delimiter', cls.DEFAULT_DELIMITER) + if 'dialect' not in kwargs: + kwargs.setdefault('delimiter', cls.DEFAULT_DELIMITER) _csv = csv.writer(stream, **kwargs) @@ -40,7 +41,8 @@ def import_set(cls, dset, in_stream, headers=True, skip_lines=0, **kwargs): dset.wipe() - kwargs.setdefault('delimiter', cls.DEFAULT_DELIMITER) + if 'dialect' not in kwargs: + kwargs.setdefault('delimiter', cls.DEFAULT_DELIMITER) rows = csv.reader(in_stream, **kwargs) for i, row in enumerate(rows): diff --git a/tests/test_tablib.py b/tests/test_tablib.py index 32f0e4b15..307e4c1d4 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1,6 +1,7 @@ #!/usr/bin/env python """Tests for Tablib.""" +import csv import datetime as dt import doctest import json @@ -1157,6 +1158,19 @@ def test_csv_formatter_support_kwargs(self): d2 = tablib.import_set(_csv, format="csv", **kwargs) self.assertEqual(3, len(d2.headers)) + def test_csv_dialect_is_not_overridden_by_default_delimiter(self): + """A caller-supplied dialect must win over DEFAULT_DELIMITER.""" + text = 'test:test2\nvalue1:value2\n' + dialect = csv.Sniffer().sniff(text.splitlines()[0]) + self.assertEqual(':', dialect.delimiter) + + imported = tablib.Dataset().load(text, format='csv', dialect=dialect) + self.assertEqual(['test', 'test2'], imported.headers) + self.assertEqual(('value1', 'value2'), imported[0]) + + exported = imported.export('csv', dialect=dialect) + self.assertEqual('test:test2\r\nvalue1:value2\r\n', exported) + class TSVTests(BaseTestCase): def test_tsv_import_set(self):