diff --git a/rows/plugins/plugin_csv.py b/rows/plugins/plugin_csv.py index a06b1571..0e41cdde 100644 --- a/rows/plugins/plugin_csv.py +++ b/rows/plugins/plugin_csv.py @@ -56,9 +56,20 @@ def import_from_csv(filename_or_fobj, encoding='utf-8', dialect=None, `open(filename, mode='rb')`. ''' + error_msg = '''Error importing from CSV. Details: + Filename: {filename} + File object: {fobj} + Dialect (guessed?): {dialect} ({guessed}) + Encoding: {encoding} + Sample size: {sample_size} bytes + Reason: {exc} + ''' + filename, fobj = get_filename_and_fobj(filename_or_fobj, mode='rb') + guessed = False if dialect is None: + guessed = True cursor = fobj.tell() dialect = discover_dialect(fobj.read(sample_size), encoding) fobj.seek(cursor) @@ -68,7 +79,26 @@ def import_from_csv(filename_or_fobj, encoding='utf-8', dialect=None, meta = {'imported_from': 'csv', 'filename': filename, 'encoding': encoding,} - return create_table(reader, meta=meta, *args, **kwargs) + try: + try: + table = create_table(reader, meta=meta, *args, **kwargs) + except ValueError as e: + if guessed: + dialect = unicodecsv.excel + fobj.seek(cursor) + reader = unicodecsv.reader(fobj, encoding=encoding, + dialect=dialect) + table = create_table(reader, meta=meta, *args, **kwargs) + else: + raise + except Exception as e: + name = 'Excel' if dialect is unicodecsv.excel else dialect._name + error = error_msg.format(filename=filename, fobj=fobj, + dialect=name, guessed=guessed, encoding=encoding, + sample_size=sample_size, exc=e) + raise unicodecsv.Error(error) from e + + return table def export_to_csv(table, filename_or_fobj=None, encoding='utf-8', diff --git a/tests/tests_plugin_csv.py b/tests/tests_plugin_csv.py index 9430f3be..4bb7a112 100644 --- a/tests/tests_plugin_csv.py +++ b/tests/tests_plugin_csv.py @@ -250,3 +250,25 @@ def test_export_to_csv_accepts_dialect(self): result_1 = rows.export_to_csv(utils.table, dialect=csv.excel_tab) result_2 = rows.export_to_csv(utils.table, dialect=csv.excel) self.assertEqual(result_1.replace(b'\t', b','), result_2) + + def test_issue_218_revert_guess(self): + + err = b"""problematic_text,cool_number\n,42\n"Problematic text with\ + commas, ""quotes"" and a cool number: 4,2", 84""" + + csv_input = BytesIO(err) + table = rows.import_from_csv(csv_input, dialect='excel') + as_list = list(table) + csv_input = BytesIO(err) + table = rows.import_from_csv(csv_input) + self.assertEqual(as_list, list(table)) + + def test_issue_218_better_msg(self): + err = b"""problematic_text,cool_number\n,42\n"Problematic text with\ + commas, ""quotes"" and a cool number: 4,2", 84""" + + tricky_table = err * 1000 + bytes(range(256)) + self.assertRaises(csv.Error, rows.import_from_csv, BytesIO(tricky_table)) + + with self.assertRaisesRegex(csv.Error, 'Details'): + tricked = rows.import_from_csv(BytesIO(tricky_table), encoding='utf-8')