Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cf58fb5

Browse files
Issue #18829: csv.Dialect() now checks type for delimiter, escapechar and
quotechar fields. Original patch by Vajrasky Kok.
2 parents 5272fa9 + cac23a5 commit cf58fb5

3 files changed

Lines changed: 50 additions & 6 deletions

File tree

Lib/test/test_csv.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,7 @@ class mydialect(csv.Dialect):
756756
lineterminator = '\r\n'
757757
quoting = csv.QUOTE_NONE
758758
d = mydialect()
759+
self.assertEqual(d.quoting, csv.QUOTE_NONE)
759760

760761
mydialect.quoting = None
761762
self.assertRaises(csv.Error, mydialect)
@@ -764,12 +765,21 @@ class mydialect(csv.Dialect):
764765
mydialect.quoting = csv.QUOTE_ALL
765766
mydialect.quotechar = '"'
766767
d = mydialect()
768+
self.assertEqual(d.quoting, csv.QUOTE_ALL)
769+
self.assertEqual(d.quotechar, '"')
770+
self.assertTrue(d.doublequote)
767771

768772
mydialect.quotechar = "''"
769-
self.assertRaises(csv.Error, mydialect)
773+
with self.assertRaises(csv.Error) as cm:
774+
mydialect()
775+
self.assertEqual(str(cm.exception),
776+
'"quotechar" must be an 1-character string')
770777

771778
mydialect.quotechar = 4
772-
self.assertRaises(csv.Error, mydialect)
779+
with self.assertRaises(csv.Error) as cm:
780+
mydialect()
781+
self.assertEqual(str(cm.exception),
782+
'"quotechar" must be string, not int')
773783

774784
def test_delimiter(self):
775785
class mydialect(csv.Dialect):
@@ -780,12 +790,31 @@ class mydialect(csv.Dialect):
780790
lineterminator = '\r\n'
781791
quoting = csv.QUOTE_NONE
782792
d = mydialect()
793+
self.assertEqual(d.delimiter, ";")
783794

784795
mydialect.delimiter = ":::"
785-
self.assertRaises(csv.Error, mydialect)
796+
with self.assertRaises(csv.Error) as cm:
797+
mydialect()
798+
self.assertEqual(str(cm.exception),
799+
'"delimiter" must be an 1-character string')
800+
801+
mydialect.delimiter = ""
802+
with self.assertRaises(csv.Error) as cm:
803+
mydialect()
804+
self.assertEqual(str(cm.exception),
805+
'"delimiter" must be an 1-character string')
806+
807+
mydialect.delimiter = b","
808+
with self.assertRaises(csv.Error) as cm:
809+
mydialect()
810+
self.assertEqual(str(cm.exception),
811+
'"delimiter" must be string, not bytes')
786812

787813
mydialect.delimiter = 4
788-
self.assertRaises(csv.Error, mydialect)
814+
with self.assertRaises(csv.Error) as cm:
815+
mydialect()
816+
self.assertEqual(str(cm.exception),
817+
'"delimiter" must be string, not int')
789818

790819
def test_lineterminator(self):
791820
class mydialect(csv.Dialect):
@@ -796,12 +825,17 @@ class mydialect(csv.Dialect):
796825
lineterminator = '\r\n'
797826
quoting = csv.QUOTE_NONE
798827
d = mydialect()
828+
self.assertEqual(d.lineterminator, '\r\n')
799829

800830
mydialect.lineterminator = ":::"
801831
d = mydialect()
832+
self.assertEqual(d.lineterminator, ":::")
802833

803834
mydialect.lineterminator = 4
804-
self.assertRaises(csv.Error, mydialect)
835+
with self.assertRaises(csv.Error) as cm:
836+
mydialect()
837+
self.assertEqual(str(cm.exception),
838+
'"lineterminator" must be a string')
805839

806840

807841
class TestSniffer(unittest.TestCase):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ Core and Builtins
4444
Library
4545
-------
4646

47+
- Issue #18829: csv.Dialect() now checks type for delimiter, escapechar and
48+
quotechar fields. Original patch by Vajrasky Kok.
49+
4750
- Issue #19855: uuid.getnode() on Unix now looks on the PATH for the
4851
executables used to find the mac address, with /sbin and /usr/sbin as
4952
fallbacks.

Modules/_csv.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
239239
*target = '\0';
240240
if (src != Py_None) {
241241
Py_ssize_t len;
242+
if (!PyUnicode_Check(src)) {
243+
PyErr_Format(PyExc_TypeError,
244+
"\"%s\" must be string, not %.200s", name,
245+
src->ob_type->tp_name);
246+
return -1;
247+
}
242248
len = PyUnicode_GetLength(src);
243249
if (len > 1) {
244250
PyErr_Format(PyExc_TypeError,
@@ -425,7 +431,8 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
425431
if (dialect_check_quoting(self->quoting))
426432
goto err;
427433
if (self->delimiter == 0) {
428-
PyErr_SetString(PyExc_TypeError, "delimiter must be set");
434+
PyErr_SetString(PyExc_TypeError,
435+
"\"delimiter\" must be an 1-character string");
429436
goto err;
430437
}
431438
if (quotechar == Py_None && quoting == NULL)

0 commit comments

Comments
 (0)