Commit 0c221bee authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #18829: csv.Dialect() now checks type for delimiter, escapechar and

quotechar fields.  Original patch by Vajrasky Kok.
parent d46a31fc
...@@ -870,6 +870,7 @@ class TestDialectValidity(unittest.TestCase): ...@@ -870,6 +870,7 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n' lineterminator = '\r\n'
quoting = csv.QUOTE_NONE quoting = csv.QUOTE_NONE
d = mydialect() d = mydialect()
self.assertEqual(d.quoting, csv.QUOTE_NONE)
mydialect.quoting = None mydialect.quoting = None
self.assertRaises(csv.Error, mydialect) self.assertRaises(csv.Error, mydialect)
...@@ -878,12 +879,21 @@ class TestDialectValidity(unittest.TestCase): ...@@ -878,12 +879,21 @@ class TestDialectValidity(unittest.TestCase):
mydialect.quoting = csv.QUOTE_ALL mydialect.quoting = csv.QUOTE_ALL
mydialect.quotechar = '"' mydialect.quotechar = '"'
d = mydialect() d = mydialect()
self.assertEqual(d.quoting, csv.QUOTE_ALL)
self.assertEqual(d.quotechar, '"')
self.assertTrue(d.doublequote)
mydialect.quotechar = "''" 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 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): def test_delimiter(self):
class mydialect(csv.Dialect): class mydialect(csv.Dialect):
...@@ -894,12 +904,31 @@ class TestDialectValidity(unittest.TestCase): ...@@ -894,12 +904,31 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n' lineterminator = '\r\n'
quoting = csv.QUOTE_NONE quoting = csv.QUOTE_NONE
d = mydialect() d = mydialect()
self.assertEqual(d.delimiter, ";")
mydialect.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 = u","
with self.assertRaises(csv.Error) as cm:
mydialect()
self.assertEqual(str(cm.exception),
'"delimiter" must be string, not unicode')
mydialect.delimiter = 4 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): def test_lineterminator(self):
class mydialect(csv.Dialect): class mydialect(csv.Dialect):
...@@ -910,12 +939,17 @@ class TestDialectValidity(unittest.TestCase): ...@@ -910,12 +939,17 @@ class TestDialectValidity(unittest.TestCase):
lineterminator = '\r\n' lineterminator = '\r\n'
quoting = csv.QUOTE_NONE quoting = csv.QUOTE_NONE
d = mydialect() d = mydialect()
self.assertEqual(d.lineterminator, '\r\n')
mydialect.lineterminator = ":::" mydialect.lineterminator = ":::"
d = mydialect() d = mydialect()
self.assertEqual(d.lineterminator, ":::")
mydialect.lineterminator = 4 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): class TestSniffer(unittest.TestCase):
......
...@@ -27,6 +27,9 @@ Core and Builtins ...@@ -27,6 +27,9 @@ Core and Builtins
Library 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 - 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 executables used to find the mac address, with /sbin and /usr/sbin as
fallbacks. fallbacks.
......
...@@ -239,19 +239,24 @@ _set_char(const char *name, char *target, PyObject *src, char dflt) ...@@ -239,19 +239,24 @@ _set_char(const char *name, char *target, PyObject *src, char dflt)
if (src == NULL) if (src == NULL)
*target = dflt; *target = dflt;
else { else {
if (src == Py_None || PyString_Size(src) == 0) *target = '\0';
*target = '\0'; if (src != Py_None) {
else if (!PyString_Check(src) || PyString_Size(src) != 1) { Py_ssize_t len;
PyErr_Format(PyExc_TypeError, if (!PyString_Check(src)) {
"\"%s\" must be an 1-character string", PyErr_Format(PyExc_TypeError,
name); "\"%s\" must be string, not %.200s", name,
return -1; src->ob_type->tp_name);
}
else {
char *s = PyString_AsString(src);
if (s == NULL)
return -1; return -1;
*target = s[0]; }
len = PyString_GET_SIZE(src);
if (len > 1) {
PyErr_Format(PyExc_TypeError,
"\"%s\" must be an 1-character string",
name);
return -1;
}
if (len > 0)
*target = *PyString_AS_STRING(src);
} }
} }
return 0; return 0;
...@@ -267,7 +272,7 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt) ...@@ -267,7 +272,7 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
*target = NULL; *target = NULL;
else if (!IS_BASESTRING(src)) { else if (!IS_BASESTRING(src)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"\"%s\" must be an string", name); "\"%s\" must be a string", name);
return -1; return -1;
} }
else { else {
...@@ -426,7 +431,8 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) ...@@ -426,7 +431,8 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (dialect_check_quoting(self->quoting)) if (dialect_check_quoting(self->quoting))
goto err; goto err;
if (self->delimiter == 0) { 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; goto err;
} }
if (quotechar == Py_None && quoting == NULL) if (quotechar == Py_None && quoting == NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment