blob: d4567590cb1d8e4289352f73d1cb0e80abd59673 [file] [log] [blame]
Skip Montanaro1a566652003-05-06 15:56:05 +00001# -*- coding: iso-8859-1 -*-
Skip Montanarob4a04172003-03-20 23:29:12 +00002# Copyright (C) 2001,2002 Python Software Foundation
3# csv package unit tests
4
Serhiy Storchakab8e54dd2015-12-30 20:43:29 +02005import copy
Skip Montanarob4a04172003-03-20 23:29:12 +00006import sys
Skip Montanaro58fc5d02004-06-05 17:03:20 +00007import os
Skip Montanarob4a04172003-03-20 23:29:12 +00008import unittest
9from StringIO import StringIO
Skip Montanaro58fc5d02004-06-05 17:03:20 +000010import tempfile
Skip Montanaro594adac2003-04-10 17:16:15 +000011import csv
Skip Montanarob4a04172003-03-20 23:29:12 +000012import gc
Dirkjan Ochtman19c9b602010-03-04 19:21:53 +000013import io
Serhiy Storchakab8e54dd2015-12-30 20:43:29 +020014import pickle
Walter Dörwald21d3a322003-05-01 17:45:56 +000015from test import test_support
Skip Montanarob4a04172003-03-20 23:29:12 +000016
17class Test_Csv(unittest.TestCase):
18 """
Tim Peters0eadaac2003-04-24 16:02:54 +000019 Test the underlying C csv parser in ways that are not appropriate
Skip Montanarob4a04172003-03-20 23:29:12 +000020 from the high level interface. Further tests of this nature are done
21 in TestDialectRegistry.
22 """
Andrew McNamara1196cf12005-01-07 04:42:45 +000023 def _test_arg_valid(self, ctor, arg):
24 self.assertRaises(TypeError, ctor)
25 self.assertRaises(TypeError, ctor, None)
26 self.assertRaises(TypeError, ctor, arg, bad_attr = 0)
27 self.assertRaises(TypeError, ctor, arg, delimiter = 0)
28 self.assertRaises(TypeError, ctor, arg, delimiter = 'XX')
29 self.assertRaises(csv.Error, ctor, arg, 'foo')
Andrew McNamara1196cf12005-01-07 04:42:45 +000030 self.assertRaises(TypeError, ctor, arg, delimiter=None)
31 self.assertRaises(TypeError, ctor, arg, delimiter=1)
32 self.assertRaises(TypeError, ctor, arg, quotechar=1)
33 self.assertRaises(TypeError, ctor, arg, lineterminator=None)
34 self.assertRaises(TypeError, ctor, arg, lineterminator=1)
35 self.assertRaises(TypeError, ctor, arg, quoting=None)
Tim Peters608c2ff2005-01-13 17:37:38 +000036 self.assertRaises(TypeError, ctor, arg,
Andrew McNamaraaf1e3122005-01-12 01:55:21 +000037 quoting=csv.QUOTE_ALL, quotechar='')
Tim Peters608c2ff2005-01-13 17:37:38 +000038 self.assertRaises(TypeError, ctor, arg,
Andrew McNamara5d45a8d2005-01-12 08:16:17 +000039 quoting=csv.QUOTE_ALL, quotechar=None)
Andrew McNamara1196cf12005-01-07 04:42:45 +000040
41 def test_reader_arg_valid(self):
42 self._test_arg_valid(csv.reader, [])
Skip Montanarob4a04172003-03-20 23:29:12 +000043
44 def test_writer_arg_valid(self):
Andrew McNamara1196cf12005-01-07 04:42:45 +000045 self._test_arg_valid(csv.writer, StringIO())
Skip Montanarob4a04172003-03-20 23:29:12 +000046
Andrew McNamara1196cf12005-01-07 04:42:45 +000047 def _test_default_attrs(self, ctor, *args):
48 obj = ctor(*args)
49 # Check defaults
Skip Montanarob4a04172003-03-20 23:29:12 +000050 self.assertEqual(obj.dialect.delimiter, ',')
Andrew McNamara1196cf12005-01-07 04:42:45 +000051 self.assertEqual(obj.dialect.doublequote, True)
Skip Montanarob4a04172003-03-20 23:29:12 +000052 self.assertEqual(obj.dialect.escapechar, None)
Andrew McNamara1196cf12005-01-07 04:42:45 +000053 self.assertEqual(obj.dialect.lineterminator, "\r\n")
54 self.assertEqual(obj.dialect.quotechar, '"')
55 self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
56 self.assertEqual(obj.dialect.skipinitialspace, False)
57 self.assertEqual(obj.dialect.strict, False)
58 # Try deleting or changing attributes (they are read-only)
59 self.assertRaises(TypeError, delattr, obj.dialect, 'delimiter')
60 self.assertRaises(TypeError, setattr, obj.dialect, 'delimiter', ':')
Barry Warsawb180c062005-04-20 19:41:36 +000061 self.assertRaises(AttributeError, delattr, obj.dialect, 'quoting')
62 self.assertRaises(AttributeError, setattr, obj.dialect,
63 'quoting', None)
Skip Montanarob4a04172003-03-20 23:29:12 +000064
65 def test_reader_attrs(self):
Andrew McNamara1196cf12005-01-07 04:42:45 +000066 self._test_default_attrs(csv.reader, [])
Skip Montanarob4a04172003-03-20 23:29:12 +000067
68 def test_writer_attrs(self):
Andrew McNamara1196cf12005-01-07 04:42:45 +000069 self._test_default_attrs(csv.writer, StringIO())
70
71 def _test_kw_attrs(self, ctor, *args):
72 # Now try with alternate options
73 kwargs = dict(delimiter=':', doublequote=False, escapechar='\\',
74 lineterminator='\r', quotechar='*',
75 quoting=csv.QUOTE_NONE, skipinitialspace=True,
76 strict=True)
77 obj = ctor(*args, **kwargs)
78 self.assertEqual(obj.dialect.delimiter, ':')
79 self.assertEqual(obj.dialect.doublequote, False)
80 self.assertEqual(obj.dialect.escapechar, '\\')
81 self.assertEqual(obj.dialect.lineterminator, "\r")
82 self.assertEqual(obj.dialect.quotechar, '*')
83 self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
84 self.assertEqual(obj.dialect.skipinitialspace, True)
85 self.assertEqual(obj.dialect.strict, True)
86
87 def test_reader_kw_attrs(self):
88 self._test_kw_attrs(csv.reader, [])
89
90 def test_writer_kw_attrs(self):
91 self._test_kw_attrs(csv.writer, StringIO())
92
93 def _test_dialect_attrs(self, ctor, *args):
94 # Now try with dialect-derived options
95 class dialect:
96 delimiter='-'
97 doublequote=False
98 escapechar='^'
99 lineterminator='$'
100 quotechar='#'
101 quoting=csv.QUOTE_ALL
102 skipinitialspace=True
103 strict=False
104 args = args + (dialect,)
105 obj = ctor(*args)
106 self.assertEqual(obj.dialect.delimiter, '-')
107 self.assertEqual(obj.dialect.doublequote, False)
108 self.assertEqual(obj.dialect.escapechar, '^')
109 self.assertEqual(obj.dialect.lineterminator, "$")
110 self.assertEqual(obj.dialect.quotechar, '#')
111 self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
112 self.assertEqual(obj.dialect.skipinitialspace, True)
113 self.assertEqual(obj.dialect.strict, False)
114
115 def test_reader_dialect_attrs(self):
116 self._test_dialect_attrs(csv.reader, [])
117
118 def test_writer_dialect_attrs(self):
119 self._test_dialect_attrs(csv.writer, StringIO())
120
Skip Montanarob4a04172003-03-20 23:29:12 +0000121
122 def _write_test(self, fields, expect, **kwargs):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000123 fd, name = tempfile.mkstemp()
124 fileobj = os.fdopen(fd, "w+b")
125 try:
126 writer = csv.writer(fileobj, **kwargs)
127 writer.writerow(fields)
128 fileobj.seek(0)
129 self.assertEqual(fileobj.read(),
130 expect + writer.dialect.lineterminator)
131 finally:
132 fileobj.close()
133 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000134
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200135 def _write_error_test(self, exc, fields, **kwargs):
136 fd, name = tempfile.mkstemp()
137 fileobj = os.fdopen(fd, "w+b")
138 try:
139 writer = csv.writer(fileobj, **kwargs)
140 with self.assertRaises(exc):
141 writer.writerow(fields)
142 fileobj.seek(0)
143 self.assertEqual(fileobj.read(), '')
144 finally:
145 fileobj.close()
146 os.unlink(name)
147
Skip Montanarob4a04172003-03-20 23:29:12 +0000148 def test_write_arg_valid(self):
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200149 self._write_error_test(csv.Error, None)
Skip Montanarob4a04172003-03-20 23:29:12 +0000150 self._write_test((), '')
151 self._write_test([None], '""')
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200152 self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
Skip Montanarob4a04172003-03-20 23:29:12 +0000153 # Check that exceptions are passed up the chain
154 class BadList:
155 def __len__(self):
156 return 10;
157 def __getitem__(self, i):
158 if i > 2:
159 raise IOError
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200160 self._write_error_test(IOError, BadList())
Skip Montanarob4a04172003-03-20 23:29:12 +0000161 class BadItem:
162 def __str__(self):
163 raise IOError
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200164 self._write_error_test(IOError, [BadItem()])
Skip Montanarob4a04172003-03-20 23:29:12 +0000165
166 def test_write_bigfield(self):
167 # This exercises the buffer realloc functionality
168 bigstring = 'X' * 50000
169 self._write_test([bigstring,bigstring], '%s,%s' % \
170 (bigstring, bigstring))
171
172 def test_write_quoting(self):
Andrew McNamarac89f2842005-01-12 07:44:42 +0000173 self._write_test(['a',1,'p,q'], 'a,1,"p,q"')
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200174 self._write_error_test(csv.Error, ['a',1,'p,q'],
175 quoting = csv.QUOTE_NONE)
Andrew McNamarac89f2842005-01-12 07:44:42 +0000176 self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
Skip Montanarob4a04172003-03-20 23:29:12 +0000177 quoting = csv.QUOTE_MINIMAL)
Andrew McNamarac89f2842005-01-12 07:44:42 +0000178 self._write_test(['a',1,'p,q'], '"a",1,"p,q"',
Skip Montanarob4a04172003-03-20 23:29:12 +0000179 quoting = csv.QUOTE_NONNUMERIC)
Andrew McNamarac89f2842005-01-12 07:44:42 +0000180 self._write_test(['a',1,'p,q'], '"a","1","p,q"',
Skip Montanarob4a04172003-03-20 23:29:12 +0000181 quoting = csv.QUOTE_ALL)
R. David Murray38644592009-04-01 21:26:18 +0000182 self._write_test(['a\nb',1], '"a\nb","1"',
183 quoting = csv.QUOTE_ALL)
Skip Montanarob4a04172003-03-20 23:29:12 +0000184
185 def test_write_escape(self):
Andrew McNamarac89f2842005-01-12 07:44:42 +0000186 self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
Skip Montanarob4a04172003-03-20 23:29:12 +0000187 escapechar='\\')
Serhiy Storchaka837d7602015-03-25 19:15:56 +0200188 self._write_error_test(csv.Error, ['a',1,'p,"q"'],
189 escapechar=None, doublequote=False)
Andrew McNamarac89f2842005-01-12 07:44:42 +0000190 self._write_test(['a',1,'p,"q"'], 'a,1,"p,\\"q\\""',
191 escapechar='\\', doublequote = False)
Tim Peters608c2ff2005-01-13 17:37:38 +0000192 self._write_test(['"'], '""""',
Andrew McNamarac89f2842005-01-12 07:44:42 +0000193 escapechar='\\', quoting = csv.QUOTE_MINIMAL)
Tim Peters608c2ff2005-01-13 17:37:38 +0000194 self._write_test(['"'], '\\"',
Andrew McNamarac89f2842005-01-12 07:44:42 +0000195 escapechar='\\', quoting = csv.QUOTE_MINIMAL,
196 doublequote = False)
Tim Peters608c2ff2005-01-13 17:37:38 +0000197 self._write_test(['"'], '\\"',
Andrew McNamarac89f2842005-01-12 07:44:42 +0000198 escapechar='\\', quoting = csv.QUOTE_NONE)
199 self._write_test(['a',1,'p,q'], 'a,1,p\\,q',
Skip Montanarob4a04172003-03-20 23:29:12 +0000200 escapechar='\\', quoting = csv.QUOTE_NONE)
201
202 def test_writerows(self):
203 class BrokenFile:
204 def write(self, buf):
205 raise IOError
206 writer = csv.writer(BrokenFile())
207 self.assertRaises(IOError, writer.writerows, [['a']])
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000208 fd, name = tempfile.mkstemp()
209 fileobj = os.fdopen(fd, "w+b")
210 try:
211 writer = csv.writer(fileobj)
212 self.assertRaises(TypeError, writer.writerows, None)
213 writer.writerows([['a','b'],['c','d']])
214 fileobj.seek(0)
215 self.assertEqual(fileobj.read(), "a,b\r\nc,d\r\n")
216 finally:
217 fileobj.close()
218 os.unlink(name)
Tim Peters27f88362004-07-08 04:22:35 +0000219
Raymond Hettingerf5377022011-12-11 22:31:09 -0800220 def test_write_float(self):
221 # Issue 13573: loss of precision because csv.writer
222 # uses str() for floats instead of repr()
223 orig_row = [1.234567890123, 1.0/7.0, 'abc']
224 f = StringIO()
225 c = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC)
226 c.writerow(orig_row)
227 f.seek(0)
228 c = csv.reader(f, quoting=csv.QUOTE_NONNUMERIC)
229 new_row = next(c)
230 self.assertEqual(orig_row, new_row)
231
Skip Montanarob4a04172003-03-20 23:29:12 +0000232 def _read_test(self, input, expect, **kwargs):
233 reader = csv.reader(input, **kwargs)
234 result = list(reader)
235 self.assertEqual(result, expect)
236
237 def test_read_oddinputs(self):
238 self._read_test([], [])
239 self._read_test([''], [[]])
240 self.assertRaises(csv.Error, self._read_test,
241 ['"ab"c'], None, strict = 1)
242 # cannot handle null bytes for the moment
243 self.assertRaises(csv.Error, self._read_test,
244 ['ab\0c'], None, strict = 1)
245 self._read_test(['"ab"c'], [['abc']], doublequote = 0)
246
247 def test_read_eol(self):
248 self._read_test(['a,b'], [['a','b']])
249 self._read_test(['a,b\n'], [['a','b']])
250 self._read_test(['a,b\r\n'], [['a','b']])
251 self._read_test(['a,b\r'], [['a','b']])
252 self.assertRaises(csv.Error, self._read_test, ['a,b\rc,d'], [])
253 self.assertRaises(csv.Error, self._read_test, ['a,b\nc,d'], [])
254 self.assertRaises(csv.Error, self._read_test, ['a,b\r\nc,d'], [])
255
Senthil Kumarand41dc7c2012-09-25 02:48:21 -0700256 def test_read_eof(self):
257 self._read_test(['a,"'], [['a', '']])
258 self._read_test(['"a'], [['a']])
259 self._read_test(['^'], [['\n']], escapechar='^')
260 self.assertRaises(csv.Error, self._read_test, ['a,"'], [], strict=True)
261 self.assertRaises(csv.Error, self._read_test, ['"a'], [], strict=True)
262 self.assertRaises(csv.Error, self._read_test,
263 ['^'], [], escapechar='^', strict=True)
264
Skip Montanarob4a04172003-03-20 23:29:12 +0000265 def test_read_escape(self):
Andrew McNamara36a76912005-01-10 01:04:40 +0000266 self._read_test(['a,\\b,c'], [['a', 'b', 'c']], escapechar='\\')
Skip Montanarob4a04172003-03-20 23:29:12 +0000267 self._read_test(['a,b\\,c'], [['a', 'b,c']], escapechar='\\')
268 self._read_test(['a,"b\\,c"'], [['a', 'b,c']], escapechar='\\')
Andrew McNamara36a76912005-01-10 01:04:40 +0000269 self._read_test(['a,"b,\\c"'], [['a', 'b,c']], escapechar='\\')
Skip Montanarob4a04172003-03-20 23:29:12 +0000270 self._read_test(['a,"b,c\\""'], [['a', 'b,c"']], escapechar='\\')
271 self._read_test(['a,"b,c"\\'], [['a', 'b,c\\']], escapechar='\\')
272
Andrew McNamara1196cf12005-01-07 04:42:45 +0000273 def test_read_quoting(self):
274 self._read_test(['1,",3,",5'], [['1', ',3,', '5']])
275 self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
276 quotechar=None, escapechar='\\')
277 self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
278 quoting=csv.QUOTE_NONE, escapechar='\\')
Andrew McNamara0f0599d2005-01-12 09:45:18 +0000279 # will this fail where locale uses comma for decimals?
Andrew McNamara7f2053e2005-01-12 11:17:16 +0000280 self._read_test([',3,"5",7.3, 9'], [['', 3, '5', 7.3, 9]],
Andrew McNamara0f0599d2005-01-12 09:45:18 +0000281 quoting=csv.QUOTE_NONNUMERIC)
R. David Murray38644592009-04-01 21:26:18 +0000282 self._read_test(['"a\nb", 7'], [['a\nb', ' 7']])
Tim Peters608c2ff2005-01-13 17:37:38 +0000283 self.assertRaises(ValueError, self._read_test,
Andrew McNamara0f0599d2005-01-12 09:45:18 +0000284 ['abc,3'], [[]],
285 quoting=csv.QUOTE_NONNUMERIC)
Andrew McNamara1196cf12005-01-07 04:42:45 +0000286
Skip Montanarob4a04172003-03-20 23:29:12 +0000287 def test_read_bigfield(self):
Andrew McNamarae4d05c42005-01-11 07:32:02 +0000288 # This exercises the buffer realloc functionality and field size
289 # limits.
Andrew McNamara31d88962005-01-12 03:45:10 +0000290 limit = csv.field_size_limit()
Andrew McNamaraaf1e3122005-01-12 01:55:21 +0000291 try:
292 size = 50000
293 bigstring = 'X' * size
294 bigline = '%s,%s' % (bigstring, bigstring)
295 self._read_test([bigline], [[bigstring, bigstring]])
Andrew McNamara31d88962005-01-12 03:45:10 +0000296 csv.field_size_limit(size)
Andrew McNamaraaf1e3122005-01-12 01:55:21 +0000297 self._read_test([bigline], [[bigstring, bigstring]])
Andrew McNamara31d88962005-01-12 03:45:10 +0000298 self.assertEqual(csv.field_size_limit(), size)
299 csv.field_size_limit(size-1)
Andrew McNamaraaf1e3122005-01-12 01:55:21 +0000300 self.assertRaises(csv.Error, self._read_test, [bigline], [])
Andrew McNamara31d88962005-01-12 03:45:10 +0000301 self.assertRaises(TypeError, csv.field_size_limit, None)
302 self.assertRaises(TypeError, csv.field_size_limit, 1, None)
Andrew McNamaraaf1e3122005-01-12 01:55:21 +0000303 finally:
Andrew McNamara31d88962005-01-12 03:45:10 +0000304 csv.field_size_limit(limit)
Skip Montanarob4a04172003-03-20 23:29:12 +0000305
Andrew McNamara7f2053e2005-01-12 11:17:16 +0000306 def test_read_linenum(self):
Georg Brandl77354cf2008-03-21 20:01:51 +0000307 for r in (csv.reader(['line,1', 'line,2', 'line,3']),
308 csv.DictReader(['line,1', 'line,2', 'line,3'],
309 fieldnames=['a', 'b', 'c'])):
310 self.assertEqual(r.line_num, 0)
311 r.next()
312 self.assertEqual(r.line_num, 1)
313 r.next()
314 self.assertEqual(r.line_num, 2)
315 r.next()
316 self.assertEqual(r.line_num, 3)
317 self.assertRaises(StopIteration, r.next)
318 self.assertEqual(r.line_num, 3)
Andrew McNamara7f2053e2005-01-12 11:17:16 +0000319
R. David Murray38644592009-04-01 21:26:18 +0000320 def test_roundtrip_quoteed_newlines(self):
321 fd, name = tempfile.mkstemp()
322 fileobj = os.fdopen(fd, "w+b")
323 try:
324 writer = csv.writer(fileobj)
325 self.assertRaises(TypeError, writer.writerows, None)
326 rows = [['a\nb','b'],['c','x\r\nd']]
327 writer.writerows(rows)
328 fileobj.seek(0)
329 for i, row in enumerate(csv.reader(fileobj)):
330 self.assertEqual(row, rows[i])
331 finally:
332 fileobj.close()
333 os.unlink(name)
334
Skip Montanarob4a04172003-03-20 23:29:12 +0000335class TestDialectRegistry(unittest.TestCase):
336 def test_registry_badargs(self):
337 self.assertRaises(TypeError, csv.list_dialects, None)
338 self.assertRaises(TypeError, csv.get_dialect)
339 self.assertRaises(csv.Error, csv.get_dialect, None)
340 self.assertRaises(csv.Error, csv.get_dialect, "nonesuch")
341 self.assertRaises(TypeError, csv.unregister_dialect)
342 self.assertRaises(csv.Error, csv.unregister_dialect, None)
343 self.assertRaises(csv.Error, csv.unregister_dialect, "nonesuch")
344 self.assertRaises(TypeError, csv.register_dialect, None)
345 self.assertRaises(TypeError, csv.register_dialect, None, None)
Andrew McNamaraaf1e3122005-01-12 01:55:21 +0000346 self.assertRaises(TypeError, csv.register_dialect, "nonesuch", 0, 0)
347 self.assertRaises(TypeError, csv.register_dialect, "nonesuch",
348 badargument=None)
349 self.assertRaises(TypeError, csv.register_dialect, "nonesuch",
350 quoting=None)
351 self.assertRaises(TypeError, csv.register_dialect, [])
Skip Montanarob4a04172003-03-20 23:29:12 +0000352
353 def test_registry(self):
354 class myexceltsv(csv.excel):
355 delimiter = "\t"
356 name = "myexceltsv"
357 expected_dialects = csv.list_dialects() + [name]
358 expected_dialects.sort()
359 csv.register_dialect(name, myexceltsv)
Éric Araujod11058d2010-12-02 22:35:10 +0000360 self.addCleanup(csv.unregister_dialect, name)
361 self.assertEqual(csv.get_dialect(name).delimiter, '\t')
362 got_dialects = sorted(csv.list_dialects())
363 self.assertEqual(expected_dialects, got_dialects)
Skip Montanarob4a04172003-03-20 23:29:12 +0000364
Andrew McNamara86625972005-01-11 01:28:33 +0000365 def test_register_kwargs(self):
366 name = 'fedcba'
367 csv.register_dialect(name, delimiter=';')
Éric Araujod11058d2010-12-02 22:35:10 +0000368 self.addCleanup(csv.unregister_dialect, name)
369 self.assertEqual(csv.get_dialect(name).delimiter, ';')
370 self.assertEqual([['X', 'Y', 'Z']], list(csv.reader(['X;Y;Z'], name)))
Andrew McNamara86625972005-01-11 01:28:33 +0000371
Skip Montanarob4a04172003-03-20 23:29:12 +0000372 def test_incomplete_dialect(self):
373 class myexceltsv(csv.Dialect):
374 delimiter = "\t"
375 self.assertRaises(csv.Error, myexceltsv)
376
377 def test_space_dialect(self):
378 class space(csv.excel):
379 delimiter = " "
380 quoting = csv.QUOTE_NONE
381 escapechar = "\\"
382
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000383 fd, name = tempfile.mkstemp()
384 fileobj = os.fdopen(fd, "w+b")
385 try:
386 fileobj.write("abc def\nc1ccccc1 benzene\n")
387 fileobj.seek(0)
388 rdr = csv.reader(fileobj, dialect=space())
389 self.assertEqual(rdr.next(), ["abc", "def"])
390 self.assertEqual(rdr.next(), ["c1ccccc1", "benzene"])
391 finally:
392 fileobj.close()
393 os.unlink(name)
Tim Peters27f88362004-07-08 04:22:35 +0000394
Skip Montanarob4a04172003-03-20 23:29:12 +0000395 def test_dialect_apply(self):
396 class testA(csv.excel):
397 delimiter = "\t"
398 class testB(csv.excel):
399 delimiter = ":"
400 class testC(csv.excel):
401 delimiter = "|"
402
403 csv.register_dialect('testC', testC)
404 try:
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000405 fd, name = tempfile.mkstemp()
406 fileobj = os.fdopen(fd, "w+b")
407 try:
408 writer = csv.writer(fileobj)
409 writer.writerow([1,2,3])
410 fileobj.seek(0)
411 self.assertEqual(fileobj.read(), "1,2,3\r\n")
412 finally:
413 fileobj.close()
414 os.unlink(name)
Tim Peters27f88362004-07-08 04:22:35 +0000415
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000416 fd, name = tempfile.mkstemp()
417 fileobj = os.fdopen(fd, "w+b")
418 try:
419 writer = csv.writer(fileobj, testA)
420 writer.writerow([1,2,3])
421 fileobj.seek(0)
422 self.assertEqual(fileobj.read(), "1\t2\t3\r\n")
423 finally:
424 fileobj.close()
425 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000426
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000427 fd, name = tempfile.mkstemp()
428 fileobj = os.fdopen(fd, "w+b")
429 try:
430 writer = csv.writer(fileobj, dialect=testB())
431 writer.writerow([1,2,3])
432 fileobj.seek(0)
433 self.assertEqual(fileobj.read(), "1:2:3\r\n")
434 finally:
435 fileobj.close()
436 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000437
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000438 fd, name = tempfile.mkstemp()
439 fileobj = os.fdopen(fd, "w+b")
440 try:
441 writer = csv.writer(fileobj, dialect='testC')
442 writer.writerow([1,2,3])
443 fileobj.seek(0)
444 self.assertEqual(fileobj.read(), "1|2|3\r\n")
445 finally:
446 fileobj.close()
447 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000448
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000449 fd, name = tempfile.mkstemp()
450 fileobj = os.fdopen(fd, "w+b")
451 try:
452 writer = csv.writer(fileobj, dialect=testA, delimiter=';')
453 writer.writerow([1,2,3])
454 fileobj.seek(0)
455 self.assertEqual(fileobj.read(), "1;2;3\r\n")
456 finally:
457 fileobj.close()
458 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000459
Skip Montanarob4a04172003-03-20 23:29:12 +0000460 finally:
461 csv.unregister_dialect('testC')
462
463 def test_bad_dialect(self):
464 # Unknown parameter
Andrew McNamara1196cf12005-01-07 04:42:45 +0000465 self.assertRaises(TypeError, csv.reader, [], bad_attr = 0)
Skip Montanarob4a04172003-03-20 23:29:12 +0000466 # Bad values
467 self.assertRaises(TypeError, csv.reader, [], delimiter = None)
468 self.assertRaises(TypeError, csv.reader, [], quoting = -1)
469 self.assertRaises(TypeError, csv.reader, [], quoting = 100)
470
Barry Warsaw8da40232016-01-11 14:49:34 -0500471 # See issue #22995
472 ## def test_copy(self):
473 ## for name in csv.list_dialects():
474 ## dialect = csv.get_dialect(name)
475 ## self.assertRaises(TypeError, copy.copy, dialect)
Serhiy Storchakab8e54dd2015-12-30 20:43:29 +0200476
Barry Warsaw8da40232016-01-11 14:49:34 -0500477 ## def test_pickle(self):
478 ## for name in csv.list_dialects():
479 ## dialect = csv.get_dialect(name)
480 ## for proto in range(pickle.HIGHEST_PROTOCOL + 1):
481 ## self.assertRaises(TypeError, pickle.dumps, dialect, proto)
Serhiy Storchakab8e54dd2015-12-30 20:43:29 +0200482
Skip Montanarob4a04172003-03-20 23:29:12 +0000483class TestCsvBase(unittest.TestCase):
484 def readerAssertEqual(self, input, expected_result):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000485 fd, name = tempfile.mkstemp()
486 fileobj = os.fdopen(fd, "w+b")
487 try:
488 fileobj.write(input)
489 fileobj.seek(0)
490 reader = csv.reader(fileobj, dialect = self.dialect)
491 fields = list(reader)
492 self.assertEqual(fields, expected_result)
493 finally:
494 fileobj.close()
495 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000496
497 def writerAssertEqual(self, input, expected_result):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000498 fd, name = tempfile.mkstemp()
499 fileobj = os.fdopen(fd, "w+b")
500 try:
501 writer = csv.writer(fileobj, dialect = self.dialect)
502 writer.writerows(input)
503 fileobj.seek(0)
504 self.assertEqual(fileobj.read(), expected_result)
505 finally:
506 fileobj.close()
507 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000508
509class TestDialectExcel(TestCsvBase):
510 dialect = 'excel'
511
512 def test_single(self):
513 self.readerAssertEqual('abc', [['abc']])
514
515 def test_simple(self):
516 self.readerAssertEqual('1,2,3,4,5', [['1','2','3','4','5']])
517
518 def test_blankline(self):
519 self.readerAssertEqual('', [])
520
521 def test_empty_fields(self):
522 self.readerAssertEqual(',', [['', '']])
523
524 def test_singlequoted(self):
525 self.readerAssertEqual('""', [['']])
526
527 def test_singlequoted_left_empty(self):
528 self.readerAssertEqual('"",', [['','']])
529
530 def test_singlequoted_right_empty(self):
531 self.readerAssertEqual(',""', [['','']])
532
533 def test_single_quoted_quote(self):
534 self.readerAssertEqual('""""', [['"']])
535
536 def test_quoted_quotes(self):
537 self.readerAssertEqual('""""""', [['""']])
538
539 def test_inline_quote(self):
540 self.readerAssertEqual('a""b', [['a""b']])
541
542 def test_inline_quotes(self):
543 self.readerAssertEqual('a"b"c', [['a"b"c']])
544
545 def test_quotes_and_more(self):
Skip Montanaro9cea8e52007-03-12 03:30:50 +0000546 # Excel would never write a field containing '"a"b', but when
547 # reading one, it will return 'ab'.
Skip Montanarob4a04172003-03-20 23:29:12 +0000548 self.readerAssertEqual('"a"b', [['ab']])
549
550 def test_lone_quote(self):
551 self.readerAssertEqual('a"b', [['a"b']])
552
553 def test_quote_and_quote(self):
Skip Montanaro9cea8e52007-03-12 03:30:50 +0000554 # Excel would never write a field containing '"a" "b"', but when
555 # reading one, it will return 'a "b"'.
Skip Montanarob4a04172003-03-20 23:29:12 +0000556 self.readerAssertEqual('"a" "b"', [['a "b"']])
557
558 def test_space_and_quote(self):
559 self.readerAssertEqual(' "a"', [[' "a"']])
560
561 def test_quoted(self):
Tim Peters0eadaac2003-04-24 16:02:54 +0000562 self.readerAssertEqual('1,2,3,"I think, therefore I am",5,6',
563 [['1', '2', '3',
564 'I think, therefore I am',
Skip Montanarob4a04172003-03-20 23:29:12 +0000565 '5', '6']])
566
567 def test_quoted_quote(self):
568 self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"',
Tim Peters0eadaac2003-04-24 16:02:54 +0000569 [['1', '2', '3',
570 '"I see," said the blind man',
Skip Montanarob4a04172003-03-20 23:29:12 +0000571 'as he picked up his hammer and saw']])
572
573 def test_quoted_nl(self):
574 input = '''\
5751,2,3,"""I see,""
576said the blind man","as he picked up his
577hammer and saw"
5789,8,7,6'''
579 self.readerAssertEqual(input,
Tim Peters0eadaac2003-04-24 16:02:54 +0000580 [['1', '2', '3',
581 '"I see,"\nsaid the blind man',
Skip Montanarob4a04172003-03-20 23:29:12 +0000582 'as he picked up his\nhammer and saw'],
583 ['9','8','7','6']])
584
585 def test_dubious_quote(self):
586 self.readerAssertEqual('12,12,1",', [['12', '12', '1"', '']])
587
588 def test_null(self):
589 self.writerAssertEqual([], '')
590
Georg Brandl41dc63f2010-02-07 12:25:50 +0000591 def test_single_writer(self):
Skip Montanarob4a04172003-03-20 23:29:12 +0000592 self.writerAssertEqual([['abc']], 'abc\r\n')
593
Georg Brandl41dc63f2010-02-07 12:25:50 +0000594 def test_simple_writer(self):
Skip Montanarob4a04172003-03-20 23:29:12 +0000595 self.writerAssertEqual([[1, 2, 'abc', 3, 4]], '1,2,abc,3,4\r\n')
596
597 def test_quotes(self):
598 self.writerAssertEqual([[1, 2, 'a"bc"', 3, 4]], '1,2,"a""bc""",3,4\r\n')
599
600 def test_quote_fieldsep(self):
601 self.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
602
603 def test_newlines(self):
604 self.writerAssertEqual([[1, 2, 'a\nbc', 3, 4]], '1,2,"a\nbc",3,4\r\n')
605
606class EscapedExcel(csv.excel):
607 quoting = csv.QUOTE_NONE
608 escapechar = '\\'
609
610class TestEscapedExcel(TestCsvBase):
611 dialect = EscapedExcel()
612
613 def test_escape_fieldsep(self):
614 self.writerAssertEqual([['abc,def']], 'abc\\,def\r\n')
615
616 def test_read_escape_fieldsep(self):
617 self.readerAssertEqual('abc\\,def\r\n', [['abc,def']])
618
619class QuotedEscapedExcel(csv.excel):
620 quoting = csv.QUOTE_NONNUMERIC
621 escapechar = '\\'
622
623class TestQuotedEscapedExcel(TestCsvBase):
624 dialect = QuotedEscapedExcel()
625
626 def test_write_escape_fieldsep(self):
627 self.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
628
629 def test_read_escape_fieldsep(self):
630 self.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']])
631
Skip Montanarob4a04172003-03-20 23:29:12 +0000632class TestDictFields(unittest.TestCase):
633 ### "long" means the row is longer than the number of fieldnames
634 ### "short" means there are fewer elements in the row than fieldnames
635 def test_write_simple_dict(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000636 fd, name = tempfile.mkstemp()
Dirkjan Ochtman19c9b602010-03-04 19:21:53 +0000637 fileobj = io.open(fd, 'w+b')
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000638 try:
639 writer = csv.DictWriter(fileobj, fieldnames = ["f1", "f2", "f3"])
Dirkjan Ochtman86148172010-02-23 21:09:52 +0000640 writer.writeheader()
641 fileobj.seek(0)
642 self.assertEqual(fileobj.readline(), "f1,f2,f3\r\n")
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000643 writer.writerow({"f1": 10, "f3": "abc"})
644 fileobj.seek(0)
Dirkjan Ochtman86148172010-02-23 21:09:52 +0000645 fileobj.readline() # header
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000646 self.assertEqual(fileobj.read(), "10,,abc\r\n")
647 finally:
648 fileobj.close()
649 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000650
651 def test_write_no_fields(self):
652 fileobj = StringIO()
653 self.assertRaises(TypeError, csv.DictWriter, fileobj)
654
R David Murrayeccf9c22013-11-19 13:25:24 -0500655 def test_write_fields_not_in_fieldnames(self):
656 fd, name = tempfile.mkstemp()
657 fileobj = os.fdopen(fd, "w+b")
658 try:
659 writer = csv.DictWriter(fileobj, fieldnames = ["f1", "f2", "f3"])
660 # Of special note is the non-string key (issue 19449)
661 with self.assertRaises(ValueError) as cx:
662 writer.writerow({"f4": 10, "f2": "spam", 1: "abc"})
663 exception = str(cx.exception)
664 self.assertIn("fieldnames", exception)
665 self.assertIn("'f4'", exception)
666 self.assertNotIn("'f2'", exception)
667 self.assertIn("1", exception)
668 finally:
669 fileobj.close()
670 os.unlink(name)
671
Skip Montanarob4a04172003-03-20 23:29:12 +0000672 def test_read_dict_fields(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000673 fd, name = tempfile.mkstemp()
674 fileobj = os.fdopen(fd, "w+b")
675 try:
676 fileobj.write("1,2,abc\r\n")
677 fileobj.seek(0)
678 reader = csv.DictReader(fileobj,
679 fieldnames=["f1", "f2", "f3"])
680 self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
681 finally:
682 fileobj.close()
683 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000684
Skip Montanarodffeed32003-10-03 14:03:01 +0000685 def test_read_dict_no_fieldnames(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000686 fd, name = tempfile.mkstemp()
687 fileobj = os.fdopen(fd, "w+b")
688 try:
689 fileobj.write("f1,f2,f3\r\n1,2,abc\r\n")
690 fileobj.seek(0)
691 reader = csv.DictReader(fileobj)
Skip Montanaroa032bf42008-08-08 22:52:51 +0000692 self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000693 self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
694 finally:
695 fileobj.close()
696 os.unlink(name)
Skip Montanarodffeed32003-10-03 14:03:01 +0000697
Skip Montanaroa032bf42008-08-08 22:52:51 +0000698 # Two test cases to make sure existing ways of implicitly setting
699 # fieldnames continue to work. Both arise from discussion in issue3436.
700 def test_read_dict_fieldnames_from_file(self):
701 fd, name = tempfile.mkstemp()
702 f = os.fdopen(fd, "w+b")
703 try:
704 f.write("f1,f2,f3\r\n1,2,abc\r\n")
705 f.seek(0)
706 reader = csv.DictReader(f, fieldnames=csv.reader(f).next())
707 self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
708 self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
709 finally:
710 f.close()
711 os.unlink(name)
712
713 def test_read_dict_fieldnames_chain(self):
714 import itertools
715 fd, name = tempfile.mkstemp()
716 f = os.fdopen(fd, "w+b")
717 try:
718 f.write("f1,f2,f3\r\n1,2,abc\r\n")
719 f.seek(0)
720 reader = csv.DictReader(f)
721 first = next(reader)
722 for row in itertools.chain([first], reader):
723 self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
724 self.assertEqual(row, {"f1": '1', "f2": '2', "f3": 'abc'})
725 finally:
726 f.close()
727 os.unlink(name)
728
Skip Montanarob4a04172003-03-20 23:29:12 +0000729 def test_read_long(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000730 fd, name = tempfile.mkstemp()
731 fileobj = os.fdopen(fd, "w+b")
732 try:
733 fileobj.write("1,2,abc,4,5,6\r\n")
734 fileobj.seek(0)
735 reader = csv.DictReader(fileobj,
736 fieldnames=["f1", "f2"])
737 self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
738 None: ["abc", "4", "5", "6"]})
739 finally:
740 fileobj.close()
741 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000742
743 def test_read_long_with_rest(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000744 fd, name = tempfile.mkstemp()
745 fileobj = os.fdopen(fd, "w+b")
746 try:
747 fileobj.write("1,2,abc,4,5,6\r\n")
748 fileobj.seek(0)
749 reader = csv.DictReader(fileobj,
750 fieldnames=["f1", "f2"], restkey="_rest")
751 self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
752 "_rest": ["abc", "4", "5", "6"]})
753 finally:
754 fileobj.close()
755 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000756
Skip Montanarodffeed32003-10-03 14:03:01 +0000757 def test_read_long_with_rest_no_fieldnames(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000758 fd, name = tempfile.mkstemp()
759 fileobj = os.fdopen(fd, "w+b")
760 try:
761 fileobj.write("f1,f2\r\n1,2,abc,4,5,6\r\n")
762 fileobj.seek(0)
763 reader = csv.DictReader(fileobj, restkey="_rest")
Skip Montanaroa032bf42008-08-08 22:52:51 +0000764 self.assertEqual(reader.fieldnames, ["f1", "f2"])
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000765 self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
766 "_rest": ["abc", "4", "5", "6"]})
767 finally:
768 fileobj.close()
769 os.unlink(name)
Skip Montanarodffeed32003-10-03 14:03:01 +0000770
Skip Montanarob4a04172003-03-20 23:29:12 +0000771 def test_read_short(self):
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000772 fd, name = tempfile.mkstemp()
773 fileobj = os.fdopen(fd, "w+b")
774 try:
775 fileobj.write("1,2,abc,4,5,6\r\n1,2,abc\r\n")
776 fileobj.seek(0)
777 reader = csv.DictReader(fileobj,
778 fieldnames="1 2 3 4 5 6".split(),
779 restval="DEFAULT")
780 self.assertEqual(reader.next(), {"1": '1', "2": '2', "3": 'abc',
781 "4": '4', "5": '5', "6": '6'})
782 self.assertEqual(reader.next(), {"1": '1', "2": '2', "3": 'abc',
783 "4": 'DEFAULT', "5": 'DEFAULT',
784 "6": 'DEFAULT'})
785 finally:
786 fileobj.close()
787 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000788
Skip Montanaro1546bc42003-06-12 02:40:22 +0000789 def test_read_multi(self):
790 sample = [
791 '2147483648,43.0e12,17,abc,def\r\n',
792 '147483648,43.0e2,17,abc,def\r\n',
793 '47483648,43.0,170,abc,def\r\n'
794 ]
795
796 reader = csv.DictReader(sample,
797 fieldnames="i1 float i2 s1 s2".split())
798 self.assertEqual(reader.next(), {"i1": '2147483648',
799 "float": '43.0e12',
800 "i2": '17',
801 "s1": 'abc',
802 "s2": 'def'})
803
Skip Montanarob4a04172003-03-20 23:29:12 +0000804 def test_read_with_blanks(self):
805 reader = csv.DictReader(["1,2,abc,4,5,6\r\n","\r\n",
806 "1,2,abc,4,5,6\r\n"],
807 fieldnames="1 2 3 4 5 6".split())
808 self.assertEqual(reader.next(), {"1": '1', "2": '2', "3": 'abc',
809 "4": '4', "5": '5', "6": '6'})
810 self.assertEqual(reader.next(), {"1": '1', "2": '2', "3": 'abc',
811 "4": '4', "5": '5', "6": '6'})
812
Skip Montanaro3f7a9482003-09-06 19:52:12 +0000813 def test_read_semi_sep(self):
814 reader = csv.DictReader(["1;2;abc;4;5;6\r\n"],
815 fieldnames="1 2 3 4 5 6".split(),
816 delimiter=';')
817 self.assertEqual(reader.next(), {"1": '1', "2": '2', "3": 'abc',
818 "4": '4', "5": '5', "6": '6'})
819
Skip Montanarob4a04172003-03-20 23:29:12 +0000820class TestArrayWrites(unittest.TestCase):
821 def test_int_write(self):
822 import array
823 contents = [(20-i) for i in range(20)]
824 a = array.array('i', contents)
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000825
826 fd, name = tempfile.mkstemp()
827 fileobj = os.fdopen(fd, "w+b")
828 try:
829 writer = csv.writer(fileobj, dialect="excel")
830 writer.writerow(a)
831 expected = ",".join([str(i) for i in a])+"\r\n"
832 fileobj.seek(0)
833 self.assertEqual(fileobj.read(), expected)
834 finally:
835 fileobj.close()
836 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000837
838 def test_double_write(self):
839 import array
840 contents = [(20-i)*0.1 for i in range(20)]
841 a = array.array('d', contents)
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000842 fd, name = tempfile.mkstemp()
843 fileobj = os.fdopen(fd, "w+b")
844 try:
845 writer = csv.writer(fileobj, dialect="excel")
846 writer.writerow(a)
Raymond Hettingerf5377022011-12-11 22:31:09 -0800847 expected = ",".join([repr(i) for i in a])+"\r\n"
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000848 fileobj.seek(0)
849 self.assertEqual(fileobj.read(), expected)
850 finally:
851 fileobj.close()
852 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000853
854 def test_float_write(self):
855 import array
856 contents = [(20-i)*0.1 for i in range(20)]
857 a = array.array('f', contents)
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000858 fd, name = tempfile.mkstemp()
859 fileobj = os.fdopen(fd, "w+b")
860 try:
861 writer = csv.writer(fileobj, dialect="excel")
862 writer.writerow(a)
Raymond Hettingerf5377022011-12-11 22:31:09 -0800863 expected = ",".join([repr(i) for i in a])+"\r\n"
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000864 fileobj.seek(0)
865 self.assertEqual(fileobj.read(), expected)
866 finally:
867 fileobj.close()
868 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000869
870 def test_char_write(self):
871 import array, string
872 a = array.array('c', string.letters)
Skip Montanaro58fc5d02004-06-05 17:03:20 +0000873 fd, name = tempfile.mkstemp()
874 fileobj = os.fdopen(fd, "w+b")
875 try:
876 writer = csv.writer(fileobj, dialect="excel")
877 writer.writerow(a)
878 expected = ",".join(a)+"\r\n"
879 fileobj.seek(0)
880 self.assertEqual(fileobj.read(), expected)
881 finally:
882 fileobj.close()
883 os.unlink(name)
Skip Montanarob4a04172003-03-20 23:29:12 +0000884
885class TestDialectValidity(unittest.TestCase):
886 def test_quoting(self):
887 class mydialect(csv.Dialect):
888 delimiter = ";"
889 escapechar = '\\'
890 doublequote = False
891 skipinitialspace = True
892 lineterminator = '\r\n'
893 quoting = csv.QUOTE_NONE
894 d = mydialect()
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200895 self.assertEqual(d.quoting, csv.QUOTE_NONE)
Skip Montanarob4a04172003-03-20 23:29:12 +0000896
897 mydialect.quoting = None
898 self.assertRaises(csv.Error, mydialect)
899
Skip Montanarob4a04172003-03-20 23:29:12 +0000900 mydialect.doublequote = True
901 mydialect.quoting = csv.QUOTE_ALL
902 mydialect.quotechar = '"'
903 d = mydialect()
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200904 self.assertEqual(d.quoting, csv.QUOTE_ALL)
905 self.assertEqual(d.quotechar, '"')
906 self.assertTrue(d.doublequote)
Skip Montanarob4a04172003-03-20 23:29:12 +0000907
908 mydialect.quotechar = "''"
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200909 with self.assertRaises(csv.Error) as cm:
910 mydialect()
911 self.assertEqual(str(cm.exception),
912 '"quotechar" must be an 1-character string')
Skip Montanarob4a04172003-03-20 23:29:12 +0000913
914 mydialect.quotechar = 4
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200915 with self.assertRaises(csv.Error) as cm:
916 mydialect()
917 self.assertEqual(str(cm.exception),
918 '"quotechar" must be string, not int')
Skip Montanarob4a04172003-03-20 23:29:12 +0000919
920 def test_delimiter(self):
921 class mydialect(csv.Dialect):
922 delimiter = ";"
923 escapechar = '\\'
924 doublequote = False
925 skipinitialspace = True
926 lineterminator = '\r\n'
927 quoting = csv.QUOTE_NONE
928 d = mydialect()
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200929 self.assertEqual(d.delimiter, ";")
Skip Montanarob4a04172003-03-20 23:29:12 +0000930
931 mydialect.delimiter = ":::"
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200932 with self.assertRaises(csv.Error) as cm:
933 mydialect()
934 self.assertEqual(str(cm.exception),
935 '"delimiter" must be an 1-character string')
936
937 mydialect.delimiter = ""
938 with self.assertRaises(csv.Error) as cm:
939 mydialect()
940 self.assertEqual(str(cm.exception),
941 '"delimiter" must be an 1-character string')
942
943 mydialect.delimiter = u","
944 with self.assertRaises(csv.Error) as cm:
945 mydialect()
946 self.assertEqual(str(cm.exception),
947 '"delimiter" must be string, not unicode')
Skip Montanarob4a04172003-03-20 23:29:12 +0000948
949 mydialect.delimiter = 4
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200950 with self.assertRaises(csv.Error) as cm:
951 mydialect()
952 self.assertEqual(str(cm.exception),
953 '"delimiter" must be string, not int')
Skip Montanarob4a04172003-03-20 23:29:12 +0000954
955 def test_lineterminator(self):
956 class mydialect(csv.Dialect):
957 delimiter = ";"
958 escapechar = '\\'
959 doublequote = False
960 skipinitialspace = True
961 lineterminator = '\r\n'
962 quoting = csv.QUOTE_NONE
963 d = mydialect()
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200964 self.assertEqual(d.lineterminator, '\r\n')
Skip Montanarob4a04172003-03-20 23:29:12 +0000965
966 mydialect.lineterminator = ":::"
967 d = mydialect()
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200968 self.assertEqual(d.lineterminator, ":::")
Skip Montanarob4a04172003-03-20 23:29:12 +0000969
970 mydialect.lineterminator = 4
Serhiy Storchaka0c221be2013-12-19 16:26:56 +0200971 with self.assertRaises(csv.Error) as cm:
972 mydialect()
973 self.assertEqual(str(cm.exception),
974 '"lineterminator" must be a string')
Skip Montanarob4a04172003-03-20 23:29:12 +0000975
976
Skip Montanaro48816c62003-04-25 14:43:14 +0000977class TestSniffer(unittest.TestCase):
978 sample1 = """\
979Harry's, Arlington Heights, IL, 2/1/03, Kimi Hayes
980Shark City, Glendale Heights, IL, 12/28/02, Prezence
981Tommy's Place, Blue Island, IL, 12/28/02, Blue Sunday/White Crow
982Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
983"""
984 sample2 = """\
985'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes'
986'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence'
987'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow'
Skip Montanarob4fd4d32009-09-28 02:12:27 +0000988'Stonecutters ''Seafood'' and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
Skip Montanaro48816c62003-04-25 14:43:14 +0000989"""
R David Murray24dc7532013-06-29 18:43:59 -0400990 header1 = '''\
Skip Montanaro48816c62003-04-25 14:43:14 +0000991"venue","city","state","date","performers"
992'''
Skip Montanaro77892372003-05-19 15:33:36 +0000993 sample3 = '''\
99405/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
99505/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
99605/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
997'''
998
Skip Montanaro1546bc42003-06-12 02:40:22 +0000999 sample4 = '''\
10002147483648;43.0e12;17;abc;def
1001147483648;43.0e2;17;abc;def
100247483648;43.0;170;abc;def
1003'''
1004
Skip Montanaro91bb70c2005-12-28 15:37:25 +00001005 sample5 = "aaa\tbbb\r\nAAA\t\r\nBBB\t\r\n"
Skip Montanaro39b29be2005-12-30 05:09:48 +00001006 sample6 = "a|b|c\r\nd|e|f\r\n"
1007 sample7 = "'a'|'b'|'c'\r\n'd'|e|f\r\n"
Skip Montanaro91bb70c2005-12-28 15:37:25 +00001008
R David Murray24dc7532013-06-29 18:43:59 -04001009# Issue 18155: Use a delimiter that is a special char to regex:
1010
1011 header2 = '''\
1012"venue"+"city"+"state"+"date"+"performers"
1013'''
1014 sample8 = """\
1015Harry's+ Arlington Heights+ IL+ 2/1/03+ Kimi Hayes
1016Shark City+ Glendale Heights+ IL+ 12/28/02+ Prezence
1017Tommy's Place+ Blue Island+ IL+ 12/28/02+ Blue Sunday/White Crow
1018Stonecutters Seafood and Chop House+ Lemont+ IL+ 12/19/02+ Week Back
1019"""
1020 sample9 = """\
1021'Harry''s'+ Arlington Heights'+ 'IL'+ '2/1/03'+ 'Kimi Hayes'
1022'Shark City'+ Glendale Heights'+' IL'+ '12/28/02'+ 'Prezence'
1023'Tommy''s Place'+ Blue Island'+ 'IL'+ '12/28/02'+ 'Blue Sunday/White Crow'
1024'Stonecutters ''Seafood'' and Chop House'+ 'Lemont'+ 'IL'+ '12/19/02'+ 'Week Back'
1025"""
1026
Skip Montanaro48816c62003-04-25 14:43:14 +00001027 def test_has_header(self):
1028 sniffer = csv.Sniffer()
1029 self.assertEqual(sniffer.has_header(self.sample1), False)
R David Murray24dc7532013-06-29 18:43:59 -04001030 self.assertEqual(sniffer.has_header(self.header1 + self.sample1),
1031 True)
1032
1033 def test_has_header_regex_special_delimiter(self):
1034 sniffer = csv.Sniffer()
1035 self.assertEqual(sniffer.has_header(self.sample8), False)
1036 self.assertEqual(sniffer.has_header(self.header2 + self.sample8),
1037 True)
Skip Montanaro48816c62003-04-25 14:43:14 +00001038
1039 def test_sniff(self):
1040 sniffer = csv.Sniffer()
1041 dialect = sniffer.sniff(self.sample1)
1042 self.assertEqual(dialect.delimiter, ",")
1043 self.assertEqual(dialect.quotechar, '"')
1044 self.assertEqual(dialect.skipinitialspace, True)
1045
1046 dialect = sniffer.sniff(self.sample2)
1047 self.assertEqual(dialect.delimiter, ":")
1048 self.assertEqual(dialect.quotechar, "'")
1049 self.assertEqual(dialect.skipinitialspace, False)
1050
Skip Montanaro77892372003-05-19 15:33:36 +00001051 def test_delimiters(self):
1052 sniffer = csv.Sniffer()
1053 dialect = sniffer.sniff(self.sample3)
Armin Rigoa3f09272006-05-28 19:13:17 +00001054 # given that all three lines in sample3 are equal,
1055 # I think that any character could have been 'guessed' as the
1056 # delimiter, depending on dictionary order
Ezio Melottiaa980582010-01-23 23:04:36 +00001057 self.assertIn(dialect.delimiter, self.sample3)
Skip Montanaro77892372003-05-19 15:33:36 +00001058 dialect = sniffer.sniff(self.sample3, delimiters="?,")
1059 self.assertEqual(dialect.delimiter, "?")
1060 dialect = sniffer.sniff(self.sample3, delimiters="/,")
1061 self.assertEqual(dialect.delimiter, "/")
Skip Montanaro1546bc42003-06-12 02:40:22 +00001062 dialect = sniffer.sniff(self.sample4)
1063 self.assertEqual(dialect.delimiter, ";")
Skip Montanaro91bb70c2005-12-28 15:37:25 +00001064 dialect = sniffer.sniff(self.sample5)
1065 self.assertEqual(dialect.delimiter, "\t")
Skip Montanaro39b29be2005-12-30 05:09:48 +00001066 dialect = sniffer.sniff(self.sample6)
1067 self.assertEqual(dialect.delimiter, "|")
1068 dialect = sniffer.sniff(self.sample7)
1069 self.assertEqual(dialect.delimiter, "|")
1070 self.assertEqual(dialect.quotechar, "'")
R David Murray24dc7532013-06-29 18:43:59 -04001071 dialect = sniffer.sniff(self.sample8)
1072 self.assertEqual(dialect.delimiter, '+')
1073 dialect = sniffer.sniff(self.sample9)
1074 self.assertEqual(dialect.delimiter, '+')
1075 self.assertEqual(dialect.quotechar, "'")
Skip Montanaro77892372003-05-19 15:33:36 +00001076
Skip Montanarob4fd4d32009-09-28 02:12:27 +00001077 def test_doublequote(self):
1078 sniffer = csv.Sniffer()
R David Murray24dc7532013-06-29 18:43:59 -04001079 dialect = sniffer.sniff(self.header1)
1080 self.assertFalse(dialect.doublequote)
1081 dialect = sniffer.sniff(self.header2)
Skip Montanarob4fd4d32009-09-28 02:12:27 +00001082 self.assertFalse(dialect.doublequote)
1083 dialect = sniffer.sniff(self.sample2)
1084 self.assertTrue(dialect.doublequote)
R David Murray24dc7532013-06-29 18:43:59 -04001085 dialect = sniffer.sniff(self.sample8)
1086 self.assertFalse(dialect.doublequote)
1087 dialect = sniffer.sniff(self.sample9)
1088 self.assertTrue(dialect.doublequote)
Skip Montanarob4fd4d32009-09-28 02:12:27 +00001089
Serhiy Storchaka32e23e72013-11-03 23:15:46 +02001090class NUL:
1091 def write(s, *args):
1092 pass
1093 writelines = write
Skip Montanarob4a04172003-03-20 23:29:12 +00001094
Serhiy Storchaka32e23e72013-11-03 23:15:46 +02001095@unittest.skipUnless(hasattr(sys, "gettotalrefcount"),
1096 'requires sys.gettotalrefcount()')
1097class TestLeaks(unittest.TestCase):
1098 def test_create_read(self):
1099 delta = 0
1100 lastrc = sys.gettotalrefcount()
1101 for i in xrange(20):
1102 gc.collect()
1103 self.assertEqual(gc.garbage, [])
1104 rc = sys.gettotalrefcount()
1105 csv.reader(["a,b,c\r\n"])
1106 csv.reader(["a,b,c\r\n"])
1107 csv.reader(["a,b,c\r\n"])
1108 delta = rc-lastrc
1109 lastrc = rc
1110 # if csv.reader() leaks, last delta should be 3 or more
1111 self.assertEqual(delta < 3, True)
Skip Montanarob4a04172003-03-20 23:29:12 +00001112
Serhiy Storchaka32e23e72013-11-03 23:15:46 +02001113 def test_create_write(self):
1114 delta = 0
1115 lastrc = sys.gettotalrefcount()
1116 s = NUL()
1117 for i in xrange(20):
1118 gc.collect()
1119 self.assertEqual(gc.garbage, [])
1120 rc = sys.gettotalrefcount()
1121 csv.writer(s)
1122 csv.writer(s)
1123 csv.writer(s)
1124 delta = rc-lastrc
1125 lastrc = rc
1126 # if csv.writer() leaks, last delta should be 3 or more
1127 self.assertEqual(delta < 3, True)
Skip Montanarob4a04172003-03-20 23:29:12 +00001128
Serhiy Storchaka32e23e72013-11-03 23:15:46 +02001129 def test_read(self):
1130 delta = 0
1131 rows = ["a,b,c\r\n"]*5
1132 lastrc = sys.gettotalrefcount()
1133 for i in xrange(20):
1134 gc.collect()
1135 self.assertEqual(gc.garbage, [])
1136 rc = sys.gettotalrefcount()
1137 rdr = csv.reader(rows)
1138 for row in rdr:
1139 pass
1140 delta = rc-lastrc
1141 lastrc = rc
1142 # if reader leaks during read, delta should be 5 or more
1143 self.assertEqual(delta < 5, True)
Skip Montanarob4a04172003-03-20 23:29:12 +00001144
Serhiy Storchaka32e23e72013-11-03 23:15:46 +02001145 def test_write(self):
1146 delta = 0
1147 rows = [[1,2,3]]*5
1148 s = NUL()
1149 lastrc = sys.gettotalrefcount()
1150 for i in xrange(20):
1151 gc.collect()
1152 self.assertEqual(gc.garbage, [])
1153 rc = sys.gettotalrefcount()
1154 writer = csv.writer(s)
1155 for row in rows:
1156 writer.writerow(row)
1157 delta = rc-lastrc
1158 lastrc = rc
1159 # if writer leaks during write, last delta should be 5 or more
1160 self.assertEqual(delta < 5, True)
Skip Montanarob4a04172003-03-20 23:29:12 +00001161
Skip Montanaro1a566652003-05-06 15:56:05 +00001162# commented out for now - csv module doesn't yet support Unicode
Skip Montanaro58fc5d02004-06-05 17:03:20 +00001163## class TestUnicode(unittest.TestCase):
1164## def test_unicode_read(self):
1165## import codecs
1166## f = codecs.EncodedFile(StringIO("Martin von Löwis,"
1167## "Marc André Lemburg,"
1168## "Guido van Rossum,"
1169## "François Pinard\r\n"),
1170## data_encoding='iso-8859-1')
1171## reader = csv.reader(f)
1172## self.assertEqual(list(reader), [[u"Martin von Löwis",
1173## u"Marc André Lemburg",
1174## u"Guido van Rossum",
1175## u"François Pinardn"]])
Skip Montanaro1a566652003-05-06 15:56:05 +00001176
Walter Dörwald21d3a322003-05-01 17:45:56 +00001177def test_main():
Skip Montanarob4a04172003-03-20 23:29:12 +00001178 mod = sys.modules[__name__]
Walter Dörwald21d3a322003-05-01 17:45:56 +00001179 test_support.run_unittest(
1180 *[getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
1181 )
Skip Montanarob4a04172003-03-20 23:29:12 +00001182
1183if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001184 test_main()