test_tablib.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """Tests for Tablib."""
  4. import unittest
  5. import sys
  6. import tablib
  7. from tablib.compat import markup
  8. class TablibTestCase(unittest.TestCase):
  9. """Tablib test cases."""
  10. def setUp(self):
  11. """Create simple data set with headers."""
  12. global data, book
  13. data = tablib.Dataset()
  14. book = tablib.Databook()
  15. self.headers = ('first_name', 'last_name', 'gpa')
  16. self.john = ('John', 'Adams', 90)
  17. self.george = ('George', 'Washington', 67)
  18. self.tom = ('Thomas', 'Jefferson', 50)
  19. self.founders = tablib.Dataset(headers=self.headers)
  20. self.founders.append(self.john)
  21. self.founders.append(self.george)
  22. self.founders.append(self.tom)
  23. def tearDown(self):
  24. """Teardown."""
  25. pass
  26. def test_empty_append(self):
  27. """Verify append() correctly adds tuple with no headers."""
  28. new_row = (1, 2, 3)
  29. data.append(new_row)
  30. # Verify width/data
  31. self.assertTrue(data.width == len(new_row))
  32. self.assertTrue(data[0] == new_row)
  33. def test_empty_append_with_headers(self):
  34. """Verify append() correctly detects mismatch of number of
  35. headers and data.
  36. """
  37. data.headers = ['first', 'second']
  38. new_row = (1, 2, 3, 4)
  39. self.assertRaises(tablib.InvalidDimensions, data.append, new_row)
  40. def test_add_column(self):
  41. """Verify adding column works with/without headers."""
  42. data.append(['kenneth'])
  43. data.append(['bessie'])
  44. new_col = ['reitz', 'monke']
  45. data.append_col(new_col)
  46. self.assertEqual(data[0], ('kenneth', 'reitz'))
  47. self.assertEqual(data.width, 2)
  48. # With Headers
  49. data.headers = ('fname', 'lname')
  50. new_col = [21, 22]
  51. data.append_col(new_col, header='age')
  52. self.assertEqual(data['age'], new_col)
  53. def test_add_column_no_data_no_headers(self):
  54. """Verify adding new column with no headers."""
  55. new_col = ('reitz', 'monke')
  56. data.append_col(new_col)
  57. self.assertEqual(data[0], tuple([new_col[0]]))
  58. self.assertEqual(data.width, 1)
  59. self.assertEqual(data.height, len(new_col))
  60. def test_add_callable_column(self):
  61. """Verify adding column with values specified as callable."""
  62. new_col = [lambda x: x[0]]
  63. self.founders.append_col(new_col, header='first_again')
  64. def test_header_slicing(self):
  65. """Verify slicing by headers."""
  66. self.assertEqual(self.founders['first_name'],
  67. [self.john[0], self.george[0], self.tom[0]])
  68. self.assertEqual(self.founders['last_name'],
  69. [self.john[1], self.george[1], self.tom[1]])
  70. self.assertEqual(self.founders['gpa'],
  71. [self.john[2], self.george[2], self.tom[2]])
  72. def test_data_slicing(self):
  73. """Verify slicing by data."""
  74. # Slice individual rows
  75. self.assertEqual(self.founders[0], self.john)
  76. self.assertEqual(self.founders[:1], [self.john])
  77. self.assertEqual(self.founders[1:2], [self.george])
  78. self.assertEqual(self.founders[-1], self.tom)
  79. self.assertEqual(self.founders[3:], [])
  80. # Slice multiple rows
  81. self.assertEqual(self.founders[:], [self.john, self.george, self.tom])
  82. self.assertEqual(self.founders[0:2], [self.john, self.george])
  83. self.assertEqual(self.founders[1:3], [self.george, self.tom])
  84. self.assertEqual(self.founders[2:], [self.tom])
  85. def test_delete(self):
  86. """Verify deleting from dataset works."""
  87. # Delete from front of object
  88. del self.founders[0]
  89. self.assertEqual(self.founders[:], [self.george, self.tom])
  90. # Verify dimensions, width should NOT change
  91. self.assertEqual(self.founders.height, 2)
  92. self.assertEqual(self.founders.width, 3)
  93. # Delete from back of object
  94. del self.founders[1]
  95. self.assertEqual(self.founders[:], [self.george])
  96. # Verify dimensions, width should NOT change
  97. self.assertEqual(self.founders.height, 1)
  98. self.assertEqual(self.founders.width, 3)
  99. # Delete from invalid index
  100. self.assertRaises(IndexError, self.founders.__delitem__, 3)
  101. def test_csv_export(self):
  102. """Verify exporting dataset object as CSV."""
  103. # Build up the csv string with headers first, followed by each row
  104. csv = ''
  105. for col in self.headers:
  106. csv += col + ','
  107. csv = csv.strip(',') + '\r\n'
  108. for founder in self.founders:
  109. for col in founder:
  110. csv += str(col) + ','
  111. csv = csv.strip(',') + '\r\n'
  112. self.assertEqual(csv, self.founders.csv)
  113. def test_tsv_export(self):
  114. """Verify exporting dataset object as CSV."""
  115. # Build up the csv string with headers first, followed by each row
  116. tsv = ''
  117. for col in self.headers:
  118. tsv += col + '\t'
  119. tsv = tsv.strip('\t') + '\r\n'
  120. for founder in self.founders:
  121. for col in founder:
  122. tsv += str(col) + '\t'
  123. tsv = tsv.strip('\t') + '\r\n'
  124. self.assertEqual(tsv, self.founders.tsv)
  125. def test_html_export(self):
  126. """HTML export"""
  127. html = markup.page()
  128. html.table.open()
  129. html.thead.open()
  130. html.tr(markup.oneliner.th(self.founders.headers))
  131. html.thead.close()
  132. for founder in self.founders:
  133. html.tr(markup.oneliner.td(founder))
  134. html.table.close()
  135. html = str(html)
  136. self.assertEqual(html, self.founders.html)
  137. def test_unicode_append(self):
  138. """Passes in a single unicode charecter and exports."""
  139. new_row = ('å', 'é')
  140. data.append(new_row)
  141. data.json
  142. data.yaml
  143. data.csv
  144. data.tsv
  145. data.xls
  146. data.xlsx
  147. data.ods
  148. data.html
  149. def test_book_export_no_exceptions(self):
  150. """Test that varoius exports don't error out."""
  151. book = tablib.Databook()
  152. book.add_sheet(data)
  153. book.json
  154. book.yaml
  155. book.xls
  156. book.xlsx
  157. book.ods
  158. def test_json_import_set(self):
  159. """Generate and import JSON set serialization."""
  160. data.append(self.john)
  161. data.append(self.george)
  162. data.headers = self.headers
  163. _json = data.json
  164. data.json = _json
  165. self.assertEqual(_json, data.json)
  166. def test_json_import_book(self):
  167. """Generate and import JSON book serialization."""
  168. data.append(self.john)
  169. data.append(self.george)
  170. data.headers = self.headers
  171. book.add_sheet(data)
  172. _json = book.json
  173. book.json = _json
  174. self.assertEqual(_json, book.json)
  175. def test_yaml_import_set(self):
  176. """Generate and import YAML set serialization."""
  177. data.append(self.john)
  178. data.append(self.george)
  179. data.headers = self.headers
  180. _yaml = data.yaml
  181. data.yaml = _yaml
  182. self.assertEqual(_yaml, data.yaml)
  183. def test_yaml_import_book(self):
  184. """Generate and import YAML book serialization."""
  185. data.append(self.john)
  186. data.append(self.george)
  187. data.headers = self.headers
  188. book.add_sheet(data)
  189. _yaml = book.yaml
  190. book.yaml = _yaml
  191. self.assertEqual(_yaml, book.yaml)
  192. def test_csv_import_set(self):
  193. """Generate and import CSV set serialization."""
  194. data.append(self.john)
  195. data.append(self.george)
  196. data.headers = self.headers
  197. _csv = data.csv
  198. data.csv = _csv
  199. self.assertEqual(_csv, data.csv)
  200. def test_csv_import_set_with_spaces(self):
  201. """Generate and import CSV set serialization when row values have
  202. spaces."""
  203. data.append(('Bill Gates', 'Microsoft'))
  204. data.append(('Steve Jobs', 'Apple'))
  205. data.headers = ('Name', 'Company')
  206. _csv = data.csv
  207. data.csv = _csv
  208. self.assertEqual(_csv, data.csv)
  209. def test_tsv_import_set(self):
  210. """Generate and import TSV set serialization."""
  211. data.append(self.john)
  212. data.append(self.george)
  213. data.headers = self.headers
  214. _tsv = data.tsv
  215. data.tsv = _tsv
  216. self.assertEqual(_tsv, data.tsv)
  217. def test_csv_format_detect(self):
  218. """Test CSV format detection."""
  219. _csv = (
  220. '1,2,3\n'
  221. '4,5,6\n'
  222. '7,8,9\n'
  223. )
  224. _bunk = (
  225. '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶'
  226. )
  227. self.assertTrue(tablib.formats.csv.detect(_csv))
  228. self.assertFalse(tablib.formats.csv.detect(_bunk))
  229. def test_tsv_format_detect(self):
  230. """Test TSV format detection."""
  231. _tsv = (
  232. '1\t2\t3\n'
  233. '4\t5\t6\n'
  234. '7\t8\t9\n'
  235. )
  236. _bunk = (
  237. '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶'
  238. )
  239. self.assertTrue(tablib.formats.tsv.detect(_tsv))
  240. self.assertFalse(tablib.formats.tsv.detect(_bunk))
  241. def test_json_format_detect(self):
  242. """Test JSON format detection."""
  243. _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]'
  244. _bunk = (
  245. '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶'
  246. )
  247. self.assertTrue(tablib.formats.json.detect(_json))
  248. self.assertFalse(tablib.formats.json.detect(_bunk))
  249. def test_yaml_format_detect(self):
  250. """Test YAML format detection."""
  251. _yaml = '- {age: 90, first_name: John, last_name: Adams}'
  252. _bunk = (
  253. '¡¡¡¡¡¡---///\n\n\n¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶'
  254. )
  255. self.assertTrue(tablib.formats.yaml.detect(_yaml))
  256. self.assertFalse(tablib.formats.yaml.detect(_bunk))
  257. def test_auto_format_detect(self):
  258. """Test auto format detection."""
  259. _yaml = '- {age: 90, first_name: John, last_name: Adams}'
  260. _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]'
  261. _csv = '1,2,3\n4,5,6\n7,8,9\n'
  262. _bunk = '¡¡¡¡¡¡---///\n\n\n¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶'
  263. self.assertEqual(tablib.detect(_yaml)[0], tablib.formats.yaml)
  264. self.assertEqual(tablib.detect(_csv)[0], tablib.formats.csv)
  265. self.assertEqual(tablib.detect(_json)[0], tablib.formats.json)
  266. self.assertEqual(tablib.detect(_bunk)[0], None)
  267. def test_transpose(self):
  268. """Transpose a dataset."""
  269. transposed_founders = self.founders.transpose()
  270. first_row = transposed_founders[0]
  271. second_row = transposed_founders[1]
  272. self.assertEqual(transposed_founders.headers,
  273. ["first_name","John", "George", "Thomas"])
  274. self.assertEqual(first_row,
  275. ("last_name","Adams", "Washington", "Jefferson"))
  276. self.assertEqual(second_row,
  277. ("gpa",90, 67, 50))
  278. def test_row_stacking(self):
  279. """Row stacking."""
  280. to_join = tablib.Dataset(headers=self.founders.headers)
  281. for row in self.founders:
  282. to_join.append(row=row)
  283. row_stacked = self.founders.stack(to_join)
  284. for column in row_stacked.headers:
  285. original_data = self.founders[column]
  286. expected_data = original_data + original_data
  287. self.assertEqual(row_stacked[column], expected_data)
  288. def test_column_stacking(self):
  289. """Column stacking"""
  290. to_join = tablib.Dataset(headers=self.founders.headers)
  291. for row in self.founders:
  292. to_join.append(row=row)
  293. column_stacked = self.founders.stack_cols(to_join)
  294. for index, row in enumerate(column_stacked):
  295. original_data = self.founders[index]
  296. expected_data = original_data + original_data
  297. self.assertEqual(row, expected_data)
  298. self.assertEqual(column_stacked[0],
  299. ("John", "Adams", 90, "John", "Adams", 90))
  300. def test_sorting(self):
  301. """Sort columns."""
  302. sorted_data = self.founders.sort(col="first_name")
  303. first_row = sorted_data[0]
  304. second_row = sorted_data[2]
  305. third_row = sorted_data[1]
  306. expected_first = self.founders[1]
  307. expected_second = self.founders[2]
  308. expected_third = self.founders[0]
  309. self.assertEqual(first_row, expected_first)
  310. self.assertEqual(second_row, expected_second)
  311. self.assertEqual(third_row, expected_third)
  312. def test_wipe(self):
  313. """Purge a dataset."""
  314. new_row = (1, 2, 3)
  315. data.append(new_row)
  316. # Verify width/data
  317. self.assertTrue(data.width == len(new_row))
  318. self.assertTrue(data[0] == new_row)
  319. data.wipe()
  320. new_row = (1, 2, 3, 4)
  321. data.append(new_row)
  322. self.assertTrue(data.width == len(new_row))
  323. self.assertTrue(data[0] == new_row)
  324. def test_formatters(self):
  325. """Confirm formatters are being triggered."""
  326. def _formatter(cell_value):
  327. return str(cell_value).upper()
  328. self.founders.add_formatter('last_name', _formatter)
  329. for name in [r['last_name'] for r in self.founders.dict]:
  330. self.assertTrue(name.isupper())
  331. def test_unicode_csv(self):
  332. """Check if unicode in csv export doesn't raise."""
  333. data = tablib.Dataset()
  334. if sys.version_info[0] > 2:
  335. data.append(['\xfc', '\xfd'])
  336. else:
  337. exec("data.append([u'\xfc', u'\xfd'])")
  338. data.csv
  339. if __name__ == '__main__':
  340. unittest.main()