Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1196cf1

Browse files
committed
Improved the implementation of the internal "dialect" type. The new
implementation features better error reporting, and better compliance with the PEP.
1 parent 72b83c8 commit 1196cf1

3 files changed

Lines changed: 339 additions & 212 deletions

File tree

Lib/csv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def _validate(self):
6868
elif not isinstance(self.lineterminator, str):
6969
errors.append("lineterminator must be a string")
7070

71-
if self.doublequote not in (True, False):
71+
if self.doublequote not in (True, False) and self.quoting != QUOTE_NONE:
7272
errors.append("doublequote parameter must be True or False")
7373

7474
if self.skipinitialspace not in (True, False):

Lib/test/test_csv.py

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,112 @@ class Test_Csv(unittest.TestCase):
1717
from the high level interface. Further tests of this nature are done
1818
in TestDialectRegistry.
1919
"""
20-
def test_reader_arg_valid(self):
21-
self.assertRaises(TypeError, csv.reader)
22-
self.assertRaises(TypeError, csv.reader, None)
23-
self.assertRaises(AttributeError, csv.reader, [], bad_attr = 0)
24-
self.assertRaises(csv.Error, csv.reader, [], 'foo')
20+
def _test_arg_valid(self, ctor, arg):
21+
self.assertRaises(TypeError, ctor)
22+
self.assertRaises(TypeError, ctor, None)
23+
self.assertRaises(TypeError, ctor, arg, bad_attr = 0)
24+
self.assertRaises(TypeError, ctor, arg, delimiter = 0)
25+
self.assertRaises(TypeError, ctor, arg, delimiter = 'XX')
26+
self.assertRaises(csv.Error, ctor, arg, 'foo')
27+
self.assertRaises(TypeError, ctor, arg, None)
28+
self.assertRaises(TypeError, ctor, arg, delimiter=None)
29+
self.assertRaises(TypeError, ctor, arg, delimiter=1)
30+
self.assertRaises(TypeError, ctor, arg, quotechar=1)
31+
self.assertRaises(TypeError, ctor, arg, lineterminator=None)
32+
self.assertRaises(TypeError, ctor, arg, lineterminator=1)
33+
self.assertRaises(TypeError, ctor, arg, quoting=None)
34+
# We now allow this, only raising an exception if quoting is needed.
35+
# self.assertRaises(TypeError, ctor, arg, quotechar=None)
36+
# self.assertRaises(TypeError, ctor, arg,
37+
# quoting=csv.QUOTE_NONE, escapechar=None)
38+
# No longer complains about dialects with invalid attributes [AM]
39+
# class BadDialect:
40+
# bad_attr = 0
41+
# self.assertRaises(AttributeError, csv.reader, [], BadDialect)
2542
class BadClass:
2643
def __init__(self):
2744
raise IOError
2845
self.assertRaises(IOError, csv.reader, [], BadClass)
29-
self.assertRaises(TypeError, csv.reader, [], None)
30-
class BadDialect:
31-
bad_attr = 0
32-
self.assertRaises(AttributeError, csv.reader, [], BadDialect)
46+
47+
def test_reader_arg_valid(self):
48+
self._test_arg_valid(csv.reader, [])
3349

3450
def test_writer_arg_valid(self):
35-
self.assertRaises(TypeError, csv.writer)
36-
self.assertRaises(TypeError, csv.writer, None)
37-
self.assertRaises(AttributeError, csv.writer, StringIO(), bad_attr = 0)
51+
self._test_arg_valid(csv.writer, StringIO())
3852

39-
def _test_attrs(self, obj):
53+
def _test_default_attrs(self, ctor, *args):
54+
obj = ctor(*args)
55+
# Check defaults
4056
self.assertEqual(obj.dialect.delimiter, ',')
41-
obj.dialect.delimiter = '\t'
42-
self.assertEqual(obj.dialect.delimiter, '\t')
43-
self.assertRaises(TypeError, delattr, obj.dialect, 'delimiter')
44-
self.assertRaises(TypeError, setattr, obj.dialect,
45-
'lineterminator', None)
46-
obj.dialect.escapechar = None
57+
self.assertEqual(obj.dialect.doublequote, True)
4758
self.assertEqual(obj.dialect.escapechar, None)
59+
self.assertEqual(obj.dialect.lineterminator, "\r\n")
60+
self.assertEqual(obj.dialect.quotechar, '"')
61+
self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
62+
self.assertEqual(obj.dialect.skipinitialspace, False)
63+
self.assertEqual(obj.dialect.strict, False)
64+
# Try deleting or changing attributes (they are read-only)
65+
self.assertRaises(TypeError, delattr, obj.dialect, 'delimiter')
66+
self.assertRaises(TypeError, setattr, obj.dialect, 'delimiter', ':')
4867
self.assertRaises(TypeError, delattr, obj.dialect, 'quoting')
4968
self.assertRaises(TypeError, setattr, obj.dialect, 'quoting', None)
50-
obj.dialect.quoting = csv.QUOTE_MINIMAL
51-
self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
5269

5370
def test_reader_attrs(self):
54-
self._test_attrs(csv.reader([]))
71+
self._test_default_attrs(csv.reader, [])
5572

5673
def test_writer_attrs(self):
57-
self._test_attrs(csv.writer(StringIO()))
74+
self._test_default_attrs(csv.writer, StringIO())
75+
76+
def _test_kw_attrs(self, ctor, *args):
77+
# Now try with alternate options
78+
kwargs = dict(delimiter=':', doublequote=False, escapechar='\\',
79+
lineterminator='\r', quotechar='*',
80+
quoting=csv.QUOTE_NONE, skipinitialspace=True,
81+
strict=True)
82+
obj = ctor(*args, **kwargs)
83+
self.assertEqual(obj.dialect.delimiter, ':')
84+
self.assertEqual(obj.dialect.doublequote, False)
85+
self.assertEqual(obj.dialect.escapechar, '\\')
86+
self.assertEqual(obj.dialect.lineterminator, "\r")
87+
self.assertEqual(obj.dialect.quotechar, '*')
88+
self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
89+
self.assertEqual(obj.dialect.skipinitialspace, True)
90+
self.assertEqual(obj.dialect.strict, True)
91+
92+
def test_reader_kw_attrs(self):
93+
self._test_kw_attrs(csv.reader, [])
94+
95+
def test_writer_kw_attrs(self):
96+
self._test_kw_attrs(csv.writer, StringIO())
97+
98+
def _test_dialect_attrs(self, ctor, *args):
99+
# Now try with dialect-derived options
100+
class dialect:
101+
delimiter='-'
102+
doublequote=False
103+
escapechar='^'
104+
lineterminator='$'
105+
quotechar='#'
106+
quoting=csv.QUOTE_ALL
107+
skipinitialspace=True
108+
strict=False
109+
args = args + (dialect,)
110+
obj = ctor(*args)
111+
self.assertEqual(obj.dialect.delimiter, '-')
112+
self.assertEqual(obj.dialect.doublequote, False)
113+
self.assertEqual(obj.dialect.escapechar, '^')
114+
self.assertEqual(obj.dialect.lineterminator, "$")
115+
self.assertEqual(obj.dialect.quotechar, '#')
116+
self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
117+
self.assertEqual(obj.dialect.skipinitialspace, True)
118+
self.assertEqual(obj.dialect.strict, False)
119+
120+
def test_reader_dialect_attrs(self):
121+
self._test_dialect_attrs(csv.reader, [])
122+
123+
def test_writer_dialect_attrs(self):
124+
self._test_dialect_attrs(csv.writer, StringIO())
125+
58126

59127
def _write_test(self, fields, expect, **kwargs):
60128
fd, name = tempfile.mkstemp()
@@ -166,6 +234,13 @@ def test_read_escape(self):
166234
self._read_test(['a,"b,c\\""'], [['a', 'b,c"']], escapechar='\\')
167235
self._read_test(['a,"b,c"\\'], [['a', 'b,c\\']], escapechar='\\')
168236

237+
def test_read_quoting(self):
238+
self._read_test(['1,",3,",5'], [['1', ',3,', '5']])
239+
self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
240+
quotechar=None, escapechar='\\')
241+
self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
242+
quoting=csv.QUOTE_NONE, escapechar='\\')
243+
169244
def test_read_bigfield(self):
170245
# This exercises the buffer realloc functionality
171246
bigstring = 'X' * 50000
@@ -297,7 +372,7 @@ class testC(csv.excel):
297372

298373
def test_bad_dialect(self):
299374
# Unknown parameter
300-
self.assertRaises(AttributeError, csv.reader, [], bad_attr = 0)
375+
self.assertRaises(TypeError, csv.reader, [], bad_attr = 0)
301376
# Bad values
302377
self.assertRaises(TypeError, csv.reader, [], delimiter = None)
303378
self.assertRaises(TypeError, csv.reader, [], quoting = -1)

0 commit comments

Comments
 (0)