diff --git a/src/tablib/formats/_csv.py b/src/tablib/formats/_csv.py index e57e1d9e..46299d12 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 old mode 100755 new mode 100644 index ca8ac05e..e1ae306d --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1172,6 +1172,38 @@ def test_csv_formatter_support_kwargs(self): d2 = tablib.import_set(_csv, format="csv", **kwargs) self.assertEqual(3, len(d2.headers)) + def test_csv_import_custom_dialect_delimiter_not_overridden(self): + """A custom dialect's delimiter must not be overridden by the + CSV formatter's own default delimiter (issue #622). + + ``import_set``/``export_stream_set`` used to unconditionally set + ``delimiter=','`` in kwargs before calling ``csv.reader``/ + ``csv.writer``. Since Python's csv module lets explicit fmtparams + override attributes of a passed ``dialect``, this silently + overrode any delimiter configured on a custom dialect back to + the default comma, even though no delimiter was requested by the + caller. + """ + import csv as csv_module + + class ColonDialect(csv_module.excel): + delimiter = ":" + + content = "first_name:last_name\nJohn:Adams\nGeorge:Washington\n" + d = tablib.import_set( + StringIO(content), format="csv", dialect=ColonDialect + ) + self.assertEqual(["first_name", "last_name"], d.headers) + self.assertEqual(("John", "Adams"), d[0]) + self.assertEqual(("George", "Washington"), d[1]) + + data.append(self.john) + data.append(self.george) + data.headers = self.headers + exported = data.export("csv", dialect=ColonDialect) + self.assertIn(":", exported) + self.assertNotIn(",", exported.split("\n")[0]) + class TSVTests(BaseTestCase): def test_tsv_import_set(self):