summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2013-12-19 14:28:04 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2013-12-19 14:28:04 (GMT)
commitcf58fb5e2947ebe6ac1e06b7f8fbe9a417b7430f (patch)
treedd05fec470e5b75a4a79c6e5fb89e45048c66617
parent5272fa9c5707b3cdcd6f49fdaf595b21bec6b2bd (diff)
parentcac23a50ee2979b8c2e3472e6b13efb1a8bd4f78 (diff)
downloadcpython-cf58fb5e2947ebe6ac1e06b7f8fbe9a417b7430f.zip
cpython-cf58fb5e2947ebe6ac1e06b7f8fbe9a417b7430f.tar.gz
cpython-cf58fb5e2947ebe6ac1e06b7f8fbe9a417b7430f.tar.bz2
Issue #18829: csv.Dialect() now checks type for delimiter, escapechar and
quotechar fields. Original patch by Vajrasky Kok.
-rw-r--r--Lib/test/test_csv.py44
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_csv.c9
3 files changed, 50 insertions, 6 deletions
diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 01fba21..cbde781 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -756,6 +756,7 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n'
quoting = csv.QUOTE_NONE
d = mydialect()
+ self.assertEqual(d.quoting, csv.QUOTE_NONE)
mydialect.quoting = None
self.assertRaises(csv.Error, mydialect)
@@ -764,12 +765,21 @@ class TestDialectValidity(unittest.TestCase):
mydialect.quoting = csv.QUOTE_ALL
mydialect.quotechar = '"'
d = mydialect()
+ self.assertEqual(d.quoting, csv.QUOTE_ALL)
+ self.assertEqual(d.quotechar, '"')
+ self.assertTrue(d.doublequote)
mydialect.quotechar = "''"
- self.assertRaises(csv.Error, mydialect)
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"quotechar" must be an 1-character string')
mydialect.quotechar = 4
- self.assertRaises(csv.Error, mydialect)
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"quotechar" must be string, not int')
def test_delimiter(self):
class mydialect(csv.Dialect):
@@ -780,12 +790,31 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n'
quoting = csv.QUOTE_NONE
d = mydialect()
+ self.assertEqual(d.delimiter, ";")
mydialect.delimiter = ":::"
- self.assertRaises(csv.Error, mydialect)
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"delimiter" must be an 1-character string')
+
+ mydialect.delimiter = ""
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"delimiter" must be an 1-character string')
+
+ mydialect.delimiter = b","
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"delimiter" must be string, not bytes')
mydialect.delimiter = 4
- self.assertRaises(csv.Error, mydialect)
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"delimiter" must be string, not int')
def test_lineterminator(self):
class mydialect(csv.Dialect):
@@ -796,12 +825,17 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n'
quoting = csv.QUOTE_NONE
d = mydialect()
+ self.assertEqual(d.lineterminator, '\r\n')
mydialect.lineterminator = ":::"
d = mydialect()
+ self.assertEqual(d.lineterminator, ":::")
mydialect.lineterminator = 4
- self.assertRaises(csv.Error, mydialect)
+ with self.assertRaises(csv.Error) as cm:
+ mydialect()
+ self.assertEqual(str(cm.exception),
+ '"lineterminator" must be a string')
class TestSniffer(unittest.TestCase):
diff --git a/Misc/NEWS b/Misc/NEWS
index 27a8970..ad41540 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,9 @@ Core and Builtins
Library
-------
+- Issue #18829: csv.Dialect() now checks type for delimiter, escapechar and
+ quotechar fields. Original patch by Vajrasky Kok.
+
- Issue #19855: uuid.getnode() on Unix now looks on the PATH for the
executables used to find the mac address, with /sbin and /usr/sbin as
fallbacks.
diff --git a/Modules/_csv.c b/Modules/_csv.c
index 183a9a5..c8767d1 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -239,6 +239,12 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
*target = '\0';
if (src != Py_None) {
Py_ssize_t len;
+ if (!PyUnicode_Check(src)) {
+ PyErr_Format(PyExc_TypeError,
+ "\"%s\" must be string, not %.200s", name,
+ src->ob_type->tp_name);
+ return -1;
+ }
len = PyUnicode_GetLength(src);
if (len > 1) {
PyErr_Format(PyExc_TypeError,
@@ -425,7 +431,8 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (dialect_check_quoting(self->quoting))
goto err;
if (self->delimiter == 0) {
- PyErr_SetString(PyExc_TypeError, "delimiter must be set");
+ PyErr_SetString(PyExc_TypeError,
+ "\"delimiter\" must be an 1-character string");
goto err;
}
if (quotechar == Py_None && quoting == NULL)