Skip to content

Commit 323748a

Browse files
bpo-34197: Make _csv.Dialect attributes booleans. (GH-8440)
Attributes skipinitialspace, doublequote and strict are now booleans instead of integers 0 or 1.
1 parent ecf411c commit 323748a

3 files changed

Lines changed: 38 additions & 36 deletions

File tree

Lib/test/test_csv.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ def _test_default_attrs(self, ctor, *args):
4848
obj = ctor(*args)
4949
# Check defaults
5050
self.assertEqual(obj.dialect.delimiter, ',')
51-
self.assertEqual(obj.dialect.doublequote, True)
51+
self.assertIs(obj.dialect.doublequote, True)
5252
self.assertEqual(obj.dialect.escapechar, None)
5353
self.assertEqual(obj.dialect.lineterminator, "\r\n")
5454
self.assertEqual(obj.dialect.quotechar, '"')
5555
self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
56-
self.assertEqual(obj.dialect.skipinitialspace, False)
57-
self.assertEqual(obj.dialect.strict, False)
56+
self.assertIs(obj.dialect.skipinitialspace, False)
57+
self.assertIs(obj.dialect.strict, False)
5858
# Try deleting or changing attributes (they are read-only)
5959
self.assertRaises(AttributeError, delattr, obj.dialect, 'delimiter')
6060
self.assertRaises(AttributeError, setattr, obj.dialect, 'delimiter', ':')
@@ -76,13 +76,13 @@ def _test_kw_attrs(self, ctor, *args):
7676
strict=True)
7777
obj = ctor(*args, **kwargs)
7878
self.assertEqual(obj.dialect.delimiter, ':')
79-
self.assertEqual(obj.dialect.doublequote, False)
79+
self.assertIs(obj.dialect.doublequote, False)
8080
self.assertEqual(obj.dialect.escapechar, '\\')
8181
self.assertEqual(obj.dialect.lineterminator, "\r")
8282
self.assertEqual(obj.dialect.quotechar, '*')
8383
self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
84-
self.assertEqual(obj.dialect.skipinitialspace, True)
85-
self.assertEqual(obj.dialect.strict, True)
84+
self.assertIs(obj.dialect.skipinitialspace, True)
85+
self.assertIs(obj.dialect.strict, True)
8686

8787
def test_reader_kw_attrs(self):
8888
self._test_kw_attrs(csv.reader, [])
@@ -104,13 +104,13 @@ class dialect:
104104
args = args + (dialect,)
105105
obj = ctor(*args)
106106
self.assertEqual(obj.dialect.delimiter, '-')
107-
self.assertEqual(obj.dialect.doublequote, False)
107+
self.assertIs(obj.dialect.doublequote, False)
108108
self.assertEqual(obj.dialect.escapechar, '^')
109109
self.assertEqual(obj.dialect.lineterminator, "$")
110110
self.assertEqual(obj.dialect.quotechar, '#')
111111
self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
112-
self.assertEqual(obj.dialect.skipinitialspace, True)
113-
self.assertEqual(obj.dialect.strict, False)
112+
self.assertIs(obj.dialect.skipinitialspace, True)
113+
self.assertIs(obj.dialect.strict, False)
114114

115115
def test_reader_dialect_attrs(self):
116116
self._test_dialect_attrs(csv.reader, [])
@@ -976,15 +976,13 @@ class TestSniffer(unittest.TestCase):
976976

977977
def test_has_header(self):
978978
sniffer = csv.Sniffer()
979-
self.assertEqual(sniffer.has_header(self.sample1), False)
980-
self.assertEqual(sniffer.has_header(self.header1 + self.sample1),
981-
True)
979+
self.assertIs(sniffer.has_header(self.sample1), False)
980+
self.assertIs(sniffer.has_header(self.header1 + self.sample1), True)
982981

983982
def test_has_header_regex_special_delimiter(self):
984983
sniffer = csv.Sniffer()
985-
self.assertEqual(sniffer.has_header(self.sample8), False)
986-
self.assertEqual(sniffer.has_header(self.header2 + self.sample8),
987-
True)
984+
self.assertIs(sniffer.has_header(self.sample8), False)
985+
self.assertIs(sniffer.has_header(self.header2 + self.sample8), True)
988986

989987
def test_guess_quote_and_delimiter(self):
990988
sniffer = csv.Sniffer()
@@ -1001,12 +999,12 @@ def test_sniff(self):
1001999
dialect = sniffer.sniff(self.sample1)
10021000
self.assertEqual(dialect.delimiter, ",")
10031001
self.assertEqual(dialect.quotechar, '"')
1004-
self.assertEqual(dialect.skipinitialspace, True)
1002+
self.assertIs(dialect.skipinitialspace, True)
10051003

10061004
dialect = sniffer.sniff(self.sample2)
10071005
self.assertEqual(dialect.delimiter, ":")
10081006
self.assertEqual(dialect.quotechar, "'")
1009-
self.assertEqual(dialect.skipinitialspace, False)
1007+
self.assertIs(dialect.skipinitialspace, False)
10101008

10111009
def test_delimiters(self):
10121010
sniffer = csv.Sniffer()
@@ -1068,7 +1066,7 @@ def test_create_read(self):
10681066
delta = rc-lastrc
10691067
lastrc = rc
10701068
# if csv.reader() leaks, last delta should be 3 or more
1071-
self.assertEqual(delta < 3, True)
1069+
self.assertLess(delta, 3)
10721070

10731071
def test_create_write(self):
10741072
delta = 0
@@ -1084,7 +1082,7 @@ def test_create_write(self):
10841082
delta = rc-lastrc
10851083
lastrc = rc
10861084
# if csv.writer() leaks, last delta should be 3 or more
1087-
self.assertEqual(delta < 3, True)
1085+
self.assertLess(delta, 3)
10881086

10891087
def test_read(self):
10901088
delta = 0
@@ -1100,7 +1098,7 @@ def test_read(self):
11001098
delta = rc-lastrc
11011099
lastrc = rc
11021100
# if reader leaks during read, delta should be 5 or more
1103-
self.assertEqual(delta < 5, True)
1101+
self.assertLess(delta, 5)
11041102

11051103
def test_write(self):
11061104
delta = 0
@@ -1117,7 +1115,7 @@ def test_write(self):
11171115
delta = rc-lastrc
11181116
lastrc = rc
11191117
# if writer leaks during write, last delta should be 5 or more
1120-
self.assertEqual(delta < 5, True)
1118+
self.assertLess(delta, 5)
11211119

11221120
class TestUnicode(unittest.TestCase):
11231121

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Attributes *skipinitialspace*, *doublequote* and *strict* of the *dialect*
2+
attribute of the :mod:`csv` reader are now :class:`bool` instances instead
3+
of integers 0 or 1.

Modules/_csv.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module instead.
1212

1313
#include "Python.h"
1414
#include "structmember.h"
15+
#include <stdbool.h>
1516

1617

1718
typedef struct {
@@ -74,15 +75,15 @@ static const StyleDesc quote_styles[] = {
7475
typedef struct {
7576
PyObject_HEAD
7677

77-
int doublequote; /* is " represented by ""? */
78-
Py_UCS4 delimiter; /* field separator */
79-
Py_UCS4 quotechar; /* quote character */
80-
Py_UCS4 escapechar; /* escape character */
81-
int skipinitialspace; /* ignore spaces following delimiter? */
82-
PyObject *lineterminator; /* string to write between records */
78+
char doublequote; /* is " represented by ""? */
79+
char skipinitialspace; /* ignore spaces following delimiter? */
80+
char strict; /* raise exception on bad CSV */
8381
int quoting; /* style of quoting to write */
82+
Py_UCS4 delimiter; /* field separator */
83+
Py_UCS4 quotechar; /* quote character */
84+
Py_UCS4 escapechar; /* escape character */
85+
PyObject *lineterminator; /* string to write between records */
8486

85-
int strict; /* raise exception on bad CSV */
8687
} DialectObj;
8788

8889
static PyTypeObject Dialect_Type;
@@ -189,15 +190,15 @@ Dialect_get_quoting(DialectObj *self)
189190
}
190191

191192
static int
192-
_set_bool(const char *name, int *target, PyObject *src, int dflt)
193+
_set_bool(const char *name, char *target, PyObject *src, bool dflt)
193194
{
194195
if (src == NULL)
195196
*target = dflt;
196197
else {
197198
int b = PyObject_IsTrue(src);
198199
if (b < 0)
199200
return -1;
200-
*target = b;
201+
*target = (char)b;
201202
}
202203
return 0;
203204
}
@@ -292,9 +293,9 @@ dialect_check_quoting(int quoting)
292293
#define D_OFF(x) offsetof(DialectObj, x)
293294

294295
static struct PyMemberDef Dialect_memberlist[] = {
295-
{ "skipinitialspace", T_INT, D_OFF(skipinitialspace), READONLY },
296-
{ "doublequote", T_INT, D_OFF(doublequote), READONLY },
297-
{ "strict", T_INT, D_OFF(strict), READONLY },
296+
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), READONLY },
297+
{ "doublequote", T_BOOL, D_OFF(doublequote), READONLY },
298+
{ "strict", T_BOOL, D_OFF(strict), READONLY },
298299
{ NULL }
299300
};
300301

@@ -411,13 +412,13 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
411412
if (meth(name, target, src, dflt)) \
412413
goto err
413414
DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ',');
414-
DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, 1);
415+
DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, true);
415416
DIASET(_set_char, "escapechar", &self->escapechar, escapechar, 0);
416417
DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n");
417418
DIASET(_set_char, "quotechar", &self->quotechar, quotechar, '"');
418419
DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL);
419-
DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, 0);
420-
DIASET(_set_bool, "strict", &self->strict, strict, 0);
420+
DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false);
421+
DIASET(_set_bool, "strict", &self->strict, strict, false);
421422

422423
/* validate options */
423424
if (dialect_check_quoting(self->quoting))

0 commit comments

Comments
 (0)