test_csv.py 44 KB

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