From a0df54ca2234f904dcc1ccc189cbcd173d59f691 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Thu, 3 Oct 2019 22:59:12 +0200 Subject: Reorganized test cases by format --- test_tablib.py | 1141 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 577 insertions(+), 564 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 011a69b..9cbc6c8 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -17,9 +17,7 @@ from tablib.core import Row from tablib.formats import _csv as csv_module -class TablibTestCase(unittest.TestCase): - """Tablib test cases.""" - +class BaseTestCase(unittest.TestCase): def setUp(self): """Create simple data set with headers.""" @@ -38,9 +36,9 @@ class TablibTestCase(unittest.TestCase): self.founders.append(self.george) self.founders.append(self.tom) - def tearDown(self): - """Teardown.""" - pass + +class TablibTestCase(BaseTestCase): + """Tablib test cases.""" def test_empty_append(self): """Verify append() correctly adds tuple with no headers.""" @@ -230,184 +228,6 @@ class TablibTestCase(unittest.TestCase): # Delete from invalid index self.assertRaises(IndexError, self.founders.__delitem__, 3) - def test_json_export(self): - """Verify exporting dataset object as JSON""" - - address_id = uuid4() - headers = self.headers + ('address_id',) - founders = tablib.Dataset(headers=headers, title='Founders') - founders.append(('John', 'Adams', 90, address_id)) - founders_json = founders.export('json') - - expected_json = ( - '[{"first_name": "John", "last_name": "Adams", "gpa": 90, ' - '"address_id": "%s"}]' % str(address_id) - ) - - self.assertEqual(founders_json, expected_json) - - def test_csv_export(self): - """Verify exporting dataset object as CSV.""" - - # Build up the csv string with headers first, followed by each row - csv = '' - for col in self.headers: - csv += col + ',' - - csv = csv.strip(',') + '\r\n' - - for founder in self.founders: - for col in founder: - csv += str(col) + ',' - csv = csv.strip(',') + '\r\n' - - self.assertEqual(csv, self.founders.csv) - - def test_csv_stream_export(self): - """Verify exporting dataset object as CSV from file object.""" - - # Build up the csv string with headers first, followed by each row - csv = '' - for col in self.headers: - csv += col + ',' - - csv = csv.strip(',') + '\r\n' - - for founder in self.founders: - for col in founder: - csv += str(col) + ',' - csv = csv.strip(',') + '\r\n' - - csv_stream = csv_module.export_stream_set(self.founders) - self.assertEqual(csv, csv_stream.getvalue()) - - def test_tsv_export(self): - """Verify exporting dataset object as TSV.""" - - # Build up the tsv string with headers first, followed by each row - tsv = '' - for col in self.headers: - tsv += col + '\t' - - tsv = tsv.strip('\t') + '\r\n' - - for founder in self.founders: - for col in founder: - tsv += str(col) + '\t' - tsv = tsv.strip('\t') + '\r\n' - - self.assertEqual(tsv, self.founders.tsv) - - def test_html_export(self): - """HTML export""" - - html = markup.page() - html.table.open() - html.thead.open() - - html.tr(markup.oneliner.th(self.founders.headers)) - html.thead.close() - - for founder in self.founders: - html.tr(markup.oneliner.td(founder)) - - html.table.close() - html = str(html) - - self.assertEqual(html, self.founders.html) - - def test_html_export_none_value(self): - """HTML export""" - - html = markup.page() - html.table.open() - html.thead.open() - - html.tr(markup.oneliner.th(['foo', '', 'bar'])) - html.thead.close() - - html.tr(markup.oneliner.td(['foo', '', 'bar'])) - - html.table.close() - html = str(html) - - headers = ['foo', None, 'bar']; - d = tablib.Dataset(['foo', None, 'bar'], headers=headers) - - self.assertEqual(html, d.html) - - def test_jira_export(self): - - expected = """||first_name||last_name||gpa|| -|John|Adams|90| -|George|Washington|67| -|Thomas|Jefferson|50|""" - self.assertEqual(expected, self.founders.jira) - - def test_jira_export_no_headers(self): - self.assertEqual('|a|b|c|', tablib.Dataset(['a', 'b', 'c']).jira) - - def test_jira_export_none_and_empty_values(self): - self.assertEqual('| | |c|', tablib.Dataset(['', None, 'c']).jira) - - def test_jira_export_empty_dataset(self): - self.assertTrue(tablib.Dataset().jira is not None) - - def test_latex_export(self): - """LaTeX export""" - - expected = """\ -% Note: add \\usepackage{booktabs} to your preamble -% -\\begin{table}[!htbp] - \\centering - \\caption{Founders} - \\begin{tabular}{lrr} - \\toprule - first\\_name & last\\_name & gpa \\\\ - \\cmidrule(r){1-1} \\cmidrule(lr){2-2} \\cmidrule(l){3-3} - John & Adams & 90 \\\\ - George & Washington & 67 \\\\ - Thomas & Jefferson & 50 \\\\ - \\bottomrule - \\end{tabular} -\\end{table} -""" - output = self.founders.latex - self.assertEqual(output, expected) - - def test_latex_export_empty_dataset(self): - self.assertTrue(tablib.Dataset().latex is not None) - - def test_latex_export_no_headers(self): - d = tablib.Dataset() - d.append(('one', 'two', 'three')) - self.assertTrue('one' in d.latex) - - def test_latex_export_caption(self): - d = tablib.Dataset() - d.append(('one', 'two', 'three')) - self.assertFalse('caption' in d.latex) - - d.title = 'Title' - self.assertTrue('\\caption{Title}' in d.latex) - - def test_latex_export_none_values(self): - headers = ['foo', None, 'bar'] - d = tablib.Dataset(['foo', None, 'bar'], headers=headers) - output = d.latex - self.assertTrue('foo' in output) - self.assertFalse('None' in output) - - def test_latex_escaping(self): - d = tablib.Dataset(['~', '^']) - output = d.latex - - self.assertFalse('~' in output) - self.assertTrue('textasciitilde' in output) - self.assertFalse('^' in output) - self.assertTrue('textasciicircum' in output) - def test_str_no_columns(self): d = tablib.Dataset(['a', 1], ['b', 2], ['c', 3]) output = '%s' % d @@ -477,55 +297,264 @@ class TablibTestCase(unittest.TestCase): book.html data.rst - def test_json_import_set(self): - """Generate and import JSON set serialization.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + def test_auto_format_detect(self): + """Test auto format detection.""" - _json = data.json + _yaml = '- {age: 90, first_name: John, last_name: Adams}' + _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]' + _csv = '1,2,3\n4,5,6\n7,8,9\n' + _tsv = '1\t2\t3\n4\t5\t6\n7\t8\t9\n' + _bunk = '¡¡¡¡¡¡---///\n\n\n¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' - data.json = _json + self.assertEqual(tablib.detect_format(_yaml), 'yaml') + self.assertEqual(tablib.detect_format(_csv), 'csv') + self.assertEqual(tablib.detect_format(_tsv), 'tsv') + self.assertEqual(tablib.detect_format(_json), 'json') + self.assertEqual(tablib.detect_format(_bunk), None) - self.assertEqual(json.loads(_json), json.loads(data.json)) + def test_transpose(self): + """Transpose a dataset.""" - def test_json_import_book(self): - """Generate and import JSON book serialization.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + transposed_founders = self.founders.transpose() + first_row = transposed_founders[0] + second_row = transposed_founders[1] - book.add_sheet(data) - _json = book.json + self.assertEqual(transposed_founders.headers, + ["first_name", "John", "George", "Thomas"]) + self.assertEqual(first_row, + ("last_name", "Adams", "Washington", "Jefferson")) + self.assertEqual(second_row, + ("gpa", 90, 67, 50)) - book.json = _json + def test_transpose_multiple_headers(self): - self.assertEqual(json.loads(_json), json.loads(book.json)) + data = tablib.Dataset() + data.headers = ("first_name", "last_name", "age") + data.append(('John', 'Adams', 90)) + data.append(('George', 'Washington', 67)) + data.append(('John', 'Tyler', 71)) + self.assertEqual(data.transpose().transpose().dict, data.dict) - def test_yaml_import_set(self): - """Generate and import YAML set serialization.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + def test_row_stacking(self): + """Row stacking.""" - _yaml = data.yaml + to_join = tablib.Dataset(headers=self.founders.headers) - data.yaml = _yaml + for row in self.founders: + to_join.append(row=row) - self.assertEqual(_yaml, data.yaml) + row_stacked = self.founders.stack(to_join) - def test_yaml_import_book(self): - """Generate and import YAML book serialization.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + for column in row_stacked.headers: + original_data = self.founders[column] + expected_data = original_data + original_data + self.assertEqual(row_stacked[column], expected_data) - book.add_sheet(data) - _yaml = book.yaml + def test_column_stacking(self): + """Column stacking""" - book.yaml = _yaml + to_join = tablib.Dataset(headers=self.founders.headers) - self.assertEqual(_yaml, book.yaml) + for row in self.founders: + to_join.append(row=row) + + column_stacked = self.founders.stack_cols(to_join) + + for index, row in enumerate(column_stacked): + original_data = self.founders[index] + expected_data = original_data + original_data + self.assertEqual(row, expected_data) + + self.assertEqual(column_stacked[0], + ("John", "Adams", 90, "John", "Adams", 90)) + + def test_sorting(self): + """Sort columns.""" + + sorted_data = self.founders.sort(col="first_name") + self.assertEqual(sorted_data.title, 'Founders') + + first_row = sorted_data[0] + second_row = sorted_data[2] + third_row = sorted_data[1] + expected_first = self.founders[1] + expected_second = self.founders[2] + expected_third = self.founders[0] + + self.assertEqual(first_row, expected_first) + self.assertEqual(second_row, expected_second) + self.assertEqual(third_row, expected_third) + + def test_remove_duplicates(self): + """Unique Rows.""" + + self.founders.append(self.john) + self.founders.append(self.george) + self.founders.append(self.tom) + self.assertEqual(self.founders[0], self.founders[3]) + self.assertEqual(self.founders[1], self.founders[4]) + self.assertEqual(self.founders[2], self.founders[5]) + self.assertEqual(self.founders.height, 6) + + self.founders.remove_duplicates() + + self.assertEqual(self.founders[0], self.john) + self.assertEqual(self.founders[1], self.george) + self.assertEqual(self.founders[2], self.tom) + self.assertEqual(self.founders.height, 3) + + def test_wipe(self): + """Purge a dataset.""" + + new_row = (1, 2, 3) + data.append(new_row) + + # Verify width/data + self.assertTrue(data.width == len(new_row)) + self.assertTrue(data[0] == new_row) + + data.wipe() + new_row = (1, 2, 3, 4) + data.append(new_row) + self.assertTrue(data.width == len(new_row)) + self.assertTrue(data[0] == new_row) + + def test_subset(self): + """Create a subset of a dataset""" + + rows = (0, 2) + columns = ('first_name', 'gpa') + + data.headers = self.headers + + data.append(self.john) + data.append(self.george) + data.append(self.tom) + + # Verify data is truncated + subset = data.subset(rows=rows, cols=columns) + self.assertEqual(type(subset), tablib.Dataset) + self.assertEqual(subset.headers, list(columns)) + self.assertEqual(subset._data[0].list, ['John', 90]) + self.assertEqual(subset._data[1].list, ['Thomas', 50]) + + def test_formatters(self): + """Confirm formatters are being triggered.""" + + def _formatter(cell_value): + return str(cell_value).upper() + + self.founders.add_formatter('last_name', _formatter) + + for name in [r['last_name'] for r in self.founders.dict]: + self.assertTrue(name.isupper()) + + def test_unicode_renders_markdown_table(self): + # add another entry to test right field width for + # integer + self.founders.append(('Old', 'Man', 100500)) + self.assertEqual('first_name|last_name |gpa ', unicode(self.founders).split('\n')[0]) + + def test_databook_add_sheet_accepts_only_dataset_instances(self): + class NotDataset(object): + def append(self, item): + pass + + dataset = NotDataset() + dataset.append(self.john) + + self.assertRaises(tablib.InvalidDatasetType, book.add_sheet, dataset) + + def test_databook_add_sheet_accepts_dataset_subclasses(self): + class DatasetSubclass(tablib.Dataset): + pass + + # just checking if subclass of tablib.Dataset can be added to Databook + dataset = DatasetSubclass() + dataset.append(self.john) + dataset.append(self.tom) + + try: + book.add_sheet(dataset) + except tablib.InvalidDatasetType: + self.fail("Subclass of tablib.Dataset should be accepted by Databook.add_sheet") + + def test_databook_formatter_support_kwargs(self): + """Test XLSX export with formatter configuration.""" + self.founders.export('xlsx', freeze_panes=False) + + def test_databook_formatter_with_new_lines(self): + """Test XLSX export with new line in content.""" + self.founders.append(('First\nSecond', 'Name', 42)) + self.founders.export('xlsx') + + def test_rst_force_grid(self): + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + simple = tablib.formats._rst.export_set(data) + grid = tablib.formats._rst.export_set(data, force_grid=True) + self.assertNotEqual(simple, grid) + self.assertNotIn('+', simple) + self.assertIn('+', grid) + + +class HTMLTests(BaseTestCase): + def test_html_export(self): + """HTML export""" + + html = markup.page() + html.table.open() + html.thead.open() + + html.tr(markup.oneliner.th(self.founders.headers)) + html.thead.close() + + for founder in self.founders: + html.tr(markup.oneliner.td(founder)) + + html.table.close() + html = str(html) + + self.assertEqual(html, self.founders.html) + + def test_html_export_none_value(self): + """HTML export""" + + html = markup.page() + html.table.open() + html.thead.open() + + html.tr(markup.oneliner.th(['foo', '', 'bar'])) + html.thead.close() + + html.tr(markup.oneliner.td(['foo', '', 'bar'])) + + html.table.close() + html = str(html) + + headers = ['foo', None, 'bar']; + d = tablib.Dataset(['foo', None, 'bar'], headers=headers) + + self.assertEqual(html, d.html) + + +class CSVTests(BaseTestCase): + def test_csv_format_detect(self): + """Test CSV format detection.""" + + _csv = ( + '1,2,3\n' + '4,5,6\n' + '7,8,9\n' + ) + _bunk = ( + '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' + ) + + self.assertTrue(tablib.formats.csv.detect(_csv)) + self.assertFalse(tablib.formats.csv.detect(_bunk)) def test_csv_import_set(self): """Generate and import CSV set serialization.""" @@ -600,134 +629,125 @@ class TablibTestCase(unittest.TestCase): data.csv = csv_text self.assertEqual(data.width, 7) - def test_tsv_import_set(self): - """Generate and import TSV set serialization.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + def test_csv_export(self): + """Verify exporting dataset object as CSV.""" - _tsv = data.tsv + # Build up the csv string with headers first, followed by each row + csv = '' + for col in self.headers: + csv += col + ',' - data.tsv = _tsv + csv = csv.strip(',') + '\r\n' - self.assertEqual(_tsv, data.tsv) + for founder in self.founders: + for col in founder: + csv += str(col) + ',' + csv = csv.strip(',') + '\r\n' - def test_dbf_import_set(self): - data.append(self.john) - data.append(self.george) - data.headers = self.headers + self.assertEqual(csv, self.founders.csv) - _dbf = data.dbf - data.dbf = _dbf + def test_csv_stream_export(self): + """Verify exporting dataset object as CSV from file object.""" - # self.assertEqual(_dbf, data.dbf) - try: - self.assertEqual(_dbf, data.dbf) - except AssertionError: - index = 0 - so_far = '' - for reg_char, data_char in zip(_dbf, data.dbf): - so_far += chr(data_char) - if reg_char != data_char and index not in [1, 2, 3]: - raise AssertionError('Failing at char %s: %s vs %s %s' % ( - index, reg_char, data_char, so_far)) - index += 1 + # Build up the csv string with headers first, followed by each row + csv = '' + for col in self.headers: + csv += col + ',' - def test_dbf_export_set(self): - """Test DBF import.""" - data.append(self.john) - data.append(self.george) - data.append(self.tom) - data.headers = self.headers + csv = csv.strip(',') + '\r\n' - _regression_dbf = (b'\x03r\x06\x06\x03\x00\x00\x00\x81\x00\xab\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00FIRST_NAME\x00C\x00\x00\x00\x00P\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LAST_NAME\x00\x00C\x00' - b'\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00GPA\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x00\n' - b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r' - ) - _regression_dbf += b' John' + (b' ' * 75) - _regression_dbf += b' Adams' + (b' ' * 74) - _regression_dbf += b' 90.0000000' - _regression_dbf += b' George' + (b' ' * 73) - _regression_dbf += b' Washington' + (b' ' * 69) - _regression_dbf += b' 67.0000000' - _regression_dbf += b' Thomas' + (b' ' * 73) - _regression_dbf += b' Jefferson' + (b' ' * 70) - _regression_dbf += b' 50.0000000' - _regression_dbf += b'\x1a' + for founder in self.founders: + for col in founder: + csv += str(col) + ',' + csv = csv.strip(',') + '\r\n' - if is_py3: - # If in python3, decode regression string to binary. - # _regression_dbf = bytes(_regression_dbf, 'utf-8') - # _regression_dbf = _regression_dbf.replace(b'\n', b'\r') - pass + csv_stream = csv_module.export_stream_set(self.founders) + self.assertEqual(csv, csv_stream.getvalue()) - try: - self.assertEqual(_regression_dbf, data.dbf) - except AssertionError: - index = 0 - found_so_far = '' - for reg_char, data_char in zip(_regression_dbf, data.dbf): - # found_so_far += chr(data_char) - if reg_char != data_char and index not in [1, 2, 3]: - raise AssertionError( - 'Failing at char %s: %s vs %s (found %s)' % ( - index, reg_char, data_char, found_so_far)) - index += 1 + def test_unicode_csv(self): + """Check if unicode in csv export doesn't raise.""" - def test_dbf_format_detect(self): - """Test the DBF format detection.""" - _dbf = (b'\x03r\x06\x03\x03\x00\x00\x00\x81\x00\xab\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00FIRST_NAME\x00C\x00\x00\x00\x00P\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LAST_NAME\x00\x00C\x00' - b'\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00GPA\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x00\n' - b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r' - ) - _dbf += b' John' + (b' ' * 75) - _dbf += b' Adams' + (b' ' * 74) - _dbf += b' 90.0000000' - _dbf += b' George' + (b' ' * 73) - _dbf += b' Washington' + (b' ' * 69) - _dbf += b' 67.0000000' - _dbf += b' Thomas' + (b' ' * 73) - _dbf += b' Jefferson' + (b' ' * 70) - _dbf += b' 50.0000000' - _dbf += b'\x1a' + data = tablib.Dataset() - _yaml = '- {age: 90, first_name: John, last_name: Adams}' - _tsv = 'foo\tbar' - _csv = '1,2,3\n4,5,6\n7,8,9\n' - _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]' + if sys.version_info[0] > 2: + data.append(['\xfc', '\xfd']) + else: + exec ("data.append([u'\xfc', u'\xfd'])") - _bunk = ( - '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' - ) - self.assertTrue(tablib.formats.dbf.detect(_dbf)) - self.assertFalse(tablib.formats.dbf.detect(_yaml)) - self.assertFalse(tablib.formats.dbf.detect(_tsv)) - self.assertFalse(tablib.formats.dbf.detect(_csv)) - self.assertFalse(tablib.formats.dbf.detect(_json)) - self.assertFalse(tablib.formats.dbf.detect(_bunk)) + data.csv - def test_csv_format_detect(self): - """Test CSV format detection.""" + def test_csv_column_select(self): + """Build up a CSV and test selecting a column""" - _csv = ( - '1,2,3\n' - '4,5,6\n' - '7,8,9\n' - ) - _bunk = ( - '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' - ) + data = tablib.Dataset() + data.csv = self.founders.csv - self.assertTrue(tablib.formats.csv.detect(_csv)) - self.assertFalse(tablib.formats.csv.detect(_bunk)) + headers = data.headers + self.assertTrue(isinstance(headers[0], unicode)) + + orig_first_name = self.founders[self.headers[0]] + csv_first_name = data[headers[0]] + self.assertEqual(orig_first_name, csv_first_name) + + def test_csv_column_delete(self): + """Build up a CSV and test deleting a column""" + + data = tablib.Dataset() + data.csv = self.founders.csv + + target_header = data.headers[0] + self.assertTrue(isinstance(target_header, unicode)) + + del data[target_header] + + self.assertTrue(target_header not in data.headers) + + def test_csv_column_sort(self): + """Build up a CSV and test sorting a column by name""" + + data = tablib.Dataset() + data.csv = self.founders.csv + + orig_target_header = self.founders.headers[1] + target_header = data.headers[1] + + self.founders.sort(orig_target_header) + data.sort(target_header) + + self.assertEqual(self.founders[orig_target_header], data[target_header]) + + def test_csv_formatter_support_kwargs(self): + """Test CSV import and export with formatter configuration.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + expected = 'first_name;last_name;gpa\nJohn;Adams;90\nGeorge;Washington;67\n' + + kwargs = dict(delimiter=';', lineterminator='\n') + _csv = data.export('csv', **kwargs) + self.assertEqual(expected, _csv) + + # the import works but consider default delimiter=',' + d1 = tablib.import_set(_csv, format="csv") + self.assertEqual(1, len(d1.headers)) + + d2 = tablib.import_set(_csv, format="csv", **kwargs) + self.assertEqual(3, len(d2.headers)) + + +class TSVTests(BaseTestCase): + def test_tsv_import_set(self): + """Generate and import TSV set serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + _tsv = data.tsv + + data.tsv = _tsv + + self.assertEqual(_tsv, data.tsv) def test_tsv_format_detect(self): """Test TSV format detection.""" @@ -744,6 +764,25 @@ class TablibTestCase(unittest.TestCase): self.assertTrue(tablib.formats.tsv.detect(_tsv)) self.assertFalse(tablib.formats.tsv.detect(_bunk)) + def test_tsv_export(self): + """Verify exporting dataset object as TSV.""" + + # Build up the tsv string with headers first, followed by each row + tsv = '' + for col in self.headers: + tsv += col + '\t' + + tsv = tsv.strip('\t') + '\r\n' + + for founder in self.founders: + for col in founder: + tsv += str(col) + '\t' + tsv = tsv.strip('\t') + '\r\n' + + self.assertEqual(tsv, self.founders.tsv) + + +class JSONTests(BaseTestCase): def test_json_format_detect(self): """Test JSON format detection.""" @@ -755,6 +794,49 @@ class TablibTestCase(unittest.TestCase): self.assertTrue(tablib.formats.json.detect(_json)) self.assertFalse(tablib.formats.json.detect(_bunk)) + def test_json_import_book(self): + """Generate and import JSON book serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + book.add_sheet(data) + _json = book.json + + book.json = _json + + self.assertEqual(json.loads(_json), json.loads(book.json)) + + def test_json_import_set(self): + """Generate and import JSON set serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + _json = data.json + + data.json = _json + + self.assertEqual(json.loads(_json), json.loads(data.json)) + + def test_json_export(self): + """Verify exporting dataset object as JSON""" + + address_id = uuid4() + headers = self.headers + ('address_id',) + founders = tablib.Dataset(headers=headers, title='Founders') + founders.append(('John', 'Adams', 90, address_id)) + founders_json = founders.export('json') + + expected_json = ( + '[{"first_name": "John", "last_name": "Adams", "gpa": 90, ' + '"address_id": "%s"}]' % str(address_id) + ) + + self.assertEqual(founders_json, expected_json) + + +class YAMLTests(BaseTestCase): def test_yaml_format_detect(self): """Test YAML format detection.""" @@ -768,278 +850,209 @@ class TablibTestCase(unittest.TestCase): self.assertFalse(tablib.formats.yaml.detect(_bunk)) self.assertFalse(tablib.formats.yaml.detect(_tsv)) - def test_auto_format_detect(self): - """Test auto format detection.""" + def test_yaml_import_book(self): + """Generate and import YAML book serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers - _yaml = '- {age: 90, first_name: John, last_name: Adams}' - _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]' - _csv = '1,2,3\n4,5,6\n7,8,9\n' - _tsv = '1\t2\t3\n4\t5\t6\n7\t8\t9\n' - _bunk = '¡¡¡¡¡¡---///\n\n\n¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' + book.add_sheet(data) + _yaml = book.yaml - self.assertEqual(tablib.detect_format(_yaml), 'yaml') - self.assertEqual(tablib.detect_format(_csv), 'csv') - self.assertEqual(tablib.detect_format(_tsv), 'tsv') - self.assertEqual(tablib.detect_format(_json), 'json') - self.assertEqual(tablib.detect_format(_bunk), None) + book.yaml = _yaml - def test_transpose(self): - """Transpose a dataset.""" + self.assertEqual(_yaml, book.yaml) - transposed_founders = self.founders.transpose() - first_row = transposed_founders[0] - second_row = transposed_founders[1] + def test_yaml_import_set(self): + """Generate and import YAML set serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers - self.assertEqual(transposed_founders.headers, - ["first_name", "John", "George", "Thomas"]) - self.assertEqual(first_row, - ("last_name", "Adams", "Washington", "Jefferson")) - self.assertEqual(second_row, - ("gpa", 90, 67, 50)) - - def test_transpose_multiple_headers(self): - - data = tablib.Dataset() - data.headers = ("first_name", "last_name", "age") - data.append(('John', 'Adams', 90)) - data.append(('George', 'Washington', 67)) - data.append(('John', 'Tyler', 71)) - self.assertEqual(data.transpose().transpose().dict, data.dict) - - def test_row_stacking(self): - """Row stacking.""" - - to_join = tablib.Dataset(headers=self.founders.headers) - - for row in self.founders: - to_join.append(row=row) - - row_stacked = self.founders.stack(to_join) - - for column in row_stacked.headers: - original_data = self.founders[column] - expected_data = original_data + original_data - self.assertEqual(row_stacked[column], expected_data) - - def test_column_stacking(self): - """Column stacking""" - - to_join = tablib.Dataset(headers=self.founders.headers) - - for row in self.founders: - to_join.append(row=row) - - column_stacked = self.founders.stack_cols(to_join) - - for index, row in enumerate(column_stacked): - original_data = self.founders[index] - expected_data = original_data + original_data - self.assertEqual(row, expected_data) + _yaml = data.yaml - self.assertEqual(column_stacked[0], - ("John", "Adams", 90, "John", "Adams", 90)) + data.yaml = _yaml - def test_sorting(self): - """Sort columns.""" + self.assertEqual(_yaml, data.yaml) - sorted_data = self.founders.sort(col="first_name") - self.assertEqual(sorted_data.title, 'Founders') - first_row = sorted_data[0] - second_row = sorted_data[2] - third_row = sorted_data[1] - expected_first = self.founders[1] - expected_second = self.founders[2] - expected_third = self.founders[0] +class LatexTests(BaseTestCase): + def test_latex_export(self): + """LaTeX export""" - self.assertEqual(first_row, expected_first) - self.assertEqual(second_row, expected_second) - self.assertEqual(third_row, expected_third) + expected = """\ +% Note: add \\usepackage{booktabs} to your preamble +% +\\begin{table}[!htbp] + \\centering + \\caption{Founders} + \\begin{tabular}{lrr} + \\toprule + first\\_name & last\\_name & gpa \\\\ + \\cmidrule(r){1-1} \\cmidrule(lr){2-2} \\cmidrule(l){3-3} + John & Adams & 90 \\\\ + George & Washington & 67 \\\\ + Thomas & Jefferson & 50 \\\\ + \\bottomrule + \\end{tabular} +\\end{table} +""" + output = self.founders.latex + self.assertEqual(output, expected) - def test_remove_duplicates(self): - """Unique Rows.""" + def test_latex_export_empty_dataset(self): + self.assertTrue(tablib.Dataset().latex is not None) - self.founders.append(self.john) - self.founders.append(self.george) - self.founders.append(self.tom) - self.assertEqual(self.founders[0], self.founders[3]) - self.assertEqual(self.founders[1], self.founders[4]) - self.assertEqual(self.founders[2], self.founders[5]) - self.assertEqual(self.founders.height, 6) + def test_latex_export_no_headers(self): + d = tablib.Dataset() + d.append(('one', 'two', 'three')) + self.assertTrue('one' in d.latex) - self.founders.remove_duplicates() + def test_latex_export_caption(self): + d = tablib.Dataset() + d.append(('one', 'two', 'three')) + self.assertFalse('caption' in d.latex) - self.assertEqual(self.founders[0], self.john) - self.assertEqual(self.founders[1], self.george) - self.assertEqual(self.founders[2], self.tom) - self.assertEqual(self.founders.height, 3) + d.title = 'Title' + self.assertTrue('\\caption{Title}' in d.latex) - def test_wipe(self): - """Purge a dataset.""" + def test_latex_export_none_values(self): + headers = ['foo', None, 'bar'] + d = tablib.Dataset(['foo', None, 'bar'], headers=headers) + output = d.latex + self.assertTrue('foo' in output) + self.assertFalse('None' in output) - new_row = (1, 2, 3) - data.append(new_row) + def test_latex_escaping(self): + d = tablib.Dataset(['~', '^']) + output = d.latex - # Verify width/data - self.assertTrue(data.width == len(new_row)) - self.assertTrue(data[0] == new_row) + self.assertFalse('~' in output) + self.assertTrue('textasciitilde' in output) + self.assertFalse('^' in output) + self.assertTrue('textasciicircum' in output) - data.wipe() - new_row = (1, 2, 3, 4) - data.append(new_row) - self.assertTrue(data.width == len(new_row)) - self.assertTrue(data[0] == new_row) - def test_subset(self): - """Create a subset of a dataset""" +class DBFTests(BaseTestCase): + def test_dbf_import_set(self): + data.append(self.john) + data.append(self.george) + data.headers = self.headers - rows = (0, 2) - columns = ('first_name', 'gpa') + _dbf = data.dbf + data.dbf = _dbf - data.headers = self.headers + # self.assertEqual(_dbf, data.dbf) + try: + self.assertEqual(_dbf, data.dbf) + except AssertionError: + index = 0 + so_far = '' + for reg_char, data_char in zip(_dbf, data.dbf): + so_far += chr(data_char) + if reg_char != data_char and index not in [1, 2, 3]: + raise AssertionError('Failing at char %s: %s vs %s %s' % ( + index, reg_char, data_char, so_far)) + index += 1 + def test_dbf_export_set(self): + """Test DBF import.""" data.append(self.john) data.append(self.george) data.append(self.tom) + data.headers = self.headers - # Verify data is truncated - subset = data.subset(rows=rows, cols=columns) - self.assertEqual(type(subset), tablib.Dataset) - self.assertEqual(subset.headers, list(columns)) - self.assertEqual(subset._data[0].list, ['John', 90]) - self.assertEqual(subset._data[1].list, ['Thomas', 50]) - - def test_formatters(self): - """Confirm formatters are being triggered.""" - - def _formatter(cell_value): - return str(cell_value).upper() - - self.founders.add_formatter('last_name', _formatter) - - for name in [r['last_name'] for r in self.founders.dict]: - self.assertTrue(name.isupper()) - - def test_unicode_csv(self): - """Check if unicode in csv export doesn't raise.""" - - data = tablib.Dataset() - - if sys.version_info[0] > 2: - data.append(['\xfc', '\xfd']) - else: - exec ("data.append([u'\xfc', u'\xfd'])") - - data.csv - - def test_csv_column_select(self): - """Build up a CSV and test selecting a column""" - - data = tablib.Dataset() - data.csv = self.founders.csv - - headers = data.headers - self.assertTrue(isinstance(headers[0], unicode)) - - orig_first_name = self.founders[self.headers[0]] - csv_first_name = data[headers[0]] - self.assertEqual(orig_first_name, csv_first_name) - - def test_csv_column_delete(self): - """Build up a CSV and test deleting a column""" - - data = tablib.Dataset() - data.csv = self.founders.csv - - target_header = data.headers[0] - self.assertTrue(isinstance(target_header, unicode)) - - del data[target_header] - - self.assertTrue(target_header not in data.headers) - - def test_csv_column_sort(self): - """Build up a CSV and test sorting a column by name""" - - data = tablib.Dataset() - data.csv = self.founders.csv - - orig_target_header = self.founders.headers[1] - target_header = data.headers[1] - - self.founders.sort(orig_target_header) - data.sort(target_header) - - self.assertEqual(self.founders[orig_target_header], data[target_header]) - - def test_unicode_renders_markdown_table(self): - # add another entry to test right field width for - # integer - self.founders.append(('Old', 'Man', 100500)) - self.assertEqual('first_name|last_name |gpa ', unicode(self.founders).split('\n')[0]) - - def test_databook_add_sheet_accepts_only_dataset_instances(self): - class NotDataset(object): - def append(self, item): - pass - - dataset = NotDataset() - dataset.append(self.john) - - self.assertRaises(tablib.InvalidDatasetType, book.add_sheet, dataset) + _regression_dbf = (b'\x03r\x06\x06\x03\x00\x00\x00\x81\x00\xab\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00FIRST_NAME\x00C\x00\x00\x00\x00P\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LAST_NAME\x00\x00C\x00' + b'\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00GPA\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x00\n' + b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r' + ) + _regression_dbf += b' John' + (b' ' * 75) + _regression_dbf += b' Adams' + (b' ' * 74) + _regression_dbf += b' 90.0000000' + _regression_dbf += b' George' + (b' ' * 73) + _regression_dbf += b' Washington' + (b' ' * 69) + _regression_dbf += b' 67.0000000' + _regression_dbf += b' Thomas' + (b' ' * 73) + _regression_dbf += b' Jefferson' + (b' ' * 70) + _regression_dbf += b' 50.0000000' + _regression_dbf += b'\x1a' - def test_databook_add_sheet_accepts_dataset_subclasses(self): - class DatasetSubclass(tablib.Dataset): + if is_py3: + # If in python3, decode regression string to binary. + # _regression_dbf = bytes(_regression_dbf, 'utf-8') + # _regression_dbf = _regression_dbf.replace(b'\n', b'\r') pass - # just checking if subclass of tablib.Dataset can be added to Databook - dataset = DatasetSubclass() - dataset.append(self.john) - dataset.append(self.tom) - try: - book.add_sheet(dataset) - except tablib.InvalidDatasetType: - self.fail("Subclass of tablib.Dataset should be accepted by Databook.add_sheet") - - def test_csv_formatter_support_kwargs(self): - """Test CSV import and export with formatter configuration.""" - data.append(self.john) - data.append(self.george) - data.headers = self.headers + self.assertEqual(_regression_dbf, data.dbf) + except AssertionError: + index = 0 + found_so_far = '' + for reg_char, data_char in zip(_regression_dbf, data.dbf): + # found_so_far += chr(data_char) + if reg_char != data_char and index not in [1, 2, 3]: + raise AssertionError( + 'Failing at char %s: %s vs %s (found %s)' % ( + index, reg_char, data_char, found_so_far)) + index += 1 - expected = 'first_name;last_name;gpa\nJohn;Adams;90\nGeorge;Washington;67\n' + def test_dbf_format_detect(self): + """Test the DBF format detection.""" + _dbf = (b'\x03r\x06\x03\x03\x00\x00\x00\x81\x00\xab\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00FIRST_NAME\x00C\x00\x00\x00\x00P\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LAST_NAME\x00\x00C\x00' + b'\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00GPA\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x00\n' + b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r' + ) + _dbf += b' John' + (b' ' * 75) + _dbf += b' Adams' + (b' ' * 74) + _dbf += b' 90.0000000' + _dbf += b' George' + (b' ' * 73) + _dbf += b' Washington' + (b' ' * 69) + _dbf += b' 67.0000000' + _dbf += b' Thomas' + (b' ' * 73) + _dbf += b' Jefferson' + (b' ' * 70) + _dbf += b' 50.0000000' + _dbf += b'\x1a' - kwargs = dict(delimiter=';', lineterminator='\n') - _csv = data.export('csv', **kwargs) - self.assertEqual(expected, _csv) + _yaml = '- {age: 90, first_name: John, last_name: Adams}' + _tsv = 'foo\tbar' + _csv = '1,2,3\n4,5,6\n7,8,9\n' + _json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]' - # the import works but consider default delimiter=',' - d1 = tablib.import_set(_csv, format="csv") - self.assertEqual(1, len(d1.headers)) + _bunk = ( + '¡¡¡¡¡¡¡¡£™∞¢£§∞§¶•¶ª∞¶•ªº••ª–º§•†•§º¶•†¥ª–º•§ƒø¥¨©πƒø†ˆ¥ç©¨√øˆ¥≈†ƒ¥ç©ø¨çˆ¥ƒçø¶' + ) + self.assertTrue(tablib.formats.dbf.detect(_dbf)) + self.assertFalse(tablib.formats.dbf.detect(_yaml)) + self.assertFalse(tablib.formats.dbf.detect(_tsv)) + self.assertFalse(tablib.formats.dbf.detect(_csv)) + self.assertFalse(tablib.formats.dbf.detect(_json)) + self.assertFalse(tablib.formats.dbf.detect(_bunk)) - d2 = tablib.import_set(_csv, format="csv", **kwargs) - self.assertEqual(3, len(d2.headers)) - def test_databook_formatter_support_kwargs(self): - """Test XLSX export with formatter configuration.""" - self.founders.export('xlsx', freeze_panes=False) +class JiraTests(BaseTestCase): + def test_jira_export(self): + expected = """||first_name||last_name||gpa|| +|John|Adams|90| +|George|Washington|67| +|Thomas|Jefferson|50|""" + self.assertEqual(expected, self.founders.jira) - def test_databook_formatter_with_new_lines(self): - """Test XLSX export with new line in content.""" - self.founders.append(('First\nSecond', 'Name', 42)) - self.founders.export('xlsx') + def test_jira_export_no_headers(self): + self.assertEqual('|a|b|c|', tablib.Dataset(['a', 'b', 'c']).jira) - def test_rst_force_grid(self): - data.append(self.john) - data.append(self.george) - data.headers = self.headers + def test_jira_export_none_and_empty_values(self): + self.assertEqual('| | |c|', tablib.Dataset(['', None, 'c']).jira) - simple = tablib.formats._rst.export_set(data) - grid = tablib.formats._rst.export_set(data, force_grid=True) - self.assertNotEqual(simple, grid) - self.assertNotIn('+', simple) - self.assertIn('+', grid) + def test_jira_export_empty_dataset(self): + self.assertTrue(tablib.Dataset().jira is not None) class DocTests(unittest.TestCase): -- cgit v1.2.1