1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2001,2002 Python Software Foundation
3 # csv package unit tests
8 from StringIO
import StringIO
13 from test
import test_support
15 class Test_Csv(unittest
.TestCase
):
17 Test the underlying C csv parser in ways that are not appropriate
18 from the high level interface. Further tests of this nature are done
19 in TestDialectRegistry.
21 def _test_arg_valid(self
, ctor
, arg
):
22 self
.assertRaises(TypeError, ctor
)
23 self
.assertRaises(TypeError, ctor
, None)
24 self
.assertRaises(TypeError, ctor
, arg
, bad_attr
= 0)
25 self
.assertRaises(TypeError, ctor
, arg
, delimiter
= 0)
26 self
.assertRaises(TypeError, ctor
, arg
, delimiter
= 'XX')
27 self
.assertRaises(csv
.Error
, ctor
, arg
, 'foo')
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 self
.assertRaises(TypeError, ctor
, arg
,
35 quoting
=csv
.QUOTE_ALL
, quotechar
='')
36 self
.assertRaises(TypeError, ctor
, arg
,
37 quoting
=csv
.QUOTE_ALL
, quotechar
=None)
39 def test_reader_arg_valid(self
):
40 self
._test
_arg
_valid
(csv
.reader
, [])
42 def test_writer_arg_valid(self
):
43 self
._test
_arg
_valid
(csv
.writer
, StringIO())
45 def _test_default_attrs(self
, ctor
, *args
):
48 self
.assertEqual(obj
.dialect
.delimiter
, ',')
49 self
.assertEqual(obj
.dialect
.doublequote
, True)
50 self
.assertEqual(obj
.dialect
.escapechar
, None)
51 self
.assertEqual(obj
.dialect
.lineterminator
, "\r\n")
52 self
.assertEqual(obj
.dialect
.quotechar
, '"')
53 self
.assertEqual(obj
.dialect
.quoting
, csv
.QUOTE_MINIMAL
)
54 self
.assertEqual(obj
.dialect
.skipinitialspace
, False)
55 self
.assertEqual(obj
.dialect
.strict
, False)
56 # Try deleting or changing attributes (they are read-only)
57 self
.assertRaises(TypeError, delattr, obj
.dialect
, 'delimiter')
58 self
.assertRaises(TypeError, setattr, obj
.dialect
, 'delimiter', ':')
59 self
.assertRaises(AttributeError, delattr, obj
.dialect
, 'quoting')
60 self
.assertRaises(AttributeError, setattr, obj
.dialect
,
63 def test_reader_attrs(self
):
64 self
._test
_default
_attrs
(csv
.reader
, [])
66 def test_writer_attrs(self
):
67 self
._test
_default
_attrs
(csv
.writer
, StringIO())
69 def _test_kw_attrs(self
, ctor
, *args
):
70 # Now try with alternate options
71 kwargs
= dict(delimiter
=':', doublequote
=False, escapechar
='\\',
72 lineterminator
='\r', quotechar
='*',
73 quoting
=csv
.QUOTE_NONE
, skipinitialspace
=True,
75 obj
= ctor(*args
, **kwargs
)
76 self
.assertEqual(obj
.dialect
.delimiter
, ':')
77 self
.assertEqual(obj
.dialect
.doublequote
, False)
78 self
.assertEqual(obj
.dialect
.escapechar
, '\\')
79 self
.assertEqual(obj
.dialect
.lineterminator
, "\r")
80 self
.assertEqual(obj
.dialect
.quotechar
, '*')
81 self
.assertEqual(obj
.dialect
.quoting
, csv
.QUOTE_NONE
)
82 self
.assertEqual(obj
.dialect
.skipinitialspace
, True)
83 self
.assertEqual(obj
.dialect
.strict
, True)
85 def test_reader_kw_attrs(self
):
86 self
._test
_kw
_attrs
(csv
.reader
, [])
88 def test_writer_kw_attrs(self
):
89 self
._test
_kw
_attrs
(csv
.writer
, StringIO())
91 def _test_dialect_attrs(self
, ctor
, *args
):
92 # Now try with dialect-derived options
100 skipinitialspace
=True
102 args
= args
+ (dialect
,)
104 self
.assertEqual(obj
.dialect
.delimiter
, '-')
105 self
.assertEqual(obj
.dialect
.doublequote
, False)
106 self
.assertEqual(obj
.dialect
.escapechar
, '^')
107 self
.assertEqual(obj
.dialect
.lineterminator
, "$")
108 self
.assertEqual(obj
.dialect
.quotechar
, '#')
109 self
.assertEqual(obj
.dialect
.quoting
, csv
.QUOTE_ALL
)
110 self
.assertEqual(obj
.dialect
.skipinitialspace
, True)
111 self
.assertEqual(obj
.dialect
.strict
, False)
113 def test_reader_dialect_attrs(self
):
114 self
._test
_dialect
_attrs
(csv
.reader
, [])
116 def test_writer_dialect_attrs(self
):
117 self
._test
_dialect
_attrs
(csv
.writer
, StringIO())
120 def _write_test(self
, fields
, expect
, **kwargs
):
121 fd
, name
= tempfile
.mkstemp()
122 fileobj
= os
.fdopen(fd
, "w+b")
124 writer
= csv
.writer(fileobj
, **kwargs
)
125 writer
.writerow(fields
)
127 self
.assertEqual(fileobj
.read(),
128 expect
+ writer
.dialect
.lineterminator
)
133 def test_write_arg_valid(self
):
134 self
.assertRaises(csv
.Error
, self
._write
_test
, None, '')
135 self
._write
_test
((), '')
136 self
._write
_test
([None], '""')
137 self
.assertRaises(csv
.Error
, self
._write
_test
,
138 [None], None, quoting
= csv
.QUOTE_NONE
)
139 # Check that exceptions are passed up the chain
143 def __getitem__(self
, i
):
146 self
.assertRaises(IOError, self
._write
_test
, BadList(), '')
150 self
.assertRaises(IOError, self
._write
_test
, [BadItem()], '')
152 def test_write_bigfield(self
):
153 # This exercises the buffer realloc functionality
154 bigstring
= 'X' * 50000
155 self
._write
_test
([bigstring
,bigstring
], '%s,%s' % \
156 (bigstring
, bigstring
))
158 def test_write_quoting(self
):
159 self
._write
_test
(['a',1,'p,q'], 'a,1,"p,q"')
160 self
.assertRaises(csv
.Error
,
162 ['a',1,'p,q'], 'a,1,p,q',
163 quoting
= csv
.QUOTE_NONE
)
164 self
._write
_test
(['a',1,'p,q'], 'a,1,"p,q"',
165 quoting
= csv
.QUOTE_MINIMAL
)
166 self
._write
_test
(['a',1,'p,q'], '"a",1,"p,q"',
167 quoting
= csv
.QUOTE_NONNUMERIC
)
168 self
._write
_test
(['a',1,'p,q'], '"a","1","p,q"',
169 quoting
= csv
.QUOTE_ALL
)
170 self
._write
_test
(['a\nb',1], '"a\nb","1"',
171 quoting
= csv
.QUOTE_ALL
)
173 def test_write_escape(self
):
174 self
._write
_test
(['a',1,'p,q'], 'a,1,"p,q"',
176 self
.assertRaises(csv
.Error
,
178 ['a',1,'p,"q"'], 'a,1,"p,\\"q\\""',
179 escapechar
=None, doublequote
=False)
180 self
._write
_test
(['a',1,'p,"q"'], 'a,1,"p,\\"q\\""',
181 escapechar
='\\', doublequote
= False)
182 self
._write
_test
(['"'], '""""',
183 escapechar
='\\', quoting
= csv
.QUOTE_MINIMAL
)
184 self
._write
_test
(['"'], '\\"',
185 escapechar
='\\', quoting
= csv
.QUOTE_MINIMAL
,
187 self
._write
_test
(['"'], '\\"',
188 escapechar
='\\', quoting
= csv
.QUOTE_NONE
)
189 self
._write
_test
(['a',1,'p,q'], 'a,1,p\\,q',
190 escapechar
='\\', quoting
= csv
.QUOTE_NONE
)
192 def test_writerows(self
):
194 def write(self
, buf
):
196 writer
= csv
.writer(BrokenFile())
197 self
.assertRaises(IOError, writer
.writerows
, [['a']])
198 fd
, name
= tempfile
.mkstemp()
199 fileobj
= os
.fdopen(fd
, "w+b")
201 writer
= csv
.writer(fileobj
)
202 self
.assertRaises(TypeError, writer
.writerows
, None)
203 writer
.writerows([['a','b'],['c','d']])
205 self
.assertEqual(fileobj
.read(), "a,b\r\nc,d\r\n")
210 def _read_test(self
, input, expect
, **kwargs
):
211 reader
= csv
.reader(input, **kwargs
)
212 result
= list(reader
)
213 self
.assertEqual(result
, expect
)
215 def test_read_oddinputs(self
):
216 self
._read
_test
([], [])
217 self
._read
_test
([''], [[]])
218 self
.assertRaises(csv
.Error
, self
._read
_test
,
219 ['"ab"c'], None, strict
= 1)
220 # cannot handle null bytes for the moment
221 self
.assertRaises(csv
.Error
, self
._read
_test
,
222 ['ab\0c'], None, strict
= 1)
223 self
._read
_test
(['"ab"c'], [['abc']], doublequote
= 0)
225 def test_read_eol(self
):
226 self
._read
_test
(['a,b'], [['a','b']])
227 self
._read
_test
(['a,b\n'], [['a','b']])
228 self
._read
_test
(['a,b\r\n'], [['a','b']])
229 self
._read
_test
(['a,b\r'], [['a','b']])
230 self
.assertRaises(csv
.Error
, self
._read
_test
, ['a,b\rc,d'], [])
231 self
.assertRaises(csv
.Error
, self
._read
_test
, ['a,b\nc,d'], [])
232 self
.assertRaises(csv
.Error
, self
._read
_test
, ['a,b\r\nc,d'], [])
234 def test_read_escape(self
):
235 self
._read
_test
(['a,\\b,c'], [['a', 'b', 'c']], escapechar
='\\')
236 self
._read
_test
(['a,b\\,c'], [['a', 'b,c']], escapechar
='\\')
237 self
._read
_test
(['a,"b\\,c"'], [['a', 'b,c']], escapechar
='\\')
238 self
._read
_test
(['a,"b,\\c"'], [['a', 'b,c']], escapechar
='\\')
239 self
._read
_test
(['a,"b,c\\""'], [['a', 'b,c"']], escapechar
='\\')
240 self
._read
_test
(['a,"b,c"\\'], [['a', 'b,c\\']], escapechar
='\\')
242 def test_read_quoting(self
):
243 self
._read
_test
(['1,",3,",5'], [['1', ',3,', '5']])
244 self
._read
_test
(['1,",3,",5'], [['1', '"', '3', '"', '5']],
245 quotechar
=None, escapechar
='\\')
246 self
._read
_test
(['1,",3,",5'], [['1', '"', '3', '"', '5']],
247 quoting
=csv
.QUOTE_NONE
, escapechar
='\\')
248 # will this fail where locale uses comma for decimals?
249 self
._read
_test
([',3,"5",7.3, 9'], [['', 3, '5', 7.3, 9]],
250 quoting
=csv
.QUOTE_NONNUMERIC
)
251 self
._read
_test
(['"a\nb", 7'], [['a\nb', ' 7']])
252 self
.assertRaises(ValueError, self
._read
_test
,
254 quoting
=csv
.QUOTE_NONNUMERIC
)
256 def test_read_bigfield(self
):
257 # This exercises the buffer realloc functionality and field size
259 limit
= csv
.field_size_limit()
262 bigstring
= 'X' * size
263 bigline
= '%s,%s' % (bigstring
, bigstring
)
264 self
._read
_test
([bigline
], [[bigstring
, bigstring
]])
265 csv
.field_size_limit(size
)
266 self
._read
_test
([bigline
], [[bigstring
, bigstring
]])
267 self
.assertEqual(csv
.field_size_limit(), size
)
268 csv
.field_size_limit(size
-1)
269 self
.assertRaises(csv
.Error
, self
._read
_test
, [bigline
], [])
270 self
.assertRaises(TypeError, csv
.field_size_limit
, None)
271 self
.assertRaises(TypeError, csv
.field_size_limit
, 1, None)
273 csv
.field_size_limit(limit
)
275 def test_read_linenum(self
):
276 for r
in (csv
.reader(['line,1', 'line,2', 'line,3']),
277 csv
.DictReader(['line,1', 'line,2', 'line,3'],
278 fieldnames
=['a', 'b', 'c'])):
279 self
.assertEqual(r
.line_num
, 0)
281 self
.assertEqual(r
.line_num
, 1)
283 self
.assertEqual(r
.line_num
, 2)
285 self
.assertEqual(r
.line_num
, 3)
286 self
.assertRaises(StopIteration, r
.next
)
287 self
.assertEqual(r
.line_num
, 3)
289 def test_roundtrip_quoteed_newlines(self
):
290 fd
, name
= tempfile
.mkstemp()
291 fileobj
= os
.fdopen(fd
, "w+b")
293 writer
= csv
.writer(fileobj
)
294 self
.assertRaises(TypeError, writer
.writerows
, None)
295 rows
= [['a\nb','b'],['c','x\r\nd']]
296 writer
.writerows(rows
)
298 for i
, row
in enumerate(csv
.reader(fileobj
)):
299 self
.assertEqual(row
, rows
[i
])
304 class TestDialectRegistry(unittest
.TestCase
):
305 def test_registry_badargs(self
):
306 self
.assertRaises(TypeError, csv
.list_dialects
, None)
307 self
.assertRaises(TypeError, csv
.get_dialect
)
308 self
.assertRaises(csv
.Error
, csv
.get_dialect
, None)
309 self
.assertRaises(csv
.Error
, csv
.get_dialect
, "nonesuch")
310 self
.assertRaises(TypeError, csv
.unregister_dialect
)
311 self
.assertRaises(csv
.Error
, csv
.unregister_dialect
, None)
312 self
.assertRaises(csv
.Error
, csv
.unregister_dialect
, "nonesuch")
313 self
.assertRaises(TypeError, csv
.register_dialect
, None)
314 self
.assertRaises(TypeError, csv
.register_dialect
, None, None)
315 self
.assertRaises(TypeError, csv
.register_dialect
, "nonesuch", 0, 0)
316 self
.assertRaises(TypeError, csv
.register_dialect
, "nonesuch",
318 self
.assertRaises(TypeError, csv
.register_dialect
, "nonesuch",
320 self
.assertRaises(TypeError, csv
.register_dialect
, [])
322 def test_registry(self
):
323 class myexceltsv(csv
.excel
):
326 expected_dialects
= csv
.list_dialects() + [name
]
327 expected_dialects
.sort()
328 csv
.register_dialect(name
, myexceltsv
)
330 self
.assertTrue(csv
.get_dialect(name
).delimiter
, '\t')
331 got_dialects
= csv
.list_dialects()
333 self
.assertEqual(expected_dialects
, got_dialects
)
335 csv
.unregister_dialect(name
)
337 def test_register_kwargs(self
):
339 csv
.register_dialect(name
, delimiter
=';')
341 self
.assertTrue(csv
.get_dialect(name
).delimiter
, '\t')
342 self
.assertTrue(list(csv
.reader('X;Y;Z', name
)), ['X', 'Y', 'Z'])
344 csv
.unregister_dialect(name
)
346 def test_incomplete_dialect(self
):
347 class myexceltsv(csv
.Dialect
):
349 self
.assertRaises(csv
.Error
, myexceltsv
)
351 def test_space_dialect(self
):
352 class space(csv
.excel
):
354 quoting
= csv
.QUOTE_NONE
357 fd
, name
= tempfile
.mkstemp()
358 fileobj
= os
.fdopen(fd
, "w+b")
360 fileobj
.write("abc def\nc1ccccc1 benzene\n")
362 rdr
= csv
.reader(fileobj
, dialect
=space())
363 self
.assertEqual(rdr
.next(), ["abc", "def"])
364 self
.assertEqual(rdr
.next(), ["c1ccccc1", "benzene"])
369 def test_dialect_apply(self
):
370 class testA(csv
.excel
):
372 class testB(csv
.excel
):
374 class testC(csv
.excel
):
377 csv
.register_dialect('testC', testC
)
379 fd
, name
= tempfile
.mkstemp()
380 fileobj
= os
.fdopen(fd
, "w+b")
382 writer
= csv
.writer(fileobj
)
383 writer
.writerow([1,2,3])
385 self
.assertEqual(fileobj
.read(), "1,2,3\r\n")
390 fd
, name
= tempfile
.mkstemp()
391 fileobj
= os
.fdopen(fd
, "w+b")
393 writer
= csv
.writer(fileobj
, testA
)
394 writer
.writerow([1,2,3])
396 self
.assertEqual(fileobj
.read(), "1\t2\t3\r\n")
401 fd
, name
= tempfile
.mkstemp()
402 fileobj
= os
.fdopen(fd
, "w+b")
404 writer
= csv
.writer(fileobj
, dialect
=testB())
405 writer
.writerow([1,2,3])
407 self
.assertEqual(fileobj
.read(), "1:2:3\r\n")
412 fd
, name
= tempfile
.mkstemp()
413 fileobj
= os
.fdopen(fd
, "w+b")
415 writer
= csv
.writer(fileobj
, dialect
='testC')
416 writer
.writerow([1,2,3])
418 self
.assertEqual(fileobj
.read(), "1|2|3\r\n")
423 fd
, name
= tempfile
.mkstemp()
424 fileobj
= os
.fdopen(fd
, "w+b")
426 writer
= csv
.writer(fileobj
, dialect
=testA
, delimiter
=';')
427 writer
.writerow([1,2,3])
429 self
.assertEqual(fileobj
.read(), "1;2;3\r\n")
435 csv
.unregister_dialect('testC')
437 def test_bad_dialect(self
):
439 self
.assertRaises(TypeError, csv
.reader
, [], bad_attr
= 0)
441 self
.assertRaises(TypeError, csv
.reader
, [], delimiter
= None)
442 self
.assertRaises(TypeError, csv
.reader
, [], quoting
= -1)
443 self
.assertRaises(TypeError, csv
.reader
, [], quoting
= 100)
445 class TestCsvBase(unittest
.TestCase
):
446 def readerAssertEqual(self
, input, expected_result
):
447 fd
, name
= tempfile
.mkstemp()
448 fileobj
= os
.fdopen(fd
, "w+b")
452 reader
= csv
.reader(fileobj
, dialect
= self
.dialect
)
453 fields
= list(reader
)
454 self
.assertEqual(fields
, expected_result
)
459 def writerAssertEqual(self
, input, expected_result
):
460 fd
, name
= tempfile
.mkstemp()
461 fileobj
= os
.fdopen(fd
, "w+b")
463 writer
= csv
.writer(fileobj
, dialect
= self
.dialect
)
464 writer
.writerows(input)
466 self
.assertEqual(fileobj
.read(), expected_result
)
471 class TestDialectExcel(TestCsvBase
):
474 def test_single(self
):
475 self
.readerAssertEqual('abc', [['abc']])
477 def test_simple(self
):
478 self
.readerAssertEqual('1,2,3,4,5', [['1','2','3','4','5']])
480 def test_blankline(self
):
481 self
.readerAssertEqual('', [])
483 def test_empty_fields(self
):
484 self
.readerAssertEqual(',', [['', '']])
486 def test_singlequoted(self
):
487 self
.readerAssertEqual('""', [['']])
489 def test_singlequoted_left_empty(self
):
490 self
.readerAssertEqual('"",', [['','']])
492 def test_singlequoted_right_empty(self
):
493 self
.readerAssertEqual(',""', [['','']])
495 def test_single_quoted_quote(self
):
496 self
.readerAssertEqual('""""', [['"']])
498 def test_quoted_quotes(self
):
499 self
.readerAssertEqual('""""""', [['""']])
501 def test_inline_quote(self
):
502 self
.readerAssertEqual('a""b', [['a""b']])
504 def test_inline_quotes(self
):
505 self
.readerAssertEqual('a"b"c', [['a"b"c']])
507 def test_quotes_and_more(self
):
508 # Excel would never write a field containing '"a"b', but when
509 # reading one, it will return 'ab'.
510 self
.readerAssertEqual('"a"b', [['ab']])
512 def test_lone_quote(self
):
513 self
.readerAssertEqual('a"b', [['a"b']])
515 def test_quote_and_quote(self
):
516 # Excel would never write a field containing '"a" "b"', but when
517 # reading one, it will return 'a "b"'.
518 self
.readerAssertEqual('"a" "b"', [['a "b"']])
520 def test_space_and_quote(self
):
521 self
.readerAssertEqual(' "a"', [[' "a"']])
523 def test_quoted(self
):
524 self
.readerAssertEqual('1,2,3,"I think, therefore I am",5,6',
526 'I think, therefore I am',
529 def test_quoted_quote(self
):
530 self
.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"',
532 '"I see," said the blind man',
533 'as he picked up his hammer and saw']])
535 def test_quoted_nl(self
):
538 said the blind man","as he picked up his
541 self
.readerAssertEqual(input,
543 '"I see,"\nsaid the blind man',
544 'as he picked up his\nhammer and saw'],
547 def test_dubious_quote(self
):
548 self
.readerAssertEqual('12,12,1",', [['12', '12', '1"', '']])
551 self
.writerAssertEqual([], '')
553 def test_single_writer(self
):
554 self
.writerAssertEqual([['abc']], 'abc\r\n')
556 def test_simple_writer(self
):
557 self
.writerAssertEqual([[1, 2, 'abc', 3, 4]], '1,2,abc,3,4\r\n')
559 def test_quotes(self
):
560 self
.writerAssertEqual([[1, 2, 'a"bc"', 3, 4]], '1,2,"a""bc""",3,4\r\n')
562 def test_quote_fieldsep(self
):
563 self
.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
565 def test_newlines(self
):
566 self
.writerAssertEqual([[1, 2, 'a\nbc', 3, 4]], '1,2,"a\nbc",3,4\r\n')
568 class EscapedExcel(csv
.excel
):
569 quoting
= csv
.QUOTE_NONE
572 class TestEscapedExcel(TestCsvBase
):
573 dialect
= EscapedExcel()
575 def test_escape_fieldsep(self
):
576 self
.writerAssertEqual([['abc,def']], 'abc\\,def\r\n')
578 def test_read_escape_fieldsep(self
):
579 self
.readerAssertEqual('abc\\,def\r\n', [['abc,def']])
581 class QuotedEscapedExcel(csv
.excel
):
582 quoting
= csv
.QUOTE_NONNUMERIC
585 class TestQuotedEscapedExcel(TestCsvBase
):
586 dialect
= QuotedEscapedExcel()
588 def test_write_escape_fieldsep(self
):
589 self
.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
591 def test_read_escape_fieldsep(self
):
592 self
.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']])
594 class TestDictFields(unittest
.TestCase
):
595 ### "long" means the row is longer than the number of fieldnames
596 ### "short" means there are fewer elements in the row than fieldnames
597 def test_write_simple_dict(self
):
598 fd
, name
= tempfile
.mkstemp()
599 fileobj
= io
.open(fd
, 'w+b')
601 writer
= csv
.DictWriter(fileobj
, fieldnames
= ["f1", "f2", "f3"])
604 self
.assertEqual(fileobj
.readline(), "f1,f2,f3\r\n")
605 writer
.writerow({"f1": 10, "f3": "abc"})
607 fileobj
.readline() # header
608 self
.assertEqual(fileobj
.read(), "10,,abc\r\n")
613 def test_write_no_fields(self
):
615 self
.assertRaises(TypeError, csv
.DictWriter
, fileobj
)
617 def test_read_dict_fields(self
):
618 fd
, name
= tempfile
.mkstemp()
619 fileobj
= os
.fdopen(fd
, "w+b")
621 fileobj
.write("1,2,abc\r\n")
623 reader
= csv
.DictReader(fileobj
,
624 fieldnames
=["f1", "f2", "f3"])
625 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
630 def test_read_dict_no_fieldnames(self
):
631 fd
, name
= tempfile
.mkstemp()
632 fileobj
= os
.fdopen(fd
, "w+b")
634 fileobj
.write("f1,f2,f3\r\n1,2,abc\r\n")
636 reader
= csv
.DictReader(fileobj
)
637 self
.assertEqual(reader
.fieldnames
, ["f1", "f2", "f3"])
638 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
643 # Two test cases to make sure existing ways of implicitly setting
644 # fieldnames continue to work. Both arise from discussion in issue3436.
645 def test_read_dict_fieldnames_from_file(self
):
646 fd
, name
= tempfile
.mkstemp()
647 f
= os
.fdopen(fd
, "w+b")
649 f
.write("f1,f2,f3\r\n1,2,abc\r\n")
651 reader
= csv
.DictReader(f
, fieldnames
=csv
.reader(f
).next())
652 self
.assertEqual(reader
.fieldnames
, ["f1", "f2", "f3"])
653 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
658 def test_read_dict_fieldnames_chain(self
):
660 fd
, name
= tempfile
.mkstemp()
661 f
= os
.fdopen(fd
, "w+b")
663 f
.write("f1,f2,f3\r\n1,2,abc\r\n")
665 reader
= csv
.DictReader(f
)
667 for row
in itertools
.chain([first
], reader
):
668 self
.assertEqual(reader
.fieldnames
, ["f1", "f2", "f3"])
669 self
.assertEqual(row
, {"f1": '1', "f2": '2', "f3": 'abc'})
674 def test_read_long(self
):
675 fd
, name
= tempfile
.mkstemp()
676 fileobj
= os
.fdopen(fd
, "w+b")
678 fileobj
.write("1,2,abc,4,5,6\r\n")
680 reader
= csv
.DictReader(fileobj
,
681 fieldnames
=["f1", "f2"])
682 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2',
683 None: ["abc", "4", "5", "6"]})
688 def test_read_long_with_rest(self
):
689 fd
, name
= tempfile
.mkstemp()
690 fileobj
= os
.fdopen(fd
, "w+b")
692 fileobj
.write("1,2,abc,4,5,6\r\n")
694 reader
= csv
.DictReader(fileobj
,
695 fieldnames
=["f1", "f2"], restkey
="_rest")
696 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2',
697 "_rest": ["abc", "4", "5", "6"]})
702 def test_read_long_with_rest_no_fieldnames(self
):
703 fd
, name
= tempfile
.mkstemp()
704 fileobj
= os
.fdopen(fd
, "w+b")
706 fileobj
.write("f1,f2\r\n1,2,abc,4,5,6\r\n")
708 reader
= csv
.DictReader(fileobj
, restkey
="_rest")
709 self
.assertEqual(reader
.fieldnames
, ["f1", "f2"])
710 self
.assertEqual(reader
.next(), {"f1": '1', "f2": '2',
711 "_rest": ["abc", "4", "5", "6"]})
716 def test_read_short(self
):
717 fd
, name
= tempfile
.mkstemp()
718 fileobj
= os
.fdopen(fd
, "w+b")
720 fileobj
.write("1,2,abc,4,5,6\r\n1,2,abc\r\n")
722 reader
= csv
.DictReader(fileobj
,
723 fieldnames
="1 2 3 4 5 6".split(),
725 self
.assertEqual(reader
.next(), {"1": '1', "2": '2', "3": 'abc',
726 "4": '4', "5": '5', "6": '6'})
727 self
.assertEqual(reader
.next(), {"1": '1', "2": '2', "3": 'abc',
728 "4": 'DEFAULT', "5": 'DEFAULT',
734 def test_read_multi(self
):
736 '2147483648,43.0e12,17,abc,def\r\n',
737 '147483648,43.0e2,17,abc,def\r\n',
738 '47483648,43.0,170,abc,def\r\n'
741 reader
= csv
.DictReader(sample
,
742 fieldnames
="i1 float i2 s1 s2".split())
743 self
.assertEqual(reader
.next(), {"i1": '2147483648',
749 def test_read_with_blanks(self
):
750 reader
= csv
.DictReader(["1,2,abc,4,5,6\r\n","\r\n",
751 "1,2,abc,4,5,6\r\n"],
752 fieldnames
="1 2 3 4 5 6".split())
753 self
.assertEqual(reader
.next(), {"1": '1', "2": '2', "3": 'abc',
754 "4": '4', "5": '5', "6": '6'})
755 self
.assertEqual(reader
.next(), {"1": '1', "2": '2', "3": 'abc',
756 "4": '4', "5": '5', "6": '6'})
758 def test_read_semi_sep(self
):
759 reader
= csv
.DictReader(["1;2;abc;4;5;6\r\n"],
760 fieldnames
="1 2 3 4 5 6".split(),
762 self
.assertEqual(reader
.next(), {"1": '1', "2": '2', "3": 'abc',
763 "4": '4', "5": '5', "6": '6'})
765 class TestArrayWrites(unittest
.TestCase
):
766 def test_int_write(self
):
768 contents
= [(20-i
) for i
in range(20)]
769 a
= array
.array('i', contents
)
771 fd
, name
= tempfile
.mkstemp()
772 fileobj
= os
.fdopen(fd
, "w+b")
774 writer
= csv
.writer(fileobj
, dialect
="excel")
776 expected
= ",".join([str(i
) for i
in a
])+"\r\n"
778 self
.assertEqual(fileobj
.read(), expected
)
783 def test_double_write(self
):
785 contents
= [(20-i
)*0.1 for i
in range(20)]
786 a
= array
.array('d', contents
)
787 fd
, name
= tempfile
.mkstemp()
788 fileobj
= os
.fdopen(fd
, "w+b")
790 writer
= csv
.writer(fileobj
, dialect
="excel")
792 expected
= ",".join([str(i
) for i
in a
])+"\r\n"
794 self
.assertEqual(fileobj
.read(), expected
)
799 def test_float_write(self
):
801 contents
= [(20-i
)*0.1 for i
in range(20)]
802 a
= array
.array('f', contents
)
803 fd
, name
= tempfile
.mkstemp()
804 fileobj
= os
.fdopen(fd
, "w+b")
806 writer
= csv
.writer(fileobj
, dialect
="excel")
808 expected
= ",".join([str(i
) for i
in a
])+"\r\n"
810 self
.assertEqual(fileobj
.read(), expected
)
815 def test_char_write(self
):
817 a
= array
.array('c', string
.letters
)
818 fd
, name
= tempfile
.mkstemp()
819 fileobj
= os
.fdopen(fd
, "w+b")
821 writer
= csv
.writer(fileobj
, dialect
="excel")
823 expected
= ",".join(a
)+"\r\n"
825 self
.assertEqual(fileobj
.read(), expected
)
830 class TestDialectValidity(unittest
.TestCase
):
831 def test_quoting(self
):
832 class mydialect(csv
.Dialect
):
836 skipinitialspace
= True
837 lineterminator
= '\r\n'
838 quoting
= csv
.QUOTE_NONE
841 mydialect
.quoting
= None
842 self
.assertRaises(csv
.Error
, mydialect
)
844 mydialect
.doublequote
= True
845 mydialect
.quoting
= csv
.QUOTE_ALL
846 mydialect
.quotechar
= '"'
849 mydialect
.quotechar
= "''"
850 self
.assertRaises(csv
.Error
, mydialect
)
852 mydialect
.quotechar
= 4
853 self
.assertRaises(csv
.Error
, mydialect
)
855 def test_delimiter(self
):
856 class mydialect(csv
.Dialect
):
860 skipinitialspace
= True
861 lineterminator
= '\r\n'
862 quoting
= csv
.QUOTE_NONE
865 mydialect
.delimiter
= ":::"
866 self
.assertRaises(csv
.Error
, mydialect
)
868 mydialect
.delimiter
= 4
869 self
.assertRaises(csv
.Error
, mydialect
)
871 def test_lineterminator(self
):
872 class mydialect(csv
.Dialect
):
876 skipinitialspace
= True
877 lineterminator
= '\r\n'
878 quoting
= csv
.QUOTE_NONE
881 mydialect
.lineterminator
= ":::"
884 mydialect
.lineterminator
= 4
885 self
.assertRaises(csv
.Error
, mydialect
)
888 class TestSniffer(unittest
.TestCase
):
890 Harry's, Arlington Heights, IL, 2/1/03, Kimi Hayes
891 Shark City, Glendale Heights, IL, 12/28/02, Prezence
892 Tommy's Place, Blue Island, IL, 12/28/02, Blue Sunday/White Crow
893 Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
896 'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes'
897 'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence'
898 'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow'
899 'Stonecutters ''Seafood'' and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
902 "venue","city","state","date","performers"
905 05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
906 05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
907 05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
911 2147483648;43.0e12;17;abc;def
912 147483648;43.0e2;17;abc;def
913 47483648;43.0;170;abc;def
916 sample5
= "aaa\tbbb\r\nAAA\t\r\nBBB\t\r\n"
917 sample6
= "a|b|c\r\nd|e|f\r\n"
918 sample7
= "'a'|'b'|'c'\r\n'd'|e|f\r\n"
920 def test_has_header(self
):
921 sniffer
= csv
.Sniffer()
922 self
.assertEqual(sniffer
.has_header(self
.sample1
), False)
923 self
.assertEqual(sniffer
.has_header(self
.header
+self
.sample1
), True)
925 def test_sniff(self
):
926 sniffer
= csv
.Sniffer()
927 dialect
= sniffer
.sniff(self
.sample1
)
928 self
.assertEqual(dialect
.delimiter
, ",")
929 self
.assertEqual(dialect
.quotechar
, '"')
930 self
.assertEqual(dialect
.skipinitialspace
, True)
932 dialect
= sniffer
.sniff(self
.sample2
)
933 self
.assertEqual(dialect
.delimiter
, ":")
934 self
.assertEqual(dialect
.quotechar
, "'")
935 self
.assertEqual(dialect
.skipinitialspace
, False)
937 def test_delimiters(self
):
938 sniffer
= csv
.Sniffer()
939 dialect
= sniffer
.sniff(self
.sample3
)
940 # given that all three lines in sample3 are equal,
941 # I think that any character could have been 'guessed' as the
942 # delimiter, depending on dictionary order
943 self
.assertIn(dialect
.delimiter
, self
.sample3
)
944 dialect
= sniffer
.sniff(self
.sample3
, delimiters
="?,")
945 self
.assertEqual(dialect
.delimiter
, "?")
946 dialect
= sniffer
.sniff(self
.sample3
, delimiters
="/,")
947 self
.assertEqual(dialect
.delimiter
, "/")
948 dialect
= sniffer
.sniff(self
.sample4
)
949 self
.assertEqual(dialect
.delimiter
, ";")
950 dialect
= sniffer
.sniff(self
.sample5
)
951 self
.assertEqual(dialect
.delimiter
, "\t")
952 dialect
= sniffer
.sniff(self
.sample6
)
953 self
.assertEqual(dialect
.delimiter
, "|")
954 dialect
= sniffer
.sniff(self
.sample7
)
955 self
.assertEqual(dialect
.delimiter
, "|")
956 self
.assertEqual(dialect
.quotechar
, "'")
958 def test_doublequote(self
):
959 sniffer
= csv
.Sniffer()
960 dialect
= sniffer
.sniff(self
.header
)
961 self
.assertFalse(dialect
.doublequote
)
962 dialect
= sniffer
.sniff(self
.sample2
)
963 self
.assertTrue(dialect
.doublequote
)
965 if not hasattr(sys
, "gettotalrefcount"):
966 if test_support
.verbose
: print "*** skipping leakage tests ***"
973 class TestLeaks(unittest
.TestCase
):
974 def test_create_read(self
):
976 lastrc
= sys
.gettotalrefcount()
979 self
.assertEqual(gc
.garbage
, [])
980 rc
= sys
.gettotalrefcount()
981 csv
.reader(["a,b,c\r\n"])
982 csv
.reader(["a,b,c\r\n"])
983 csv
.reader(["a,b,c\r\n"])
986 # if csv.reader() leaks, last delta should be 3 or more
987 self
.assertEqual(delta
< 3, True)
989 def test_create_write(self
):
991 lastrc
= sys
.gettotalrefcount()
995 self
.assertEqual(gc
.garbage
, [])
996 rc
= sys
.gettotalrefcount()
1002 # if csv.writer() leaks, last delta should be 3 or more
1003 self
.assertEqual(delta
< 3, True)
1005 def test_read(self
):
1007 rows
= ["a,b,c\r\n"]*5
1008 lastrc
= sys
.gettotalrefcount()
1009 for i
in xrange(20):
1011 self
.assertEqual(gc
.garbage
, [])
1012 rc
= sys
.gettotalrefcount()
1013 rdr
= csv
.reader(rows
)
1018 # if reader leaks during read, delta should be 5 or more
1019 self
.assertEqual(delta
< 5, True)
1021 def test_write(self
):
1025 lastrc
= sys
.gettotalrefcount()
1026 for i
in xrange(20):
1028 self
.assertEqual(gc
.garbage
, [])
1029 rc
= sys
.gettotalrefcount()
1030 writer
= csv
.writer(s
)
1032 writer
.writerow(row
)
1035 # if writer leaks during write, last delta should be 5 or more
1036 self
.assertEqual(delta
< 5, True)
1038 # commented out for now - csv module doesn't yet support Unicode
1039 ## class TestUnicode(unittest.TestCase):
1040 ## def test_unicode_read(self):
1042 ## f = codecs.EncodedFile(StringIO("Martin von Löwis,"
1043 ## "Marc André Lemburg,"
1044 ## "Guido van Rossum,"
1045 ## "François Pinard\r\n"),
1046 ## data_encoding='iso-8859-1')
1047 ## reader = csv.reader(f)
1048 ## self.assertEqual(list(reader), [[u"Martin von Löwis",
1049 ## u"Marc André Lemburg",
1050 ## u"Guido van Rossum",
1051 ## u"François Pinardn"]])
1054 mod
= sys
.modules
[__name__
]
1055 test_support
.run_unittest(
1056 *[getattr(mod
, name
) for name
in dir(mod
) if name
.startswith('Test')]
1059 if __name__
== '__main__':