bpo-34197: Make _csv.Dialect attributes booleans. (GH-8440)
Attributes skipinitialspace, doublequote and strict are now booleans instead of integers 0 or 1.
This commit is contained in:
parent
ecf411c59e
commit
323748ad74
|
@ -48,13 +48,13 @@ class Test_Csv(unittest.TestCase):
|
||||||
obj = ctor(*args)
|
obj = ctor(*args)
|
||||||
# Check defaults
|
# Check defaults
|
||||||
self.assertEqual(obj.dialect.delimiter, ',')
|
self.assertEqual(obj.dialect.delimiter, ',')
|
||||||
self.assertEqual(obj.dialect.doublequote, True)
|
self.assertIs(obj.dialect.doublequote, True)
|
||||||
self.assertEqual(obj.dialect.escapechar, None)
|
self.assertEqual(obj.dialect.escapechar, None)
|
||||||
self.assertEqual(obj.dialect.lineterminator, "\r\n")
|
self.assertEqual(obj.dialect.lineterminator, "\r\n")
|
||||||
self.assertEqual(obj.dialect.quotechar, '"')
|
self.assertEqual(obj.dialect.quotechar, '"')
|
||||||
self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
|
self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
|
||||||
self.assertEqual(obj.dialect.skipinitialspace, False)
|
self.assertIs(obj.dialect.skipinitialspace, False)
|
||||||
self.assertEqual(obj.dialect.strict, False)
|
self.assertIs(obj.dialect.strict, False)
|
||||||
# Try deleting or changing attributes (they are read-only)
|
# Try deleting or changing attributes (they are read-only)
|
||||||
self.assertRaises(AttributeError, delattr, obj.dialect, 'delimiter')
|
self.assertRaises(AttributeError, delattr, obj.dialect, 'delimiter')
|
||||||
self.assertRaises(AttributeError, setattr, obj.dialect, 'delimiter', ':')
|
self.assertRaises(AttributeError, setattr, obj.dialect, 'delimiter', ':')
|
||||||
|
@ -76,13 +76,13 @@ class Test_Csv(unittest.TestCase):
|
||||||
strict=True)
|
strict=True)
|
||||||
obj = ctor(*args, **kwargs)
|
obj = ctor(*args, **kwargs)
|
||||||
self.assertEqual(obj.dialect.delimiter, ':')
|
self.assertEqual(obj.dialect.delimiter, ':')
|
||||||
self.assertEqual(obj.dialect.doublequote, False)
|
self.assertIs(obj.dialect.doublequote, False)
|
||||||
self.assertEqual(obj.dialect.escapechar, '\\')
|
self.assertEqual(obj.dialect.escapechar, '\\')
|
||||||
self.assertEqual(obj.dialect.lineterminator, "\r")
|
self.assertEqual(obj.dialect.lineterminator, "\r")
|
||||||
self.assertEqual(obj.dialect.quotechar, '*')
|
self.assertEqual(obj.dialect.quotechar, '*')
|
||||||
self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
|
self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
|
||||||
self.assertEqual(obj.dialect.skipinitialspace, True)
|
self.assertIs(obj.dialect.skipinitialspace, True)
|
||||||
self.assertEqual(obj.dialect.strict, True)
|
self.assertIs(obj.dialect.strict, True)
|
||||||
|
|
||||||
def test_reader_kw_attrs(self):
|
def test_reader_kw_attrs(self):
|
||||||
self._test_kw_attrs(csv.reader, [])
|
self._test_kw_attrs(csv.reader, [])
|
||||||
|
@ -104,13 +104,13 @@ class Test_Csv(unittest.TestCase):
|
||||||
args = args + (dialect,)
|
args = args + (dialect,)
|
||||||
obj = ctor(*args)
|
obj = ctor(*args)
|
||||||
self.assertEqual(obj.dialect.delimiter, '-')
|
self.assertEqual(obj.dialect.delimiter, '-')
|
||||||
self.assertEqual(obj.dialect.doublequote, False)
|
self.assertIs(obj.dialect.doublequote, False)
|
||||||
self.assertEqual(obj.dialect.escapechar, '^')
|
self.assertEqual(obj.dialect.escapechar, '^')
|
||||||
self.assertEqual(obj.dialect.lineterminator, "$")
|
self.assertEqual(obj.dialect.lineterminator, "$")
|
||||||
self.assertEqual(obj.dialect.quotechar, '#')
|
self.assertEqual(obj.dialect.quotechar, '#')
|
||||||
self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
|
self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
|
||||||
self.assertEqual(obj.dialect.skipinitialspace, True)
|
self.assertIs(obj.dialect.skipinitialspace, True)
|
||||||
self.assertEqual(obj.dialect.strict, False)
|
self.assertIs(obj.dialect.strict, False)
|
||||||
|
|
||||||
def test_reader_dialect_attrs(self):
|
def test_reader_dialect_attrs(self):
|
||||||
self._test_dialect_attrs(csv.reader, [])
|
self._test_dialect_attrs(csv.reader, [])
|
||||||
|
@ -976,15 +976,13 @@ Stonecutters Seafood and Chop House+ Lemont+ IL+ 12/19/02+ Week Back
|
||||||
|
|
||||||
def test_has_header(self):
|
def test_has_header(self):
|
||||||
sniffer = csv.Sniffer()
|
sniffer = csv.Sniffer()
|
||||||
self.assertEqual(sniffer.has_header(self.sample1), False)
|
self.assertIs(sniffer.has_header(self.sample1), False)
|
||||||
self.assertEqual(sniffer.has_header(self.header1 + self.sample1),
|
self.assertIs(sniffer.has_header(self.header1 + self.sample1), True)
|
||||||
True)
|
|
||||||
|
|
||||||
def test_has_header_regex_special_delimiter(self):
|
def test_has_header_regex_special_delimiter(self):
|
||||||
sniffer = csv.Sniffer()
|
sniffer = csv.Sniffer()
|
||||||
self.assertEqual(sniffer.has_header(self.sample8), False)
|
self.assertIs(sniffer.has_header(self.sample8), False)
|
||||||
self.assertEqual(sniffer.has_header(self.header2 + self.sample8),
|
self.assertIs(sniffer.has_header(self.header2 + self.sample8), True)
|
||||||
True)
|
|
||||||
|
|
||||||
def test_guess_quote_and_delimiter(self):
|
def test_guess_quote_and_delimiter(self):
|
||||||
sniffer = csv.Sniffer()
|
sniffer = csv.Sniffer()
|
||||||
|
@ -1001,12 +999,12 @@ Stonecutters Seafood and Chop House+ Lemont+ IL+ 12/19/02+ Week Back
|
||||||
dialect = sniffer.sniff(self.sample1)
|
dialect = sniffer.sniff(self.sample1)
|
||||||
self.assertEqual(dialect.delimiter, ",")
|
self.assertEqual(dialect.delimiter, ",")
|
||||||
self.assertEqual(dialect.quotechar, '"')
|
self.assertEqual(dialect.quotechar, '"')
|
||||||
self.assertEqual(dialect.skipinitialspace, True)
|
self.assertIs(dialect.skipinitialspace, True)
|
||||||
|
|
||||||
dialect = sniffer.sniff(self.sample2)
|
dialect = sniffer.sniff(self.sample2)
|
||||||
self.assertEqual(dialect.delimiter, ":")
|
self.assertEqual(dialect.delimiter, ":")
|
||||||
self.assertEqual(dialect.quotechar, "'")
|
self.assertEqual(dialect.quotechar, "'")
|
||||||
self.assertEqual(dialect.skipinitialspace, False)
|
self.assertIs(dialect.skipinitialspace, False)
|
||||||
|
|
||||||
def test_delimiters(self):
|
def test_delimiters(self):
|
||||||
sniffer = csv.Sniffer()
|
sniffer = csv.Sniffer()
|
||||||
|
@ -1068,7 +1066,7 @@ class TestLeaks(unittest.TestCase):
|
||||||
delta = rc-lastrc
|
delta = rc-lastrc
|
||||||
lastrc = rc
|
lastrc = rc
|
||||||
# if csv.reader() leaks, last delta should be 3 or more
|
# if csv.reader() leaks, last delta should be 3 or more
|
||||||
self.assertEqual(delta < 3, True)
|
self.assertLess(delta, 3)
|
||||||
|
|
||||||
def test_create_write(self):
|
def test_create_write(self):
|
||||||
delta = 0
|
delta = 0
|
||||||
|
@ -1084,7 +1082,7 @@ class TestLeaks(unittest.TestCase):
|
||||||
delta = rc-lastrc
|
delta = rc-lastrc
|
||||||
lastrc = rc
|
lastrc = rc
|
||||||
# if csv.writer() leaks, last delta should be 3 or more
|
# if csv.writer() leaks, last delta should be 3 or more
|
||||||
self.assertEqual(delta < 3, True)
|
self.assertLess(delta, 3)
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
delta = 0
|
delta = 0
|
||||||
|
@ -1100,7 +1098,7 @@ class TestLeaks(unittest.TestCase):
|
||||||
delta = rc-lastrc
|
delta = rc-lastrc
|
||||||
lastrc = rc
|
lastrc = rc
|
||||||
# if reader leaks during read, delta should be 5 or more
|
# if reader leaks during read, delta should be 5 or more
|
||||||
self.assertEqual(delta < 5, True)
|
self.assertLess(delta, 5)
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
delta = 0
|
delta = 0
|
||||||
|
@ -1117,7 +1115,7 @@ class TestLeaks(unittest.TestCase):
|
||||||
delta = rc-lastrc
|
delta = rc-lastrc
|
||||||
lastrc = rc
|
lastrc = rc
|
||||||
# if writer leaks during write, last delta should be 5 or more
|
# if writer leaks during write, last delta should be 5 or more
|
||||||
self.assertEqual(delta < 5, True)
|
self.assertLess(delta, 5)
|
||||||
|
|
||||||
class TestUnicode(unittest.TestCase):
|
class TestUnicode(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Attributes *skipinitialspace*, *doublequote* and *strict* of the *dialect*
|
||||||
|
attribute of the :mod:`csv` reader are now :class:`bool` instances instead
|
||||||
|
of integers 0 or 1.
|
|
@ -12,6 +12,7 @@ module instead.
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -74,15 +75,15 @@ static const StyleDesc quote_styles[] = {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
|
||||||
int doublequote; /* is " represented by ""? */
|
char doublequote; /* is " represented by ""? */
|
||||||
|
char skipinitialspace; /* ignore spaces following delimiter? */
|
||||||
|
char strict; /* raise exception on bad CSV */
|
||||||
|
int quoting; /* style of quoting to write */
|
||||||
Py_UCS4 delimiter; /* field separator */
|
Py_UCS4 delimiter; /* field separator */
|
||||||
Py_UCS4 quotechar; /* quote character */
|
Py_UCS4 quotechar; /* quote character */
|
||||||
Py_UCS4 escapechar; /* escape character */
|
Py_UCS4 escapechar; /* escape character */
|
||||||
int skipinitialspace; /* ignore spaces following delimiter? */
|
|
||||||
PyObject *lineterminator; /* string to write between records */
|
PyObject *lineterminator; /* string to write between records */
|
||||||
int quoting; /* style of quoting to write */
|
|
||||||
|
|
||||||
int strict; /* raise exception on bad CSV */
|
|
||||||
} DialectObj;
|
} DialectObj;
|
||||||
|
|
||||||
static PyTypeObject Dialect_Type;
|
static PyTypeObject Dialect_Type;
|
||||||
|
@ -189,7 +190,7 @@ Dialect_get_quoting(DialectObj *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_set_bool(const char *name, int *target, PyObject *src, int dflt)
|
_set_bool(const char *name, char *target, PyObject *src, bool dflt)
|
||||||
{
|
{
|
||||||
if (src == NULL)
|
if (src == NULL)
|
||||||
*target = dflt;
|
*target = dflt;
|
||||||
|
@ -197,7 +198,7 @@ _set_bool(const char *name, int *target, PyObject *src, int dflt)
|
||||||
int b = PyObject_IsTrue(src);
|
int b = PyObject_IsTrue(src);
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
return -1;
|
return -1;
|
||||||
*target = b;
|
*target = (char)b;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -292,9 +293,9 @@ dialect_check_quoting(int quoting)
|
||||||
#define D_OFF(x) offsetof(DialectObj, x)
|
#define D_OFF(x) offsetof(DialectObj, x)
|
||||||
|
|
||||||
static struct PyMemberDef Dialect_memberlist[] = {
|
static struct PyMemberDef Dialect_memberlist[] = {
|
||||||
{ "skipinitialspace", T_INT, D_OFF(skipinitialspace), READONLY },
|
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), READONLY },
|
||||||
{ "doublequote", T_INT, D_OFF(doublequote), READONLY },
|
{ "doublequote", T_BOOL, D_OFF(doublequote), READONLY },
|
||||||
{ "strict", T_INT, D_OFF(strict), READONLY },
|
{ "strict", T_BOOL, D_OFF(strict), READONLY },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -411,13 +412,13 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||||
if (meth(name, target, src, dflt)) \
|
if (meth(name, target, src, dflt)) \
|
||||||
goto err
|
goto err
|
||||||
DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ',');
|
DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ',');
|
||||||
DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, 1);
|
DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, true);
|
||||||
DIASET(_set_char, "escapechar", &self->escapechar, escapechar, 0);
|
DIASET(_set_char, "escapechar", &self->escapechar, escapechar, 0);
|
||||||
DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n");
|
DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n");
|
||||||
DIASET(_set_char, "quotechar", &self->quotechar, quotechar, '"');
|
DIASET(_set_char, "quotechar", &self->quotechar, quotechar, '"');
|
||||||
DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL);
|
DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL);
|
||||||
DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, 0);
|
DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false);
|
||||||
DIASET(_set_bool, "strict", &self->strict, strict, 0);
|
DIASET(_set_bool, "strict", &self->strict, strict, false);
|
||||||
|
|
||||||
/* validate options */
|
/* validate options */
|
||||||
if (dialect_check_quoting(self->quoting))
|
if (dialect_check_quoting(self->quoting))
|
||||||
|
|
Loading…
Reference in New Issue