diff -r 98f82b124c7d Lib/csv.py --- a/Lib/csv.py Sat Sep 07 10:36:04 2013 +0200 +++ b/Lib/csv.py Sat Sep 07 18:58:57 2013 +0800 @@ -46,7 +46,7 @@ def _validate(self): try: _Dialect(self) - except TypeError as e: + except (TypeError, ValueError) as e: # We do this for compatibility with py2.3 raise Error(str(e)) diff -r 98f82b124c7d Lib/test/test_csv.py --- a/Lib/test/test_csv.py Sat Sep 07 10:36:04 2013 +0200 +++ b/Lib/test/test_csv.py Sat Sep 07 18:58:57 2013 +0800 @@ -22,7 +22,7 @@ self.assertRaises(TypeError, ctor, None) self.assertRaises(TypeError, ctor, arg, bad_attr = 0) self.assertRaises(TypeError, ctor, arg, delimiter = 0) - self.assertRaises(TypeError, ctor, arg, delimiter = 'XX') + self.assertRaises(ValueError, ctor, arg, delimiter = 'XX') self.assertRaises(csv.Error, ctor, arg, 'foo') self.assertRaises(TypeError, ctor, arg, delimiter=None) self.assertRaises(TypeError, ctor, arg, delimiter=1) @@ -744,6 +744,7 @@ lineterminator = '\r\n' quoting = csv.QUOTE_NONE d = mydialect() + self.assertEqual(d.quoting, csv.QUOTE_NONE) mydialect.quoting = None self.assertRaises(csv.Error, mydialect) @@ -752,12 +753,21 @@ 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): @@ -768,12 +778,25 @@ 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 = 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): @@ -784,12 +807,17 @@ 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 -r 98f82b124c7d Modules/_csv.c --- a/Modules/_csv.c Sat Sep 07 10:36:04 2013 +0200 +++ b/Modules/_csv.c Sat Sep 07 18:58:57 2013 +0800 @@ -239,11 +239,16 @@ *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, - "\"%s\" must be an 1-character string", - name); + PyErr_Format(PyExc_ValueError, + "\"%s\" must be an 1-character string", name); return -1; } /* PyUnicode_READY() is called in PyUnicode_GetLength() */