»Core Development>Code coverage>Lib/test/test_csv.py

Python code coverage for Lib/test/test_csv.py

#countcontent
1n/a# Copyright (C) 2001,2002 Python Software Foundation
2n/a# csv package unit tests
3n/a
4n/aimport copy
5n/aimport sys
6n/aimport unittest
7n/afrom io import StringIO
8n/afrom tempfile import TemporaryFile
9n/aimport csv
10n/aimport gc
11n/aimport pickle
12n/afrom test import support
13n/afrom itertools import permutations
14n/afrom textwrap import dedent
15n/afrom collections import OrderedDict
16n/a
17n/aclass Test_Csv(unittest.TestCase):
18n/a """
19n/a Test the underlying C csv parser in ways that are not appropriate
20n/a from the high level interface. Further tests of this nature are done
21n/a in TestDialectRegistry.
22n/a """
23n/a def _test_arg_valid(self, ctor, arg):
24n/a self.assertRaises(TypeError, ctor)
25n/a self.assertRaises(TypeError, ctor, None)
26n/a self.assertRaises(TypeError, ctor, arg, bad_attr = 0)
27n/a self.assertRaises(TypeError, ctor, arg, delimiter = 0)
28n/a self.assertRaises(TypeError, ctor, arg, delimiter = 'XX')
29n/a self.assertRaises(csv.Error, ctor, arg, 'foo')
30n/a self.assertRaises(TypeError, ctor, arg, delimiter=None)
31n/a self.assertRaises(TypeError, ctor, arg, delimiter=1)
32n/a self.assertRaises(TypeError, ctor, arg, quotechar=1)
33n/a self.assertRaises(TypeError, ctor, arg, lineterminator=None)
34n/a self.assertRaises(TypeError, ctor, arg, lineterminator=1)
35n/a self.assertRaises(TypeError, ctor, arg, quoting=None)
36n/a self.assertRaises(TypeError, ctor, arg,
37n/a quoting=csv.QUOTE_ALL, quotechar='')
38n/a self.assertRaises(TypeError, ctor, arg,
39n/a quoting=csv.QUOTE_ALL, quotechar=None)
40n/a
41n/a def test_reader_arg_valid(self):
42n/a self._test_arg_valid(csv.reader, [])
43n/a
44n/a def test_writer_arg_valid(self):
45n/a self._test_arg_valid(csv.writer, StringIO())
46n/a
47n/a def _test_default_attrs(self, ctor, *args):
48n/a obj = ctor(*args)
49n/a # Check defaults
50n/a self.assertEqual(obj.dialect.delimiter, ',')
51n/a self.assertEqual(obj.dialect.doublequote, True)
52n/a self.assertEqual(obj.dialect.escapechar, None)
53n/a self.assertEqual(obj.dialect.lineterminator, "\r\n")
54n/a self.assertEqual(obj.dialect.quotechar, '"')
55n/a self.assertEqual(obj.dialect.quoting, csv.QUOTE_MINIMAL)
56n/a self.assertEqual(obj.dialect.skipinitialspace, False)
57n/a self.assertEqual(obj.dialect.strict, False)
58n/a # Try deleting or changing attributes (they are read-only)
59n/a self.assertRaises(AttributeError, delattr, obj.dialect, 'delimiter')
60n/a self.assertRaises(AttributeError, setattr, obj.dialect, 'delimiter', ':')
61n/a self.assertRaises(AttributeError, delattr, obj.dialect, 'quoting')
62n/a self.assertRaises(AttributeError, setattr, obj.dialect,
63n/a 'quoting', None)
64n/a
65n/a def test_reader_attrs(self):
66n/a self._test_default_attrs(csv.reader, [])
67n/a
68n/a def test_writer_attrs(self):
69n/a self._test_default_attrs(csv.writer, StringIO())
70n/a
71n/a def _test_kw_attrs(self, ctor, *args):
72n/a # Now try with alternate options
73n/a kwargs = dict(delimiter=':', doublequote=False, escapechar='\\',
74n/a lineterminator='\r', quotechar='*',
75n/a quoting=csv.QUOTE_NONE, skipinitialspace=True,
76n/a strict=True)
77n/a obj = ctor(*args, **kwargs)
78n/a self.assertEqual(obj.dialect.delimiter, ':')
79n/a self.assertEqual(obj.dialect.doublequote, False)
80n/a self.assertEqual(obj.dialect.escapechar, '\\')
81n/a self.assertEqual(obj.dialect.lineterminator, "\r")
82n/a self.assertEqual(obj.dialect.quotechar, '*')
83n/a self.assertEqual(obj.dialect.quoting, csv.QUOTE_NONE)
84n/a self.assertEqual(obj.dialect.skipinitialspace, True)
85n/a self.assertEqual(obj.dialect.strict, True)
86n/a
87n/a def test_reader_kw_attrs(self):
88n/a self._test_kw_attrs(csv.reader, [])
89n/a
90n/a def test_writer_kw_attrs(self):
91n/a self._test_kw_attrs(csv.writer, StringIO())
92n/a
93n/a def _test_dialect_attrs(self, ctor, *args):
94n/a # Now try with dialect-derived options
95n/a class dialect:
96n/a delimiter='-'
97n/a doublequote=False
98n/a escapechar='^'
99n/a lineterminator='$'
100n/a quotechar='#'
101n/a quoting=csv.QUOTE_ALL
102n/a skipinitialspace=True
103n/a strict=False
104n/a args = args + (dialect,)
105n/a obj = ctor(*args)
106n/a self.assertEqual(obj.dialect.delimiter, '-')
107n/a self.assertEqual(obj.dialect.doublequote, False)
108n/a self.assertEqual(obj.dialect.escapechar, '^')
109n/a self.assertEqual(obj.dialect.lineterminator, "$")
110n/a self.assertEqual(obj.dialect.quotechar, '#')
111n/a self.assertEqual(obj.dialect.quoting, csv.QUOTE_ALL)
112n/a self.assertEqual(obj.dialect.skipinitialspace, True)
113n/a self.assertEqual(obj.dialect.strict, False)
114n/a
115n/a def test_reader_dialect_attrs(self):
116n/a self._test_dialect_attrs(csv.reader, [])
117n/a
118n/a def test_writer_dialect_attrs(self):
119n/a self._test_dialect_attrs(csv.writer, StringIO())
120n/a
121n/a
122n/a def _write_test(self, fields, expect, **kwargs):
123n/a with TemporaryFile("w+", newline='') as fileobj:
124n/a writer = csv.writer(fileobj, **kwargs)
125n/a writer.writerow(fields)
126n/a fileobj.seek(0)
127n/a self.assertEqual(fileobj.read(),
128n/a expect + writer.dialect.lineterminator)
129n/a
130n/a def _write_error_test(self, exc, fields, **kwargs):
131n/a with TemporaryFile("w+", newline='') as fileobj:
132n/a writer = csv.writer(fileobj, **kwargs)
133n/a with self.assertRaises(exc):
134n/a writer.writerow(fields)
135n/a fileobj.seek(0)
136n/a self.assertEqual(fileobj.read(), '')
137n/a
138n/a def test_write_arg_valid(self):
139n/a self._write_error_test(csv.Error, None)
140n/a self._write_test((), '')
141n/a self._write_test([None], '""')
142n/a self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
143n/a # Check that exceptions are passed up the chain
144n/a class BadList:
145n/a def __len__(self):
146n/a return 10;
147n/a def __getitem__(self, i):
148n/a if i > 2:
149n/a raise OSError
150n/a self._write_error_test(OSError, BadList())
151n/a class BadItem:
152n/a def __str__(self):
153n/a raise OSError
154n/a self._write_error_test(OSError, [BadItem()])
155n/a
156n/a def test_write_bigfield(self):
157n/a # This exercises the buffer realloc functionality
158n/a bigstring = 'X' * 50000
159n/a self._write_test([bigstring,bigstring], '%s,%s' % \
160n/a (bigstring, bigstring))
161n/a
162n/a def test_write_quoting(self):
163n/a self._write_test(['a',1,'p,q'], 'a,1,"p,q"')
164n/a self._write_error_test(csv.Error, ['a',1,'p,q'],
165n/a quoting = csv.QUOTE_NONE)
166n/a self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
167n/a quoting = csv.QUOTE_MINIMAL)
168n/a self._write_test(['a',1,'p,q'], '"a",1,"p,q"',
169n/a quoting = csv.QUOTE_NONNUMERIC)
170n/a self._write_test(['a',1,'p,q'], '"a","1","p,q"',
171n/a quoting = csv.QUOTE_ALL)
172n/a self._write_test(['a\nb',1], '"a\nb","1"',
173n/a quoting = csv.QUOTE_ALL)
174n/a
175n/a def test_write_escape(self):
176n/a self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
177n/a escapechar='\\')
178n/a self._write_error_test(csv.Error, ['a',1,'p,"q"'],
179n/a escapechar=None, doublequote=False)
180n/a self._write_test(['a',1,'p,"q"'], 'a,1,"p,\\"q\\""',
181n/a escapechar='\\', doublequote = False)
182n/a self._write_test(['"'], '""""',
183n/a escapechar='\\', quoting = csv.QUOTE_MINIMAL)
184n/a self._write_test(['"'], '\\"',
185n/a escapechar='\\', quoting = csv.QUOTE_MINIMAL,
186n/a doublequote = False)
187n/a self._write_test(['"'], '\\"',
188n/a escapechar='\\', quoting = csv.QUOTE_NONE)
189n/a self._write_test(['a',1,'p,q'], 'a,1,p\\,q',
190n/a escapechar='\\', quoting = csv.QUOTE_NONE)
191n/a
192n/a def test_write_iterable(self):
193n/a self._write_test(iter(['a', 1, 'p,q']), 'a,1,"p,q"')
194n/a self._write_test(iter(['a', 1, None]), 'a,1,')
195n/a self._write_test(iter([]), '')
196n/a self._write_test(iter([None]), '""')
197n/a self._write_error_test(csv.Error, iter([None]), quoting=csv.QUOTE_NONE)
198n/a self._write_test(iter([None, None]), ',')
199n/a
200n/a def test_writerows(self):
201n/a class BrokenFile:
202n/a def write(self, buf):
203n/a raise OSError
204n/a writer = csv.writer(BrokenFile())
205n/a self.assertRaises(OSError, writer.writerows, [['a']])
206n/a
207n/a with TemporaryFile("w+", newline='') as fileobj:
208n/a writer = csv.writer(fileobj)
209n/a self.assertRaises(TypeError, writer.writerows, None)
210n/a writer.writerows([['a','b'],['c','d']])
211n/a fileobj.seek(0)
212n/a self.assertEqual(fileobj.read(), "a,b\r\nc,d\r\n")
213n/a
214n/a @support.cpython_only
215n/a def test_writerows_legacy_strings(self):
216n/a import _testcapi
217n/a
218n/a c = _testcapi.unicode_legacy_string('a')
219n/a with TemporaryFile("w+", newline='') as fileobj:
220n/a writer = csv.writer(fileobj)
221n/a writer.writerows([[c]])
222n/a fileobj.seek(0)
223n/a self.assertEqual(fileobj.read(), "a\r\n")
224n/a
225n/a def _read_test(self, input, expect, **kwargs):
226n/a reader = csv.reader(input, **kwargs)
227n/a result = list(reader)
228n/a self.assertEqual(result, expect)
229n/a
230n/a def test_read_oddinputs(self):
231n/a self._read_test([], [])
232n/a self._read_test([''], [[]])
233n/a self.assertRaises(csv.Error, self._read_test,
234n/a ['"ab"c'], None, strict = 1)
235n/a # cannot handle null bytes for the moment
236n/a self.assertRaises(csv.Error, self._read_test,
237n/a ['ab\0c'], None, strict = 1)
238n/a self._read_test(['"ab"c'], [['abc']], doublequote = 0)
239n/a
240n/a self.assertRaises(csv.Error, self._read_test,
241n/a [b'ab\0c'], None)
242n/a
243n/a
244n/a def test_read_eol(self):
245n/a self._read_test(['a,b'], [['a','b']])
246n/a self._read_test(['a,b\n'], [['a','b']])
247n/a self._read_test(['a,b\r\n'], [['a','b']])
248n/a self._read_test(['a,b\r'], [['a','b']])
249n/a self.assertRaises(csv.Error, self._read_test, ['a,b\rc,d'], [])
250n/a self.assertRaises(csv.Error, self._read_test, ['a,b\nc,d'], [])
251n/a self.assertRaises(csv.Error, self._read_test, ['a,b\r\nc,d'], [])
252n/a
253n/a def test_read_eof(self):
254n/a self._read_test(['a,"'], [['a', '']])
255n/a self._read_test(['"a'], [['a']])
256n/a self._read_test(['^'], [['\n']], escapechar='^')
257n/a self.assertRaises(csv.Error, self._read_test, ['a,"'], [], strict=True)
258n/a self.assertRaises(csv.Error, self._read_test, ['"a'], [], strict=True)
259n/a self.assertRaises(csv.Error, self._read_test,
260n/a ['^'], [], escapechar='^', strict=True)
261n/a
262n/a def test_read_escape(self):
263n/a self._read_test(['a,\\b,c'], [['a', 'b', 'c']], escapechar='\\')
264n/a self._read_test(['a,b\\,c'], [['a', 'b,c']], escapechar='\\')
265n/a self._read_test(['a,"b\\,c"'], [['a', 'b,c']], escapechar='\\')
266n/a self._read_test(['a,"b,\\c"'], [['a', 'b,c']], escapechar='\\')
267n/a self._read_test(['a,"b,c\\""'], [['a', 'b,c"']], escapechar='\\')
268n/a self._read_test(['a,"b,c"\\'], [['a', 'b,c\\']], escapechar='\\')
269n/a
270n/a def test_read_quoting(self):
271n/a self._read_test(['1,",3,",5'], [['1', ',3,', '5']])
272n/a self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
273n/a quotechar=None, escapechar='\\')
274n/a self._read_test(['1,",3,",5'], [['1', '"', '3', '"', '5']],
275n/a quoting=csv.QUOTE_NONE, escapechar='\\')
276n/a # will this fail where locale uses comma for decimals?
277n/a self._read_test([',3,"5",7.3, 9'], [['', 3, '5', 7.3, 9]],
278n/a quoting=csv.QUOTE_NONNUMERIC)
279n/a self._read_test(['"a\nb", 7'], [['a\nb', ' 7']])
280n/a self.assertRaises(ValueError, self._read_test,
281n/a ['abc,3'], [[]],
282n/a quoting=csv.QUOTE_NONNUMERIC)
283n/a
284n/a def test_read_bigfield(self):
285n/a # This exercises the buffer realloc functionality and field size
286n/a # limits.
287n/a limit = csv.field_size_limit()
288n/a try:
289n/a size = 50000
290n/a bigstring = 'X' * size
291n/a bigline = '%s,%s' % (bigstring, bigstring)
292n/a self._read_test([bigline], [[bigstring, bigstring]])
293n/a csv.field_size_limit(size)
294n/a self._read_test([bigline], [[bigstring, bigstring]])
295n/a self.assertEqual(csv.field_size_limit(), size)
296n/a csv.field_size_limit(size-1)
297n/a self.assertRaises(csv.Error, self._read_test, [bigline], [])
298n/a self.assertRaises(TypeError, csv.field_size_limit, None)
299n/a self.assertRaises(TypeError, csv.field_size_limit, 1, None)
300n/a finally:
301n/a csv.field_size_limit(limit)
302n/a
303n/a def test_read_linenum(self):
304n/a r = csv.reader(['line,1', 'line,2', 'line,3'])
305n/a self.assertEqual(r.line_num, 0)
306n/a next(r)
307n/a self.assertEqual(r.line_num, 1)
308n/a next(r)
309n/a self.assertEqual(r.line_num, 2)
310n/a next(r)
311n/a self.assertEqual(r.line_num, 3)
312n/a self.assertRaises(StopIteration, next, r)
313n/a self.assertEqual(r.line_num, 3)
314n/a
315n/a def test_roundtrip_quoteed_newlines(self):
316n/a with TemporaryFile("w+", newline='') as fileobj:
317n/a writer = csv.writer(fileobj)
318n/a self.assertRaises(TypeError, writer.writerows, None)
319n/a rows = [['a\nb','b'],['c','x\r\nd']]
320n/a writer.writerows(rows)
321n/a fileobj.seek(0)
322n/a for i, row in enumerate(csv.reader(fileobj)):
323n/a self.assertEqual(row, rows[i])
324n/a
325n/a def test_roundtrip_escaped_unquoted_newlines(self):
326n/a with TemporaryFile("w+", newline='') as fileobj:
327n/a writer = csv.writer(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")
328n/a rows = [['a\nb','b'],['c','x\r\nd']]
329n/a writer.writerows(rows)
330n/a fileobj.seek(0)
331n/a for i, row in enumerate(csv.reader(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")):
332n/a self.assertEqual(row,rows[i])
333n/a
334n/aclass TestDialectRegistry(unittest.TestCase):
335n/a def test_registry_badargs(self):
336n/a self.assertRaises(TypeError, csv.list_dialects, None)
337n/a self.assertRaises(TypeError, csv.get_dialect)
338n/a self.assertRaises(csv.Error, csv.get_dialect, None)
339n/a self.assertRaises(csv.Error, csv.get_dialect, "nonesuch")
340n/a self.assertRaises(TypeError, csv.unregister_dialect)
341n/a self.assertRaises(csv.Error, csv.unregister_dialect, None)
342n/a self.assertRaises(csv.Error, csv.unregister_dialect, "nonesuch")
343n/a self.assertRaises(TypeError, csv.register_dialect, None)
344n/a self.assertRaises(TypeError, csv.register_dialect, None, None)
345n/a self.assertRaises(TypeError, csv.register_dialect, "nonesuch", 0, 0)
346n/a self.assertRaises(TypeError, csv.register_dialect, "nonesuch",
347n/a badargument=None)
348n/a self.assertRaises(TypeError, csv.register_dialect, "nonesuch",
349n/a quoting=None)
350n/a self.assertRaises(TypeError, csv.register_dialect, [])
351n/a
352n/a def test_registry(self):
353n/a class myexceltsv(csv.excel):
354n/a delimiter = "\t"
355n/a name = "myexceltsv"
356n/a expected_dialects = csv.list_dialects() + [name]
357n/a expected_dialects.sort()
358n/a csv.register_dialect(name, myexceltsv)
359n/a self.addCleanup(csv.unregister_dialect, name)
360n/a self.assertEqual(csv.get_dialect(name).delimiter, '\t')
361n/a got_dialects = sorted(csv.list_dialects())
362n/a self.assertEqual(expected_dialects, got_dialects)
363n/a
364n/a def test_register_kwargs(self):
365n/a name = 'fedcba'
366n/a csv.register_dialect(name, delimiter=';')
367n/a self.addCleanup(csv.unregister_dialect, name)
368n/a self.assertEqual(csv.get_dialect(name).delimiter, ';')
369n/a self.assertEqual([['X', 'Y', 'Z']], list(csv.reader(['X;Y;Z'], name)))
370n/a
371n/a def test_incomplete_dialect(self):
372n/a class myexceltsv(csv.Dialect):
373n/a delimiter = "\t"
374n/a self.assertRaises(csv.Error, myexceltsv)
375n/a
376n/a def test_space_dialect(self):
377n/a class space(csv.excel):
378n/a delimiter = " "
379n/a quoting = csv.QUOTE_NONE
380n/a escapechar = "\\"
381n/a
382n/a with TemporaryFile("w+") as fileobj:
383n/a fileobj.write("abc def\nc1ccccc1 benzene\n")
384n/a fileobj.seek(0)
385n/a reader = csv.reader(fileobj, dialect=space())
386n/a self.assertEqual(next(reader), ["abc", "def"])
387n/a self.assertEqual(next(reader), ["c1ccccc1", "benzene"])
388n/a
389n/a def compare_dialect_123(self, expected, *writeargs, **kwwriteargs):
390n/a
391n/a with TemporaryFile("w+", newline='', encoding="utf-8") as fileobj:
392n/a
393n/a writer = csv.writer(fileobj, *writeargs, **kwwriteargs)
394n/a writer.writerow([1,2,3])
395n/a fileobj.seek(0)
396n/a self.assertEqual(fileobj.read(), expected)
397n/a
398n/a def test_dialect_apply(self):
399n/a class testA(csv.excel):
400n/a delimiter = "\t"
401n/a class testB(csv.excel):
402n/a delimiter = ":"
403n/a class testC(csv.excel):
404n/a delimiter = "|"
405n/a class testUni(csv.excel):
406n/a delimiter = "\u039B"
407n/a
408n/a csv.register_dialect('testC', testC)
409n/a try:
410n/a self.compare_dialect_123("1,2,3\r\n")
411n/a self.compare_dialect_123("1\t2\t3\r\n", testA)
412n/a self.compare_dialect_123("1:2:3\r\n", dialect=testB())
413n/a self.compare_dialect_123("1|2|3\r\n", dialect='testC')
414n/a self.compare_dialect_123("1;2;3\r\n", dialect=testA,
415n/a delimiter=';')
416n/a self.compare_dialect_123("1\u039B2\u039B3\r\n",
417n/a dialect=testUni)
418n/a
419n/a finally:
420n/a csv.unregister_dialect('testC')
421n/a
422n/a def test_bad_dialect(self):
423n/a # Unknown parameter
424n/a self.assertRaises(TypeError, csv.reader, [], bad_attr = 0)
425n/a # Bad values
426n/a self.assertRaises(TypeError, csv.reader, [], delimiter = None)
427n/a self.assertRaises(TypeError, csv.reader, [], quoting = -1)
428n/a self.assertRaises(TypeError, csv.reader, [], quoting = 100)
429n/a
430n/a def test_copy(self):
431n/a for name in csv.list_dialects():
432n/a dialect = csv.get_dialect(name)
433n/a self.assertRaises(TypeError, copy.copy, dialect)
434n/a
435n/a def test_pickle(self):
436n/a for name in csv.list_dialects():
437n/a dialect = csv.get_dialect(name)
438n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
439n/a self.assertRaises(TypeError, pickle.dumps, dialect, proto)
440n/a
441n/aclass TestCsvBase(unittest.TestCase):
442n/a def readerAssertEqual(self, input, expected_result):
443n/a with TemporaryFile("w+", newline='') as fileobj:
444n/a fileobj.write(input)
445n/a fileobj.seek(0)
446n/a reader = csv.reader(fileobj, dialect = self.dialect)
447n/a fields = list(reader)
448n/a self.assertEqual(fields, expected_result)
449n/a
450n/a def writerAssertEqual(self, input, expected_result):
451n/a with TemporaryFile("w+", newline='') as fileobj:
452n/a writer = csv.writer(fileobj, dialect = self.dialect)
453n/a writer.writerows(input)
454n/a fileobj.seek(0)
455n/a self.assertEqual(fileobj.read(), expected_result)
456n/a
457n/aclass TestDialectExcel(TestCsvBase):
458n/a dialect = 'excel'
459n/a
460n/a def test_single(self):
461n/a self.readerAssertEqual('abc', [['abc']])
462n/a
463n/a def test_simple(self):
464n/a self.readerAssertEqual('1,2,3,4,5', [['1','2','3','4','5']])
465n/a
466n/a def test_blankline(self):
467n/a self.readerAssertEqual('', [])
468n/a
469n/a def test_empty_fields(self):
470n/a self.readerAssertEqual(',', [['', '']])
471n/a
472n/a def test_singlequoted(self):
473n/a self.readerAssertEqual('""', [['']])
474n/a
475n/a def test_singlequoted_left_empty(self):
476n/a self.readerAssertEqual('"",', [['','']])
477n/a
478n/a def test_singlequoted_right_empty(self):
479n/a self.readerAssertEqual(',""', [['','']])
480n/a
481n/a def test_single_quoted_quote(self):
482n/a self.readerAssertEqual('""""', [['"']])
483n/a
484n/a def test_quoted_quotes(self):
485n/a self.readerAssertEqual('""""""', [['""']])
486n/a
487n/a def test_inline_quote(self):
488n/a self.readerAssertEqual('a""b', [['a""b']])
489n/a
490n/a def test_inline_quotes(self):
491n/a self.readerAssertEqual('a"b"c', [['a"b"c']])
492n/a
493n/a def test_quotes_and_more(self):
494n/a # Excel would never write a field containing '"a"b', but when
495n/a # reading one, it will return 'ab'.
496n/a self.readerAssertEqual('"a"b', [['ab']])
497n/a
498n/a def test_lone_quote(self):
499n/a self.readerAssertEqual('a"b', [['a"b']])
500n/a
501n/a def test_quote_and_quote(self):
502n/a # Excel would never write a field containing '"a" "b"', but when
503n/a # reading one, it will return 'a "b"'.
504n/a self.readerAssertEqual('"a" "b"', [['a "b"']])
505n/a
506n/a def test_space_and_quote(self):
507n/a self.readerAssertEqual(' "a"', [[' "a"']])
508n/a
509n/a def test_quoted(self):
510n/a self.readerAssertEqual('1,2,3,"I think, therefore I am",5,6',
511n/a [['1', '2', '3',
512n/a 'I think, therefore I am',
513n/a '5', '6']])
514n/a
515n/a def test_quoted_quote(self):
516n/a self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"',
517n/a [['1', '2', '3',
518n/a '"I see," said the blind man',
519n/a 'as he picked up his hammer and saw']])
520n/a
521n/a def test_quoted_nl(self):
522n/a input = '''\
523n/a1,2,3,"""I see,""
524n/asaid the blind man","as he picked up his
525n/ahammer and saw"
526n/a9,8,7,6'''
527n/a self.readerAssertEqual(input,
528n/a [['1', '2', '3',
529n/a '"I see,"\nsaid the blind man',
530n/a 'as he picked up his\nhammer and saw'],
531n/a ['9','8','7','6']])
532n/a
533n/a def test_dubious_quote(self):
534n/a self.readerAssertEqual('12,12,1",', [['12', '12', '1"', '']])
535n/a
536n/a def test_null(self):
537n/a self.writerAssertEqual([], '')
538n/a
539n/a def test_single_writer(self):
540n/a self.writerAssertEqual([['abc']], 'abc\r\n')
541n/a
542n/a def test_simple_writer(self):
543n/a self.writerAssertEqual([[1, 2, 'abc', 3, 4]], '1,2,abc,3,4\r\n')
544n/a
545n/a def test_quotes(self):
546n/a self.writerAssertEqual([[1, 2, 'a"bc"', 3, 4]], '1,2,"a""bc""",3,4\r\n')
547n/a
548n/a def test_quote_fieldsep(self):
549n/a self.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
550n/a
551n/a def test_newlines(self):
552n/a self.writerAssertEqual([[1, 2, 'a\nbc', 3, 4]], '1,2,"a\nbc",3,4\r\n')
553n/a
554n/aclass EscapedExcel(csv.excel):
555n/a quoting = csv.QUOTE_NONE
556n/a escapechar = '\\'
557n/a
558n/aclass TestEscapedExcel(TestCsvBase):
559n/a dialect = EscapedExcel()
560n/a
561n/a def test_escape_fieldsep(self):
562n/a self.writerAssertEqual([['abc,def']], 'abc\\,def\r\n')
563n/a
564n/a def test_read_escape_fieldsep(self):
565n/a self.readerAssertEqual('abc\\,def\r\n', [['abc,def']])
566n/a
567n/aclass TestDialectUnix(TestCsvBase):
568n/a dialect = 'unix'
569n/a
570n/a def test_simple_writer(self):
571n/a self.writerAssertEqual([[1, 'abc def', 'abc']], '"1","abc def","abc"\n')
572n/a
573n/a def test_simple_reader(self):
574n/a self.readerAssertEqual('"1","abc def","abc"\n', [['1', 'abc def', 'abc']])
575n/a
576n/aclass QuotedEscapedExcel(csv.excel):
577n/a quoting = csv.QUOTE_NONNUMERIC
578n/a escapechar = '\\'
579n/a
580n/aclass TestQuotedEscapedExcel(TestCsvBase):
581n/a dialect = QuotedEscapedExcel()
582n/a
583n/a def test_write_escape_fieldsep(self):
584n/a self.writerAssertEqual([['abc,def']], '"abc,def"\r\n')
585n/a
586n/a def test_read_escape_fieldsep(self):
587n/a self.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']])
588n/a
589n/aclass TestDictFields(unittest.TestCase):
590n/a ### "long" means the row is longer than the number of fieldnames
591n/a ### "short" means there are fewer elements in the row than fieldnames
592n/a def test_write_simple_dict(self):
593n/a with TemporaryFile("w+", newline='') as fileobj:
594n/a writer = csv.DictWriter(fileobj, fieldnames = ["f1", "f2", "f3"])
595n/a writer.writeheader()
596n/a fileobj.seek(0)
597n/a self.assertEqual(fileobj.readline(), "f1,f2,f3\r\n")
598n/a writer.writerow({"f1": 10, "f3": "abc"})
599n/a fileobj.seek(0)
600n/a fileobj.readline() # header
601n/a self.assertEqual(fileobj.read(), "10,,abc\r\n")
602n/a
603n/a def test_write_multiple_dict_rows(self):
604n/a fileobj = StringIO()
605n/a writer = csv.DictWriter(fileobj, fieldnames=["f1", "f2", "f3"])
606n/a writer.writeheader()
607n/a self.assertEqual(fileobj.getvalue(), "f1,f2,f3\r\n")
608n/a writer.writerows([{"f1": 1, "f2": "abc", "f3": "f"},
609n/a {"f1": 2, "f2": 5, "f3": "xyz"}])
610n/a self.assertEqual(fileobj.getvalue(),
611n/a "f1,f2,f3\r\n1,abc,f\r\n2,5,xyz\r\n")
612n/a
613n/a def test_write_no_fields(self):
614n/a fileobj = StringIO()
615n/a self.assertRaises(TypeError, csv.DictWriter, fileobj)
616n/a
617n/a def test_write_fields_not_in_fieldnames(self):
618n/a with TemporaryFile("w+", newline='') as fileobj:
619n/a writer = csv.DictWriter(fileobj, fieldnames = ["f1", "f2", "f3"])
620n/a # Of special note is the non-string key (issue 19449)
621n/a with self.assertRaises(ValueError) as cx:
622n/a writer.writerow({"f4": 10, "f2": "spam", 1: "abc"})
623n/a exception = str(cx.exception)
624n/a self.assertIn("fieldnames", exception)
625n/a self.assertIn("'f4'", exception)
626n/a self.assertNotIn("'f2'", exception)
627n/a self.assertIn("1", exception)
628n/a
629n/a def test_typo_in_extrasaction_raises_error(self):
630n/a fileobj = StringIO()
631n/a self.assertRaises(ValueError, csv.DictWriter, fileobj, ['f1', 'f2'],
632n/a extrasaction="raised")
633n/a
634n/a def test_write_field_not_in_field_names_raise(self):
635n/a fileobj = StringIO()
636n/a writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="raise")
637n/a dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3}
638n/a self.assertRaises(ValueError, csv.DictWriter.writerow, writer, dictrow)
639n/a
640n/a def test_write_field_not_in_field_names_ignore(self):
641n/a fileobj = StringIO()
642n/a writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="ignore")
643n/a dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3}
644n/a csv.DictWriter.writerow(writer, dictrow)
645n/a self.assertEqual(fileobj.getvalue(), "1,2\r\n")
646n/a
647n/a def test_read_dict_fields(self):
648n/a with TemporaryFile("w+") as fileobj:
649n/a fileobj.write("1,2,abc\r\n")
650n/a fileobj.seek(0)
651n/a reader = csv.DictReader(fileobj,
652n/a fieldnames=["f1", "f2", "f3"])
653n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2', "f3": 'abc'})
654n/a
655n/a def test_read_dict_no_fieldnames(self):
656n/a with TemporaryFile("w+") as fileobj:
657n/a fileobj.write("f1,f2,f3\r\n1,2,abc\r\n")
658n/a fileobj.seek(0)
659n/a reader = csv.DictReader(fileobj)
660n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2', "f3": 'abc'})
661n/a self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
662n/a
663n/a # Two test cases to make sure existing ways of implicitly setting
664n/a # fieldnames continue to work. Both arise from discussion in issue3436.
665n/a def test_read_dict_fieldnames_from_file(self):
666n/a with TemporaryFile("w+") as fileobj:
667n/a fileobj.write("f1,f2,f3\r\n1,2,abc\r\n")
668n/a fileobj.seek(0)
669n/a reader = csv.DictReader(fileobj,
670n/a fieldnames=next(csv.reader(fileobj)))
671n/a self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
672n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2', "f3": 'abc'})
673n/a
674n/a def test_read_dict_fieldnames_chain(self):
675n/a import itertools
676n/a with TemporaryFile("w+") as fileobj:
677n/a fileobj.write("f1,f2,f3\r\n1,2,abc\r\n")
678n/a fileobj.seek(0)
679n/a reader = csv.DictReader(fileobj)
680n/a first = next(reader)
681n/a for row in itertools.chain([first], reader):
682n/a self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
683n/a self.assertEqual(row, {"f1": '1', "f2": '2', "f3": 'abc'})
684n/a
685n/a def test_read_long(self):
686n/a with TemporaryFile("w+") as fileobj:
687n/a fileobj.write("1,2,abc,4,5,6\r\n")
688n/a fileobj.seek(0)
689n/a reader = csv.DictReader(fileobj,
690n/a fieldnames=["f1", "f2"])
691n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2',
692n/a None: ["abc", "4", "5", "6"]})
693n/a
694n/a def test_read_long_with_rest(self):
695n/a with TemporaryFile("w+") as fileobj:
696n/a fileobj.write("1,2,abc,4,5,6\r\n")
697n/a fileobj.seek(0)
698n/a reader = csv.DictReader(fileobj,
699n/a fieldnames=["f1", "f2"], restkey="_rest")
700n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2',
701n/a "_rest": ["abc", "4", "5", "6"]})
702n/a
703n/a def test_read_long_with_rest_no_fieldnames(self):
704n/a with TemporaryFile("w+") as fileobj:
705n/a fileobj.write("f1,f2\r\n1,2,abc,4,5,6\r\n")
706n/a fileobj.seek(0)
707n/a reader = csv.DictReader(fileobj, restkey="_rest")
708n/a self.assertEqual(reader.fieldnames, ["f1", "f2"])
709n/a self.assertEqual(next(reader), {"f1": '1', "f2": '2',
710n/a "_rest": ["abc", "4", "5", "6"]})
711n/a
712n/a def test_read_short(self):
713n/a with TemporaryFile("w+") as fileobj:
714n/a fileobj.write("1,2,abc,4,5,6\r\n1,2,abc\r\n")
715n/a fileobj.seek(0)
716n/a reader = csv.DictReader(fileobj,
717n/a fieldnames="1 2 3 4 5 6".split(),
718n/a restval="DEFAULT")
719n/a self.assertEqual(next(reader), {"1": '1', "2": '2', "3": 'abc',
720n/a "4": '4', "5": '5', "6": '6'})
721n/a self.assertEqual(next(reader), {"1": '1', "2": '2', "3": 'abc',
722n/a "4": 'DEFAULT', "5": 'DEFAULT',
723n/a "6": 'DEFAULT'})
724n/a
725n/a def test_read_multi(self):
726n/a sample = [
727n/a '2147483648,43.0e12,17,abc,def\r\n',
728n/a '147483648,43.0e2,17,abc,def\r\n',
729n/a '47483648,43.0,170,abc,def\r\n'
730n/a ]
731n/a
732n/a reader = csv.DictReader(sample,
733n/a fieldnames="i1 float i2 s1 s2".split())
734n/a self.assertEqual(next(reader), {"i1": '2147483648',
735n/a "float": '43.0e12',
736n/a "i2": '17',
737n/a "s1": 'abc',
738n/a "s2": 'def'})
739n/a
740n/a def test_read_with_blanks(self):
741n/a reader = csv.DictReader(["1,2,abc,4,5,6\r\n","\r\n",
742n/a "1,2,abc,4,5,6\r\n"],
743n/a fieldnames="1 2 3 4 5 6".split())
744n/a self.assertEqual(next(reader), {"1": '1', "2": '2', "3": 'abc',
745n/a "4": '4', "5": '5', "6": '6'})
746n/a self.assertEqual(next(reader), {"1": '1', "2": '2', "3": 'abc',
747n/a "4": '4', "5": '5', "6": '6'})
748n/a
749n/a def test_read_semi_sep(self):
750n/a reader = csv.DictReader(["1;2;abc;4;5;6\r\n"],
751n/a fieldnames="1 2 3 4 5 6".split(),
752n/a delimiter=';')
753n/a self.assertEqual(next(reader), {"1": '1', "2": '2', "3": 'abc',
754n/a "4": '4', "5": '5', "6": '6'})
755n/a
756n/aclass TestArrayWrites(unittest.TestCase):
757n/a def test_int_write(self):
758n/a import array
759n/a contents = [(20-i) for i in range(20)]
760n/a a = array.array('i', contents)
761n/a
762n/a with TemporaryFile("w+", newline='') as fileobj:
763n/a writer = csv.writer(fileobj, dialect="excel")
764n/a writer.writerow(a)
765n/a expected = ",".join([str(i) for i in a])+"\r\n"
766n/a fileobj.seek(0)
767n/a self.assertEqual(fileobj.read(), expected)
768n/a
769n/a def test_double_write(self):
770n/a import array
771n/a contents = [(20-i)*0.1 for i in range(20)]
772n/a a = array.array('d', contents)
773n/a with TemporaryFile("w+", newline='') as fileobj:
774n/a writer = csv.writer(fileobj, dialect="excel")
775n/a writer.writerow(a)
776n/a expected = ",".join([str(i) for i in a])+"\r\n"
777n/a fileobj.seek(0)
778n/a self.assertEqual(fileobj.read(), expected)
779n/a
780n/a def test_float_write(self):
781n/a import array
782n/a contents = [(20-i)*0.1 for i in range(20)]
783n/a a = array.array('f', contents)
784n/a with TemporaryFile("w+", newline='') as fileobj:
785n/a writer = csv.writer(fileobj, dialect="excel")
786n/a writer.writerow(a)
787n/a expected = ",".join([str(i) for i in a])+"\r\n"
788n/a fileobj.seek(0)
789n/a self.assertEqual(fileobj.read(), expected)
790n/a
791n/a def test_char_write(self):
792n/a import array, string
793n/a a = array.array('u', string.ascii_letters)
794n/a
795n/a with TemporaryFile("w+", newline='') as fileobj:
796n/a writer = csv.writer(fileobj, dialect="excel")
797n/a writer.writerow(a)
798n/a expected = ",".join(a)+"\r\n"
799n/a fileobj.seek(0)
800n/a self.assertEqual(fileobj.read(), expected)
801n/a
802n/aclass TestDialectValidity(unittest.TestCase):
803n/a def test_quoting(self):
804n/a class mydialect(csv.Dialect):
805n/a delimiter = ";"
806n/a escapechar = '\\'
807n/a doublequote = False
808n/a skipinitialspace = True
809n/a lineterminator = '\r\n'
810n/a quoting = csv.QUOTE_NONE
811n/a d = mydialect()
812n/a self.assertEqual(d.quoting, csv.QUOTE_NONE)
813n/a
814n/a mydialect.quoting = None
815n/a self.assertRaises(csv.Error, mydialect)
816n/a
817n/a mydialect.doublequote = True
818n/a mydialect.quoting = csv.QUOTE_ALL
819n/a mydialect.quotechar = '"'
820n/a d = mydialect()
821n/a self.assertEqual(d.quoting, csv.QUOTE_ALL)
822n/a self.assertEqual(d.quotechar, '"')
823n/a self.assertTrue(d.doublequote)
824n/a
825n/a mydialect.quotechar = "''"
826n/a with self.assertRaises(csv.Error) as cm:
827n/a mydialect()
828n/a self.assertEqual(str(cm.exception),
829n/a '"quotechar" must be a 1-character string')
830n/a
831n/a mydialect.quotechar = 4
832n/a with self.assertRaises(csv.Error) as cm:
833n/a mydialect()
834n/a self.assertEqual(str(cm.exception),
835n/a '"quotechar" must be string, not int')
836n/a
837n/a def test_delimiter(self):
838n/a class mydialect(csv.Dialect):
839n/a delimiter = ";"
840n/a escapechar = '\\'
841n/a doublequote = False
842n/a skipinitialspace = True
843n/a lineterminator = '\r\n'
844n/a quoting = csv.QUOTE_NONE
845n/a d = mydialect()
846n/a self.assertEqual(d.delimiter, ";")
847n/a
848n/a mydialect.delimiter = ":::"
849n/a with self.assertRaises(csv.Error) as cm:
850n/a mydialect()
851n/a self.assertEqual(str(cm.exception),
852n/a '"delimiter" must be a 1-character string')
853n/a
854n/a mydialect.delimiter = ""
855n/a with self.assertRaises(csv.Error) as cm:
856n/a mydialect()
857n/a self.assertEqual(str(cm.exception),
858n/a '"delimiter" must be a 1-character string')
859n/a
860n/a mydialect.delimiter = b","
861n/a with self.assertRaises(csv.Error) as cm:
862n/a mydialect()
863n/a self.assertEqual(str(cm.exception),
864n/a '"delimiter" must be string, not bytes')
865n/a
866n/a mydialect.delimiter = 4
867n/a with self.assertRaises(csv.Error) as cm:
868n/a mydialect()
869n/a self.assertEqual(str(cm.exception),
870n/a '"delimiter" must be string, not int')
871n/a
872n/a def test_lineterminator(self):
873n/a class mydialect(csv.Dialect):
874n/a delimiter = ";"
875n/a escapechar = '\\'
876n/a doublequote = False
877n/a skipinitialspace = True
878n/a lineterminator = '\r\n'
879n/a quoting = csv.QUOTE_NONE
880n/a d = mydialect()
881n/a self.assertEqual(d.lineterminator, '\r\n')
882n/a
883n/a mydialect.lineterminator = ":::"
884n/a d = mydialect()
885n/a self.assertEqual(d.lineterminator, ":::")
886n/a
887n/a mydialect.lineterminator = 4
888n/a with self.assertRaises(csv.Error) as cm:
889n/a mydialect()
890n/a self.assertEqual(str(cm.exception),
891n/a '"lineterminator" must be a string')
892n/a
893n/a def test_invalid_chars(self):
894n/a def create_invalid(field_name, value):
895n/a class mydialect(csv.Dialect):
896n/a pass
897n/a setattr(mydialect, field_name, value)
898n/a d = mydialect()
899n/a
900n/a for field_name in ("delimiter", "escapechar", "quotechar"):
901n/a with self.subTest(field_name=field_name):
902n/a self.assertRaises(csv.Error, create_invalid, field_name, "")
903n/a self.assertRaises(csv.Error, create_invalid, field_name, "abc")
904n/a self.assertRaises(csv.Error, create_invalid, field_name, b'x')
905n/a self.assertRaises(csv.Error, create_invalid, field_name, 5)
906n/a
907n/a
908n/aclass TestSniffer(unittest.TestCase):
909n/a sample1 = """\
910n/aHarry's, Arlington Heights, IL, 2/1/03, Kimi Hayes
911n/aShark City, Glendale Heights, IL, 12/28/02, Prezence
912n/aTommy's Place, Blue Island, IL, 12/28/02, Blue Sunday/White Crow
913n/aStonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
914n/a"""
915n/a sample2 = """\
916n/a'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes'
917n/a'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence'
918n/a'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow'
919n/a'Stonecutters ''Seafood'' and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
920n/a"""
921n/a header1 = '''\
922n/a"venue","city","state","date","performers"
923n/a'''
924n/a sample3 = '''\
925n/a05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
926n/a05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
927n/a05/05/03?05/05/03?05/05/03?05/05/03?05/05/03?05/05/03
928n/a'''
929n/a
930n/a sample4 = '''\
931n/a2147483648;43.0e12;17;abc;def
932n/a147483648;43.0e2;17;abc;def
933n/a47483648;43.0;170;abc;def
934n/a'''
935n/a
936n/a sample5 = "aaa\tbbb\r\nAAA\t\r\nBBB\t\r\n"
937n/a sample6 = "a|b|c\r\nd|e|f\r\n"
938n/a sample7 = "'a'|'b'|'c'\r\n'd'|e|f\r\n"
939n/a
940n/a# Issue 18155: Use a delimiter that is a special char to regex:
941n/a
942n/a header2 = '''\
943n/a"venue"+"city"+"state"+"date"+"performers"
944n/a'''
945n/a sample8 = """\
946n/aHarry's+ Arlington Heights+ IL+ 2/1/03+ Kimi Hayes
947n/aShark City+ Glendale Heights+ IL+ 12/28/02+ Prezence
948n/aTommy's Place+ Blue Island+ IL+ 12/28/02+ Blue Sunday/White Crow
949n/aStonecutters Seafood and Chop House+ Lemont+ IL+ 12/19/02+ Week Back
950n/a"""
951n/a sample9 = """\
952n/a'Harry''s'+ Arlington Heights'+ 'IL'+ '2/1/03'+ 'Kimi Hayes'
953n/a'Shark City'+ Glendale Heights'+' IL'+ '12/28/02'+ 'Prezence'
954n/a'Tommy''s Place'+ Blue Island'+ 'IL'+ '12/28/02'+ 'Blue Sunday/White Crow'
955n/a'Stonecutters ''Seafood'' and Chop House'+ 'Lemont'+ 'IL'+ '12/19/02'+ 'Week Back'
956n/a"""
957n/a
958n/a def test_has_header(self):
959n/a sniffer = csv.Sniffer()
960n/a self.assertEqual(sniffer.has_header(self.sample1), False)
961n/a self.assertEqual(sniffer.has_header(self.header1 + self.sample1),
962n/a True)
963n/a
964n/a def test_has_header_regex_special_delimiter(self):
965n/a sniffer = csv.Sniffer()
966n/a self.assertEqual(sniffer.has_header(self.sample8), False)
967n/a self.assertEqual(sniffer.has_header(self.header2 + self.sample8),
968n/a True)
969n/a
970n/a def test_sniff(self):
971n/a sniffer = csv.Sniffer()
972n/a dialect = sniffer.sniff(self.sample1)
973n/a self.assertEqual(dialect.delimiter, ",")
974n/a self.assertEqual(dialect.quotechar, '"')
975n/a self.assertEqual(dialect.skipinitialspace, True)
976n/a
977n/a dialect = sniffer.sniff(self.sample2)
978n/a self.assertEqual(dialect.delimiter, ":")
979n/a self.assertEqual(dialect.quotechar, "'")
980n/a self.assertEqual(dialect.skipinitialspace, False)
981n/a
982n/a def test_delimiters(self):
983n/a sniffer = csv.Sniffer()
984n/a dialect = sniffer.sniff(self.sample3)
985n/a # given that all three lines in sample3 are equal,
986n/a # I think that any character could have been 'guessed' as the
987n/a # delimiter, depending on dictionary order
988n/a self.assertIn(dialect.delimiter, self.sample3)
989n/a dialect = sniffer.sniff(self.sample3, delimiters="?,")
990n/a self.assertEqual(dialect.delimiter, "?")
991n/a dialect = sniffer.sniff(self.sample3, delimiters="/,")
992n/a self.assertEqual(dialect.delimiter, "/")
993n/a dialect = sniffer.sniff(self.sample4)
994n/a self.assertEqual(dialect.delimiter, ";")
995n/a dialect = sniffer.sniff(self.sample5)
996n/a self.assertEqual(dialect.delimiter, "\t")
997n/a dialect = sniffer.sniff(self.sample6)
998n/a self.assertEqual(dialect.delimiter, "|")
999n/a dialect = sniffer.sniff(self.sample7)
1000n/a self.assertEqual(dialect.delimiter, "|")
1001n/a self.assertEqual(dialect.quotechar, "'")
1002n/a dialect = sniffer.sniff(self.sample8)
1003n/a self.assertEqual(dialect.delimiter, '+')
1004n/a dialect = sniffer.sniff(self.sample9)
1005n/a self.assertEqual(dialect.delimiter, '+')
1006n/a self.assertEqual(dialect.quotechar, "'")
1007n/a
1008n/a def test_doublequote(self):
1009n/a sniffer = csv.Sniffer()
1010n/a dialect = sniffer.sniff(self.header1)
1011n/a self.assertFalse(dialect.doublequote)
1012n/a dialect = sniffer.sniff(self.header2)
1013n/a self.assertFalse(dialect.doublequote)
1014n/a dialect = sniffer.sniff(self.sample2)
1015n/a self.assertTrue(dialect.doublequote)
1016n/a dialect = sniffer.sniff(self.sample8)
1017n/a self.assertFalse(dialect.doublequote)
1018n/a dialect = sniffer.sniff(self.sample9)
1019n/a self.assertTrue(dialect.doublequote)
1020n/a
1021n/aclass NUL:
1022n/a def write(s, *args):
1023n/a pass
1024n/a writelines = write
1025n/a
1026n/a@unittest.skipUnless(hasattr(sys, "gettotalrefcount"),
1027n/a 'requires sys.gettotalrefcount()')
1028n/aclass TestLeaks(unittest.TestCase):
1029n/a def test_create_read(self):
1030n/a delta = 0
1031n/a lastrc = sys.gettotalrefcount()
1032n/a for i in range(20):
1033n/a gc.collect()
1034n/a self.assertEqual(gc.garbage, [])
1035n/a rc = sys.gettotalrefcount()
1036n/a csv.reader(["a,b,c\r\n"])
1037n/a csv.reader(["a,b,c\r\n"])
1038n/a csv.reader(["a,b,c\r\n"])
1039n/a delta = rc-lastrc
1040n/a lastrc = rc
1041n/a # if csv.reader() leaks, last delta should be 3 or more
1042n/a self.assertEqual(delta < 3, True)
1043n/a
1044n/a def test_create_write(self):
1045n/a delta = 0
1046n/a lastrc = sys.gettotalrefcount()
1047n/a s = NUL()
1048n/a for i in range(20):
1049n/a gc.collect()
1050n/a self.assertEqual(gc.garbage, [])
1051n/a rc = sys.gettotalrefcount()
1052n/a csv.writer(s)
1053n/a csv.writer(s)
1054n/a csv.writer(s)
1055n/a delta = rc-lastrc
1056n/a lastrc = rc
1057n/a # if csv.writer() leaks, last delta should be 3 or more
1058n/a self.assertEqual(delta < 3, True)
1059n/a
1060n/a def test_read(self):
1061n/a delta = 0
1062n/a rows = ["a,b,c\r\n"]*5
1063n/a lastrc = sys.gettotalrefcount()
1064n/a for i in range(20):
1065n/a gc.collect()
1066n/a self.assertEqual(gc.garbage, [])
1067n/a rc = sys.gettotalrefcount()
1068n/a rdr = csv.reader(rows)
1069n/a for row in rdr:
1070n/a pass
1071n/a delta = rc-lastrc
1072n/a lastrc = rc
1073n/a # if reader leaks during read, delta should be 5 or more
1074n/a self.assertEqual(delta < 5, True)
1075n/a
1076n/a def test_write(self):
1077n/a delta = 0
1078n/a rows = [[1,2,3]]*5
1079n/a s = NUL()
1080n/a lastrc = sys.gettotalrefcount()
1081n/a for i in range(20):
1082n/a gc.collect()
1083n/a self.assertEqual(gc.garbage, [])
1084n/a rc = sys.gettotalrefcount()
1085n/a writer = csv.writer(s)
1086n/a for row in rows:
1087n/a writer.writerow(row)
1088n/a delta = rc-lastrc
1089n/a lastrc = rc
1090n/a # if writer leaks during write, last delta should be 5 or more
1091n/a self.assertEqual(delta < 5, True)
1092n/a
1093n/aclass TestUnicode(unittest.TestCase):
1094n/a
1095n/a names = ["Martin von Löwis",
1096n/a "Marc André Lemburg",
1097n/a "Guido van Rossum",
1098n/a "François Pinard"]
1099n/a
1100n/a def test_unicode_read(self):
1101n/a with TemporaryFile("w+", newline='', encoding="utf-8") as fileobj:
1102n/a fileobj.write(",".join(self.names) + "\r\n")
1103n/a fileobj.seek(0)
1104n/a reader = csv.reader(fileobj)
1105n/a self.assertEqual(list(reader), [self.names])
1106n/a
1107n/a
1108n/a def test_unicode_write(self):
1109n/a with TemporaryFile("w+", newline='', encoding="utf-8") as fileobj:
1110n/a writer = csv.writer(fileobj)
1111n/a writer.writerow(self.names)
1112n/a expected = ",".join(self.names)+"\r\n"
1113n/a fileobj.seek(0)
1114n/a self.assertEqual(fileobj.read(), expected)
1115n/a
1116n/aclass KeyOrderingTest(unittest.TestCase):
1117n/a
1118n/a def test_ordering_for_the_dict_reader_and_writer(self):
1119n/a resultset = set()
1120n/a for keys in permutations("abcde"):
1121n/a with TemporaryFile('w+', newline='', encoding="utf-8") as fileobject:
1122n/a dw = csv.DictWriter(fileobject, keys)
1123n/a dw.writeheader()
1124n/a fileobject.seek(0)
1125n/a dr = csv.DictReader(fileobject)
1126n/a kt = tuple(dr.fieldnames)
1127n/a self.assertEqual(keys, kt)
1128n/a resultset.add(kt)
1129n/a # Final sanity check: were all permutations unique?
1130n/a self.assertEqual(len(resultset), 120, "Key ordering: some key permutations not collected (expected 120)")
1131n/a
1132n/a def test_ordered_dict_reader(self):
1133n/a data = dedent('''\
1134n/a FirstName,LastName
1135n/a Eric,Idle
1136n/a Graham,Chapman,Over1,Over2
1137n/a
1138n/a Under1
1139n/a John,Cleese
1140n/a ''').splitlines()
1141n/a
1142n/a self.assertEqual(list(csv.DictReader(data)),
1143n/a [OrderedDict([('FirstName', 'Eric'), ('LastName', 'Idle')]),
1144n/a OrderedDict([('FirstName', 'Graham'), ('LastName', 'Chapman'),
1145n/a (None, ['Over1', 'Over2'])]),
1146n/a OrderedDict([('FirstName', 'Under1'), ('LastName', None)]),
1147n/a OrderedDict([('FirstName', 'John'), ('LastName', 'Cleese')]),
1148n/a ])
1149n/a
1150n/a self.assertEqual(list(csv.DictReader(data, restkey='OtherInfo')),
1151n/a [OrderedDict([('FirstName', 'Eric'), ('LastName', 'Idle')]),
1152n/a OrderedDict([('FirstName', 'Graham'), ('LastName', 'Chapman'),
1153n/a ('OtherInfo', ['Over1', 'Over2'])]),
1154n/a OrderedDict([('FirstName', 'Under1'), ('LastName', None)]),
1155n/a OrderedDict([('FirstName', 'John'), ('LastName', 'Cleese')]),
1156n/a ])
1157n/a
1158n/a del data[0] # Remove the header row
1159n/a self.assertEqual(list(csv.DictReader(data, fieldnames=['fname', 'lname'])),
1160n/a [OrderedDict([('fname', 'Eric'), ('lname', 'Idle')]),
1161n/a OrderedDict([('fname', 'Graham'), ('lname', 'Chapman'),
1162n/a (None, ['Over1', 'Over2'])]),
1163n/a OrderedDict([('fname', 'Under1'), ('lname', None)]),
1164n/a OrderedDict([('fname', 'John'), ('lname', 'Cleese')]),
1165n/a ])
1166n/a
1167n/a
1168n/aclass MiscTestCase(unittest.TestCase):
1169n/a def test__all__(self):
1170n/a extra = {'__doc__', '__version__'}
1171n/a support.check__all__(self, csv, ('csv', '_csv'), extra=extra)
1172n/a
1173n/a
1174n/aif __name__ == '__main__':
1175n/a unittest.main()