From 93c6c3958172875354a688d430e92f0d95428e6a Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 20:23:31 -0500 Subject: [PATCH 01/81] Misc. pep8 cleanups including spaces after ',' and blank line organization --- test_tablib.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index cea6d24..81673bd 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -5,6 +5,7 @@ import unittest import tablib + class TablibTestCase(unittest.TestCase): def setUp(self): pass @@ -16,25 +17,22 @@ class TablibTestCase(unittest.TestCase): data = tablib.Dataset() - new_row = (1,2,3) + new_row = (1, 2, 3) data.append(new_row) self.assertTrue(data.width == len(new_row)) - def test_empty_append_with_headers(self): data = tablib.Dataset() data.headers = ['first', 'second'] - new_row = (1,2,3,4) - - self.assertRaises(tablib.InvalidDimensions, data.append, new_row) - - # def test_adding_header with (self): - + new_row = (1, 2, 3, 4) + self.assertRaises(tablib.InvalidDimensions, data.append, new_row) + + # def test_adding_header with (self): if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() From 1482ca4a198579afaa3f2a191ad2f468b28d2b37 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 20:32:36 -0500 Subject: [PATCH 02/81] Adding docstrings --- test_tablib.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 81673bd..13aa66b 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -1,20 +1,26 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +"""Tests for tablib""" + import unittest import tablib class TablibTestCase(unittest.TestCase): + """Tablib test cases""" + def setUp(self): + """setup""" pass def tearDown(self): + """teardown""" pass def test_empty_append(self): - + """Verify append() correctly adds tuple with no headers""" data = tablib.Dataset() new_row = (1, 2, 3) @@ -23,7 +29,9 @@ class TablibTestCase(unittest.TestCase): self.assertTrue(data.width == len(new_row)) def test_empty_append_with_headers(self): - + """Verify append() correctly detects mismatch of number of + headers and data + """ data = tablib.Dataset() data.headers = ['first', 'second'] From f01cf184d4d1a94ac16ac33e84bb6ea71d9ff485 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 21:03:29 -0500 Subject: [PATCH 03/81] Added simple test for slicing by headers --- test_tablib.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test_tablib.py b/test_tablib.py index 13aa66b..f63ba9d 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -26,7 +26,9 @@ class TablibTestCase(unittest.TestCase): 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) def test_empty_append_with_headers(self): """Verify append() correctly detects mismatch of number of @@ -39,6 +41,23 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, new_row) + def test_header_slicing(self): + """Verify slicing by headers""" + + headers = ('first_name', 'last_name', 'gpa') + + data = [ + ('John', 'Adams', 90), + ('George', 'Washington', 67) + ] + + data = tablib.Dataset(*data, headers=headers) + + # Slice by headers + self.assertEqual(data['first_name'], ['John', 'George']) + self.assertEqual(data['last_name'], ['Adams', 'Washington']) + self.assertEqual(data['gpa'], [90, 67]) + # def test_adding_header with (self): From 8673710ddb6dbd13d61cd6015352910a5df105aa Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 21:08:31 -0500 Subject: [PATCH 04/81] Refactored creation of data set into setUp - Broke out tuples for more robust comparisions --- test_tablib.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index f63ba9d..8dcbb94 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -12,8 +12,14 @@ class TablibTestCase(unittest.TestCase): """Tablib test cases""" def setUp(self): - """setup""" - pass + """Create simple data set with headers""" + headers = ('first_name', 'last_name', 'gpa') + self.john = ('John', 'Adams', 90) + self.george = ('George', 'Washington', 67) + + self.founders = tablib.Dataset(headers=headers) + self.founders.append(self.john) + self.founders.append(self.george) def tearDown(self): """teardown""" @@ -44,19 +50,10 @@ class TablibTestCase(unittest.TestCase): def test_header_slicing(self): """Verify slicing by headers""" - headers = ('first_name', 'last_name', 'gpa') - - data = [ - ('John', 'Adams', 90), - ('George', 'Washington', 67) - ] - - data = tablib.Dataset(*data, headers=headers) - # Slice by headers - self.assertEqual(data['first_name'], ['John', 'George']) - self.assertEqual(data['last_name'], ['Adams', 'Washington']) - self.assertEqual(data['gpa'], [90, 67]) + self.assertEqual(self.founders['first_name'], [self.john[0], self.george[0]]) + self.assertEqual(self.founders['last_name'], [self.john[1], self.george[1]]) + self.assertEqual(self.founders['gpa'], [self.john[2], self.george[2]]) # def test_adding_header with (self): From 5468dd7e679cd33ec6223ef451197d341ff2f32d Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 21:23:20 -0500 Subject: [PATCH 05/81] Added test for slicing data elements --- test_tablib.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test_tablib.py b/test_tablib.py index 8dcbb94..670a41b 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -50,11 +50,25 @@ class TablibTestCase(unittest.TestCase): def test_header_slicing(self): """Verify slicing by headers""" - # Slice by headers self.assertEqual(self.founders['first_name'], [self.john[0], self.george[0]]) self.assertEqual(self.founders['last_name'], [self.john[1], self.george[1]]) self.assertEqual(self.founders['gpa'], [self.john[2], self.george[2]]) + def test_data_slicing(self): + """Verify slicing by data""" + + # Slice individual rows + self.assertEqual(self.founders[0], self.john) + self.assertEqual(self.founders[:1], [self.john]) + self.assertEqual(self.founders[1:2], [self.george]) + self.assertEqual(self.founders[2:], []) + self.assertEqual(self.founders[-1], self.george) + + # Slice multiple rows + self.assertEqual(self.founders[:], [self.john, self.george]) + self.assertEqual(self.founders[0:2], [self.john, self.george]) + self.assertEqual(self.founders[2:], []) + # def test_adding_header with (self): From 4755020dd7f6e9e7451c3c6518de0db0ba3fc620 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 21:26:15 -0500 Subject: [PATCH 06/81] Added extra row to base data set - Testing with 3 rows is a bit more interesting --- test_tablib.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 670a41b..544ca12 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -16,10 +16,12 @@ class TablibTestCase(unittest.TestCase): headers = ('first_name', 'last_name', 'gpa') self.john = ('John', 'Adams', 90) self.george = ('George', 'Washington', 67) + self.tom = ('Thomas', 'Jefferson', 50) self.founders = tablib.Dataset(headers=headers) self.founders.append(self.john) self.founders.append(self.george) + self.founders.append(self.tom) def tearDown(self): """teardown""" @@ -50,9 +52,12 @@ class TablibTestCase(unittest.TestCase): def test_header_slicing(self): """Verify slicing by headers""" - self.assertEqual(self.founders['first_name'], [self.john[0], self.george[0]]) - self.assertEqual(self.founders['last_name'], [self.john[1], self.george[1]]) - self.assertEqual(self.founders['gpa'], [self.john[2], self.george[2]]) + self.assertEqual(self.founders['first_name'], + [self.john[0], self.george[0], self.tom[0]]) + self.assertEqual(self.founders['last_name'], + [self.john[1], self.george[1], self.tom[1]]) + self.assertEqual(self.founders['gpa'], + [self.john[2], self.george[2], self.tom[2]]) def test_data_slicing(self): """Verify slicing by data""" @@ -61,13 +66,13 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(self.founders[0], self.john) self.assertEqual(self.founders[:1], [self.john]) self.assertEqual(self.founders[1:2], [self.george]) - self.assertEqual(self.founders[2:], []) - self.assertEqual(self.founders[-1], self.george) + self.assertEqual(self.founders[-1], self.tom) + self.assertEqual(self.founders[3:], []) # Slice multiple rows - self.assertEqual(self.founders[:], [self.john, self.george]) + self.assertEqual(self.founders[:], [self.john, self.george, self.tom]) self.assertEqual(self.founders[0:2], [self.john, self.george]) - self.assertEqual(self.founders[2:], []) + self.assertEqual(self.founders[2:], [self.tom]) # def test_adding_header with (self): From 52db1ddc3eca6f4a0b3bb7ff2f71501d6b15d571 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Mon, 13 Sep 2010 21:27:35 -0500 Subject: [PATCH 07/81] Fixed typo in test from previous commit --- test_tablib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_tablib.py b/test_tablib.py index 544ca12..3111206 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -72,6 +72,7 @@ class TablibTestCase(unittest.TestCase): # Slice multiple rows self.assertEqual(self.founders[:], [self.john, self.george, self.tom]) self.assertEqual(self.founders[0:2], [self.john, self.george]) + self.assertEqual(self.founders[1:3], [self.george, self.tom]) self.assertEqual(self.founders[2:], [self.tom]) # def test_adding_header with (self): From 7cd82f956fe6a855abcb2f7d085bb0c83a6e4f98 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 15 Sep 2010 23:46:40 -0400 Subject: [PATCH 08/81] Version Bump. --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 2bf7a3b..7852f75 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,7 +1,7 @@ History ======= -0.6.2 (2010-09-14) +0.6.3 (2010-09-14) ------------------ * Added Dataset.append() support for columns. From 49dc4a249eef20f8f844da333d128e4519bf713e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 15 Sep 2010 23:46:56 -0400 Subject: [PATCH 09/81] Removed useless is_string function. --- tablib/core.py | 2 +- tablib/helpers.py | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index e4ceee1..658fd10 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -54,7 +54,7 @@ class Dataset(object): def __getitem__(self, key): - if is_string(key): + if isinstance(key, basestring): if key in self.headers: pos = self.headers.index(key) # get 'key' index from each data return [row[pos] for row in self._data] diff --git a/tablib/helpers.py b/tablib/helpers.py index b64d4b6..f20700d 100644 --- a/tablib/helpers.py +++ b/tablib/helpers.py @@ -14,12 +14,7 @@ class Struct(object): def piped(): - """Returns piped input via stdin, else False""" + """Returns piped input via stdin, else False.""" with sys.stdin as stdin: return stdin.read() if not stdin.isatty() else None - -def is_string(obj): - """Tests if an object is a string""" - - return True if type(obj).__name__ == 'str' else False \ No newline at end of file From dbcea81c170b0bb101a23428e648034d1ab41258 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 16 Sep 2010 00:59:58 -0400 Subject: [PATCH 10/81] Inline docs. --- tablib/helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tablib/helpers.py b/tablib/helpers.py index f20700d..0a91e56 100644 --- a/tablib/helpers.py +++ b/tablib/helpers.py @@ -16,5 +16,6 @@ class Struct(object): def piped(): """Returns piped input via stdin, else False.""" with sys.stdin as stdin: + # TTY is only way to detect if stdin contains data return stdin.read() if not stdin.isatty() else None From bd470684a4d0cdf5f7e5ea127d28a89a92ef33b6 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 16:06:47 -0500 Subject: [PATCH 11/81] Ignore file update - Update ignoring of python leftovers - Added vi noise --- .gitignore | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 91c9479..7b0b8c5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,8 @@ dist/* MANIFEST # python skin -.pyc -.pyo +*.pyc +*.pyo # osx noise .DS_Store @@ -15,3 +15,5 @@ profile .idea .idea/* +# vi noise +*.swp From 7ba2849829f2265973f434ab318b4af1a0e2ad4b Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 16:16:31 -0500 Subject: [PATCH 12/81] Misc. PEP8 whitespace celeanup --- test_tablib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index ad7bcd9..ac51ed8 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -32,7 +32,7 @@ class TablibTestCase(unittest.TestCase): def test_empty_append(self): """Verify append() correctly adds tuple with no headers""" - new_row = (1,2,3) + new_row = (1, 2, 3) data.append(new_row) # Verify width/data @@ -48,7 +48,6 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, new_row) - def test_add_column(self): # No Headers @@ -68,7 +67,7 @@ class TablibTestCase(unittest.TestCase): data.append(col=new_col) self.assertEquals(data[new_col[0]], new_col[1:]) - + def test_add_column_no_data_no_headers(self): # no headers @@ -94,11 +93,11 @@ class TablibTestCase(unittest.TestCase): self.assertEquals(data.width, 3) new_col = ('foo', 'bar') - + self.assertRaises(tablib.InvalidDimensions, data.append, col=new_col) def tuple_check(self): - data.append(col=(1,2,3)) + data.append(col=(1, 2, 3)) def test_header_slicing(self): """Verify slicing by headers""" @@ -126,6 +125,6 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(self.founders[1:3], [self.george, self.tom]) self.assertEqual(self.founders[2:], [self.tom]) - + if __name__ == '__main__': unittest.main() From fad3546614ceadf6c6be8fdcbd2ce6fc0237c211 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 16:25:18 -0500 Subject: [PATCH 13/81] Added docstrings --- test_tablib.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index ac51ed8..9002ee8 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -49,7 +49,7 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, new_row) def test_add_column(self): - # No Headers + """Verify adding column works with/without headers""" data.append(['kenneth']) data.append(['bessie']) @@ -69,8 +69,7 @@ class TablibTestCase(unittest.TestCase): self.assertEquals(data[new_col[0]], new_col[1:]) def test_add_column_no_data_no_headers(self): - - # no headers + """Verify adding new column with no headers""" new_col = ('reitz', 'monke') @@ -81,8 +80,7 @@ class TablibTestCase(unittest.TestCase): self.assertEquals(data.height, len(new_col)) def test_add_column_no_data_with_headers(self): - - # no headers + """Verify adding new column with headers""" data.headers = ('first', 'last') From 99a45814d1205ba9a3f5c7045ccf232afc0ba310 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 16:36:17 -0500 Subject: [PATCH 14/81] Added tests del functionality --- test_tablib.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test_tablib.py b/test_tablib.py index 9002ee8..0fffdc9 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -123,6 +123,20 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(self.founders[1:3], [self.george, self.tom]) self.assertEqual(self.founders[2:], [self.tom]) + def test_delete(self): + """Verify deleting from dataset works""" + + # Delete from front of object + del self.founders[0] + self.assertEqual(self.founders[:], [self.george, self.tom]) + + # Delete from back of object + del self.founders[1] + self.assertEqual(self.founders[:], [self.george]) + + # Delete from invalid index + self.assertRaises(IndexError, self.founders.__delitem__, 3) + if __name__ == '__main__': unittest.main() From 391ad61bef1d37fcb3b5aa2650a355588082f8c1 Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 16:41:23 -0500 Subject: [PATCH 15/81] Improved del test - Added testing for data set width/height --- test_tablib.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test_tablib.py b/test_tablib.py index 0fffdc9..b4b4fbc 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -130,10 +130,18 @@ class TablibTestCase(unittest.TestCase): del self.founders[0] self.assertEqual(self.founders[:], [self.george, self.tom]) + # Verify dimensions, width should NOT change + self.assertEqual(self.founders.height, 2) + self.assertEqual(self.founders.width, 3) + # Delete from back of object del self.founders[1] self.assertEqual(self.founders[:], [self.george]) + # Verify dimensions, width should NOT change + self.assertEqual(self.founders.height, 1) + self.assertEqual(self.founders.width, 3) + # Delete from invalid index self.assertRaises(IndexError, self.founders.__delitem__, 3) From d54d70bc223ab4f5d85e61e9b9d4c6376739012f Mon Sep 17 00:00:00 2001 From: Luke Lee Date: Sun, 19 Sep 2010 17:04:14 -0500 Subject: [PATCH 16/81] Added test for csv export --- test_tablib.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index b4b4fbc..09d05f6 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -16,12 +16,12 @@ class TablibTestCase(unittest.TestCase): global data data = tablib.Dataset() - headers = ('first_name', 'last_name', 'gpa') + self.headers = ('first_name', 'last_name', 'gpa') self.john = ('John', 'Adams', 90) self.george = ('George', 'Washington', 67) self.tom = ('Thomas', 'Jefferson', 50) - self.founders = tablib.Dataset(headers=headers) + self.founders = tablib.Dataset(headers=self.headers) self.founders.append(self.john) self.founders.append(self.george) self.founders.append(self.tom) @@ -145,6 +145,23 @@ class TablibTestCase(unittest.TestCase): # Delete from invalid index self.assertRaises(IndexError, self.founders.__delitem__, 3) + 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) + if __name__ == '__main__': unittest.main() From efc516f36668d0dbea1bfb1ace684bbc14c6cda1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 19 Sep 2010 23:23:03 -0400 Subject: [PATCH 17/81] PEP8. --- test_tablib.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test_tablib.py b/test_tablib.py index 09d05f6..a88a297 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -26,10 +26,12 @@ class TablibTestCase(unittest.TestCase): self.founders.append(self.george) self.founders.append(self.tom) + def tearDown(self): """teardown""" pass + def test_empty_append(self): """Verify append() correctly adds tuple with no headers""" new_row = (1, 2, 3) @@ -39,6 +41,7 @@ class TablibTestCase(unittest.TestCase): self.assertTrue(data.width == len(new_row)) self.assertTrue(data[0] == new_row) + def test_empty_append_with_headers(self): """Verify append() correctly detects mismatch of number of headers and data @@ -48,6 +51,7 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, new_row) + def test_add_column(self): """Verify adding column works with/without headers""" @@ -68,6 +72,7 @@ class TablibTestCase(unittest.TestCase): self.assertEquals(data[new_col[0]], new_col[1:]) + def test_add_column_no_data_no_headers(self): """Verify adding new column with no headers""" @@ -79,6 +84,7 @@ class TablibTestCase(unittest.TestCase): self.assertEquals(data.width, 1) self.assertEquals(data.height, len(new_col)) + def test_add_column_no_data_with_headers(self): """Verify adding new column with headers""" @@ -94,9 +100,11 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, col=new_col) + def tuple_check(self): data.append(col=(1, 2, 3)) + def test_header_slicing(self): """Verify slicing by headers""" @@ -107,6 +115,7 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(self.founders['gpa'], [self.john[2], self.george[2], self.tom[2]]) + def test_data_slicing(self): """Verify slicing by data""" @@ -123,6 +132,7 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(self.founders[1:3], [self.george, self.tom]) self.assertEqual(self.founders[2:], [self.tom]) + def test_delete(self): """Verify deleting from dataset works""" @@ -145,6 +155,7 @@ class TablibTestCase(unittest.TestCase): # Delete from invalid index self.assertRaises(IndexError, self.founders.__delitem__, 3) + def test_csv_export(self): """Verify exporting dataset object as CSV""" From 2d3dc5ef71ec1d0e9cbfccd9300c96a9eee080a6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 19 Sep 2010 23:26:18 -0400 Subject: [PATCH 18/81] PEP257. --- test_tablib.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index a88a297..93f2162 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -"""Tests for tablib""" +"""Tests for tablib.""" import unittest @@ -9,10 +9,10 @@ import tablib class TablibTestCase(unittest.TestCase): - """Tablib test cases""" + """Tablib test cases.""" def setUp(self): - """Create simple data set with headers""" + """Create simple data set with headers.""" global data data = tablib.Dataset() @@ -28,12 +28,12 @@ class TablibTestCase(unittest.TestCase): def tearDown(self): - """teardown""" + """Teardown.""" pass def test_empty_append(self): - """Verify append() correctly adds tuple with no headers""" + """Verify append() correctly adds tuple with no headers.""" new_row = (1, 2, 3) data.append(new_row) @@ -44,7 +44,7 @@ class TablibTestCase(unittest.TestCase): def test_empty_append_with_headers(self): """Verify append() correctly detects mismatch of number of - headers and data + headers and data. """ data.headers = ['first', 'second'] new_row = (1, 2, 3, 4) @@ -53,7 +53,7 @@ class TablibTestCase(unittest.TestCase): def test_add_column(self): - """Verify adding column works with/without headers""" + """Verify adding column works with/without headers.""" data.append(['kenneth']) data.append(['bessie']) @@ -74,7 +74,7 @@ class TablibTestCase(unittest.TestCase): def test_add_column_no_data_no_headers(self): - """Verify adding new column with no headers""" + """Verify adding new column with no headers.""" new_col = ('reitz', 'monke') @@ -86,7 +86,7 @@ class TablibTestCase(unittest.TestCase): def test_add_column_no_data_with_headers(self): - """Verify adding new column with headers""" + """Verify adding new column with headers.""" data.headers = ('first', 'last') @@ -102,11 +102,12 @@ class TablibTestCase(unittest.TestCase): def tuple_check(self): + #TODO: tuple check data.append(col=(1, 2, 3)) def test_header_slicing(self): - """Verify slicing by headers""" + """Verify slicing by headers.""" self.assertEqual(self.founders['first_name'], [self.john[0], self.george[0], self.tom[0]]) @@ -117,7 +118,7 @@ class TablibTestCase(unittest.TestCase): def test_data_slicing(self): - """Verify slicing by data""" + """Verify slicing by data.""" # Slice individual rows self.assertEqual(self.founders[0], self.john) @@ -134,7 +135,7 @@ class TablibTestCase(unittest.TestCase): def test_delete(self): - """Verify deleting from dataset works""" + """Verify deleting from dataset works.""" # Delete from front of object del self.founders[0] @@ -157,7 +158,7 @@ class TablibTestCase(unittest.TestCase): def test_csv_export(self): - """Verify exporting dataset object as CSV""" + """Verify exporting dataset object as CSV.""" # Build up the csv string with headers first, followed by each row csv = "" @@ -174,5 +175,9 @@ class TablibTestCase(unittest.TestCase): self.assertEqual(csv, self.founders.csv) + def test_unicode_append(self): + """Passes in a single unicode charecter and exports.""" + pass + if __name__ == '__main__': unittest.main() From 649c7e8bb70f55c8046e73fd38f75ba7de52e87e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 19 Sep 2010 23:31:05 -0400 Subject: [PATCH 19/81] Removed unneeded tuple_check. --- test_tablib.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 93f2162..f431f19 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -101,11 +101,6 @@ class TablibTestCase(unittest.TestCase): self.assertRaises(tablib.InvalidDimensions, data.append, col=new_col) - def tuple_check(self): - #TODO: tuple check - data.append(col=(1, 2, 3)) - - def test_header_slicing(self): """Verify slicing by headers.""" From 2c60ce9233c7a3960c8c4e057ecc510e11b275e1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 19 Sep 2010 23:51:48 -0400 Subject: [PATCH 20/81] String decoding to avoid unicode collisions for XLS output. --- tablib/core.py | 2 +- test_tablib.py | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 658fd10..7419d69 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -189,7 +189,7 @@ class Dataset(object): ws = wb.add_sheet(self.title if self.title else 'Tabbed Dataset') for i, row in enumerate(self._package(dicts=False)): for j, col in enumerate(row): - ws.write(i, j, str(col)) + ws.write(i, j, col.decode('utf8')) wb.save(stream) return stream.getvalue() diff --git a/test_tablib.py b/test_tablib.py index f431f19..959a01c 100644 --- a/test_tablib.py +++ b/test_tablib.py @@ -156,23 +156,31 @@ class TablibTestCase(unittest.TestCase): """Verify exporting dataset object as CSV.""" # Build up the csv string with headers first, followed by each row - csv = "" + csv = '' for col in self.headers: - csv += col + "," + csv += col + ',' - csv = csv.strip(",") + "\r\n" + csv = csv.strip(',') + '\r\n' for founder in self.founders: for col in founder: - csv += str(col) + "," - csv = csv.strip(",") + "\r\n" + csv += str(col) + ',' + csv = csv.strip(',') + '\r\n' self.assertEqual(csv, self.founders.csv) def test_unicode_append(self): """Passes in a single unicode charecter and exports.""" - pass + new_row = ('å', 'é') + data.append(new_row) + + data.json + data.yaml + data.csv + data.xls + + if __name__ == '__main__': unittest.main() From ccf2ebcde29afe6a21f7a7973d510f383e982a93 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 08:57:49 -0400 Subject: [PATCH 21/81] Version bump (v0.6.4) --- HISTORY.rst | 11 +++++++++++ setup.py | 2 +- tablib/core.py | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 5d2ba1e..01aba67 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,17 @@ History ======= +0.6.4 (2010-09-13) +------------------ + +* Updated unicode export for XLS +* More exhaustive unit tests + +0.6.3(2010-09-14) +---------------- + +* Added Dataset.append() support for columns + 0.6.2 (2010-09-13) ------------------ * Fixed Dataset.append() error on empty dataset. diff --git a/setup.py b/setup.py index 02c84d3..f9b71ea 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.6.3', + version='0.6.4', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), diff --git a/tablib/core.py b/tablib/core.py index e4ceee1..015a072 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -21,8 +21,8 @@ from helpers import * # __all__ = ['Dataset', 'DataBook'] __name__ = 'tablib' -__version__ = '0.6.3' -__build__ = 0x000603 +__version__ = '0.6.4' +__build__ = 0x000604 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' From 04a16afa58d0b7451d452ede8a549d2bf1f5207a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 09:14:08 -0400 Subject: [PATCH 22/81] Chmox. --- test_tablib.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test_tablib.py diff --git a/test_tablib.py b/test_tablib.py old mode 100644 new mode 100755 From 3b44349090daa69e298f5d63925deca29e7cc06f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 09:21:02 -0400 Subject: [PATCH 23/81] Version bump (0.6.4). --- HISTORY.rst | 7 +++++++ setup.py | 2 +- tablib/core.py | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7852f75..c113ff5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,13 @@ History ======= +0.6.4 (2010-09-13) +------------------ + +* Updated unicode export for XLS +* More exhaustive unit tests + + 0.6.3 (2010-09-14) ------------------ * Added Dataset.append() support for columns. diff --git a/setup.py b/setup.py index 02c84d3..f9b71ea 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.6.3', + version='0.6.4', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), diff --git a/tablib/core.py b/tablib/core.py index 7419d69..e97b8a6 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -21,8 +21,8 @@ from helpers import * # __all__ = ['Dataset', 'DataBook'] __name__ = 'tablib' -__version__ = '0.6.3' -__build__ = 0x000603 +__version__ = '0.6.4' +__build__ = 0x000604 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' From bfbb7c626ff70b9d840648cee546d4d2fad349a3 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 12:50:10 -0400 Subject: [PATCH 24/81] Moved from cStringIO to StringIO. More stable. --- tablib/core.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index e97b8a6..9e0c4e3 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -8,7 +8,7 @@ import csv -import cStringIO +import StringIO import random import simplejson as json @@ -171,7 +171,7 @@ class Dataset(object): @property def csv(self): """Returns CSV representation of Dataset.""" - stream = cStringIO.StringIO() + stream = StringIO.StringIO() _csv = csv.writer(stream) for row in self._package(dicts=False): @@ -183,13 +183,13 @@ class Dataset(object): @property def xls(self): """Returns XLS representation of Dataset.""" - stream = cStringIO.StringIO() + stream = StringIO.StringIO() - wb = xlwt.Workbook() + wb = xlwt.Workbook(encoding='utf8') ws = wb.add_sheet(self.title if self.title else 'Tabbed Dataset') for i, row in enumerate(self._package(dicts=False)): for j, col in enumerate(row): - ws.write(i, j, col.decode('utf8')) + ws.write(i, j, col) wb.save(stream) return stream.getvalue() @@ -272,7 +272,7 @@ class DataBook(object): """Returns XLS representation of DataBook.""" stream = cStringIO.StringIO() - wb = xlwt.Workbook() + wb = xlwt.Workbook(encoding='utf8') for i, dset in enumerate(self._datasets): ws = wb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i)) @@ -280,7 +280,7 @@ class DataBook(object): #for row in self._package(dicts=False): for i, row in enumerate(dset._package(dicts=False)): for j, col in enumerate(row): - ws.write(i, j, str(col)) + ws.write(i, j, col) wb.save(stream) return stream.getvalue() From f94a236122e4d40d7d79a5f52ff45fdb1debd5d6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 14:04:02 -0400 Subject: [PATCH 25/81] Changed export properties to methods. --- tablib/core.py | 16 ++++------------ test_tablib.py | 10 +++++----- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 9e0c4e3..a86c4ea 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -149,26 +149,22 @@ class Dataset(object): self.__headers = None - @property def dict(self): """Returns python dict of Dataset.""" return self._package() - @property def json(self): """Returns JSON representation of Dataset.""" return json.dumps(self.dict) - @property def yaml(self): """Returns YAML representation of Dataset.""" return yaml.dump(self.dict) - @property def csv(self): """Returns CSV representation of Dataset.""" stream = StringIO.StringIO() @@ -180,8 +176,7 @@ class Dataset(object): return stream.getvalue() - @property - def xls(self): + def xls(self, path=None): """Returns XLS representation of Dataset.""" stream = StringIO.StringIO() @@ -256,7 +251,7 @@ class DataBook(object): for dset in self._datasets: collector.append(dict( title = dset.title, - data = dset.dict + data = dset.dict() )) return collector @@ -267,8 +262,7 @@ class DataBook(object): return len(self._datasets) - @property - def xls(self): + def xls(self, path=None): """Returns XLS representation of DataBook.""" stream = cStringIO.StringIO() @@ -285,15 +279,13 @@ class DataBook(object): wb.save(stream) return stream.getvalue() - - @property + def json(self): """Returns JSON representation of Databook.""" return json.dumps(self._package()) - @property def yaml(self): """Returns YAML representation of Databook.""" diff --git a/test_tablib.py b/test_tablib.py index 959a01c..fc8cb7d 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -167,7 +167,7 @@ class TablibTestCase(unittest.TestCase): csv += str(col) + ',' csv = csv.strip(',') + '\r\n' - self.assertEqual(csv, self.founders.csv) + self.assertEqual(csv, self.founders.csv()) def test_unicode_append(self): @@ -176,10 +176,10 @@ class TablibTestCase(unittest.TestCase): new_row = ('å', 'é') data.append(new_row) - data.json - data.yaml - data.csv - data.xls + data.json() + data.yaml() + data.csv() + data.xls() if __name__ == '__main__': From 81445aeec8ceab0126a17e8d0130b548c5c3eca1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 14:05:15 -0400 Subject: [PATCH 26/81] Updated readme to reflect property to method changes. --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 32d477f..4fe26bd 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ JSON! +++++ :: - >>> print data.json + >>> print data.json() [ { "last_name": "Adams", @@ -89,7 +89,7 @@ YAML! +++++ :: - >>> print data.yaml + >>> print data.yaml() - {age: 90, first_name: John, last_name: Adams} - {age: 83, first_name: Henry, last_name: Ford} @@ -97,7 +97,7 @@ CSV... ++++++ :: - >>> print data.csv + >>> print data.csv() first_name,last_name,age John,Adams,90 Henry,Ford,83 @@ -106,8 +106,8 @@ EXCEL! ++++++ :: - >>> open('people.xls').write(data.xls) - + >>> data.xls('people.xls') + It's that easy. From e8f5e023c48dc318ede162cf49ae064c8b8e698e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 14:18:18 -0400 Subject: [PATCH 27/81] Version bump (v0.7.0). --- HISTORY.rst | 15 ++++++++++++--- setup.py | 2 +- tablib/core.py | 30 +++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index c113ff5..ca0470f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,11 +1,20 @@ History ======= -0.6.4 (2010-09-13) +0.7.0 (2010-09-20) ------------------ -* Updated unicode export for XLS -* More exhaustive unit tests +* Renamed DataBook Databook for consistiency. +* Export properties changed to methods (XLS filename / StringIO bug). +* Optional Dataset.xls(path='filename') support (for writing on windows). +* Added utf-8 on the worksheet level. + + +0.6.4 (2010-09-19) +------------------ + +* Updated unicode export for XLS. +* More exhaustive unit tests. 0.6.3 (2010-09-14) diff --git a/setup.py b/setup.py index f9b71ea..c853439 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.6.4', + version='0.7.0', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), diff --git a/tablib/core.py b/tablib/core.py index a86c4ea..f300be6 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -21,8 +21,8 @@ from helpers import * # __all__ = ['Dataset', 'DataBook'] __name__ = 'tablib' -__version__ = '0.6.4' -__build__ = 0x000604 +__version__ = '0.7.0' +__build__ = 0x000700 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' @@ -178,16 +178,21 @@ class Dataset(object): def xls(self, path=None): """Returns XLS representation of Dataset.""" - stream = StringIO.StringIO() wb = xlwt.Workbook(encoding='utf8') ws = wb.add_sheet(self.title if self.title else 'Tabbed Dataset') + for i, row in enumerate(self._package(dicts=False)): for j, col in enumerate(row): ws.write(i, j, col) - wb.save(stream) - return stream.getvalue() + if path: + wb.save(path) + return True + else: + stream = StringIO.StringIO() + wb.save(stream) + return stream.getvalue() def append(self, row=None, col=None): @@ -222,7 +227,7 @@ class Dataset(object): pass -class DataBook(object): +class Databook(object): """A book of Dataset objects. Currently, this exists only for XLS workbook support. """ @@ -265,7 +270,7 @@ class DataBook(object): def xls(self, path=None): """Returns XLS representation of DataBook.""" - stream = cStringIO.StringIO() + wb = xlwt.Workbook(encoding='utf8') for i, dset in enumerate(self._datasets): @@ -276,8 +281,15 @@ class DataBook(object): for j, col in enumerate(row): ws.write(i, j, col) - wb.save(stream) - return stream.getvalue() + + + if path: + wb.save(path) + return True + else: + stream = cStringIO.StringIO() + wb.save(stream) + return stream.getvalue() def json(self): From 9b3268f0adaeab7968f72f52f00e5f7659a0d219 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 14:37:10 -0400 Subject: [PATCH 28/81] Whoops. --- tablib/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index f300be6..730f673 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -256,7 +256,7 @@ class Databook(object): for dset in self._datasets: collector.append(dict( title = dset.title, - data = dset.dict() + data = dset.dict )) return collector From 4fc70957ac4fc796f27e199e12cc54cc2115b374 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 21:33:48 -0400 Subject: [PATCH 29/81] Reverted methods back to properties. --- tablib/core.py | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 730f673..1cdfeb2 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -8,7 +8,7 @@ import csv -import StringIO +import cStringIO import random import simplejson as json @@ -155,19 +155,20 @@ class Dataset(object): return self._package() + @property def json(self): """Returns JSON representation of Dataset.""" return json.dumps(self.dict) - + @property def yaml(self): """Returns YAML representation of Dataset.""" return yaml.dump(self.dict) - + @property def csv(self): """Returns CSV representation of Dataset.""" - stream = StringIO.StringIO() + stream = cStringIO.StringIO() _csv = csv.writer(stream) for row in self._package(dicts=False): @@ -175,8 +176,8 @@ class Dataset(object): return stream.getvalue() - - def xls(self, path=None): + @property + def xls(self): """Returns XLS representation of Dataset.""" wb = xlwt.Workbook(encoding='utf8') @@ -186,13 +187,9 @@ class Dataset(object): for j, col in enumerate(row): ws.write(i, j, col) - if path: - wb.save(path) - return True - else: - stream = StringIO.StringIO() - wb.save(stream) - return stream.getvalue() + stream = cStringIO.StringIO() + wb.save(stream) + return stream.getvalue() def append(self, row=None, col=None): @@ -266,8 +263,8 @@ class Databook(object): """The number of the Datasets within DataBook.""" return len(self._datasets) - - def xls(self, path=None): + @property + def xls(self): """Returns XLS representation of DataBook.""" @@ -282,22 +279,19 @@ class Databook(object): ws.write(i, j, col) - - if path: - wb.save(path) - return True - else: - stream = cStringIO.StringIO() - wb.save(stream) - return stream.getvalue() + stream = cStringIO.StringIO() + wb.save(stream) + return stream.getvalue() + @property def json(self): """Returns JSON representation of Databook.""" return json.dumps(self._package()) + @property def yaml(self): """Returns YAML representation of Databook.""" From 31e4c39762d9ddab781c55b1c23fc6a21a4c6a31 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 21:34:01 -0400 Subject: [PATCH 30/81] Updated tests for reverted methods. --- test_tablib.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index fc8cb7d..959a01c 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -167,7 +167,7 @@ class TablibTestCase(unittest.TestCase): csv += str(col) + ',' csv = csv.strip(',') + '\r\n' - self.assertEqual(csv, self.founders.csv()) + self.assertEqual(csv, self.founders.csv) def test_unicode_append(self): @@ -176,10 +176,10 @@ class TablibTestCase(unittest.TestCase): new_row = ('å', 'é') data.append(new_row) - data.json() - data.yaml() - data.csv() - data.xls() + data.json + data.yaml + data.csv + data.xls if __name__ == '__main__': From dd13744c9223ec34a0ad9df44f70a95cd8d21b31 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 21:37:08 -0400 Subject: [PATCH 31/81] Documentation update for properties. --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 4fe26bd..6ef9c22 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ JSON! +++++ :: - >>> print data.json() + >>> print data.json [ { "last_name": "Adams", @@ -89,7 +89,7 @@ YAML! +++++ :: - >>> print data.yaml() + >>> print data.yaml - {age: 90, first_name: John, last_name: Adams} - {age: 83, first_name: Henry, last_name: Ford} @@ -97,7 +97,7 @@ CSV... ++++++ :: - >>> print data.csv() + >>> print data.csv first_name,last_name,age John,Adams,90 Henry,Ford,83 @@ -106,7 +106,7 @@ EXCEL! ++++++ :: - >>> data.xls('people.xls') + >>> open('people.xls', 'wb').write(data.xls) It's that easy. From 3407170b99772c6155498372ac41ca663c1961ec Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 21:37:32 -0400 Subject: [PATCH 32/81] Updated TODO. --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6ef9c22..c0333e7 100644 --- a/README.rst +++ b/README.rst @@ -131,7 +131,6 @@ If you'd like to contribute, simply fork `the repository`_, commit your changes Roadmap ------- -- Add ability to add/remove full columns - Import datasets from CSV, JSON, YAML - Release CLI Interface - Auto-detect import format @@ -141,4 +140,4 @@ Roadmap - Plugin support .. _`the repository`: http://github.com/kennethreitz/tablib -.. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS \ No newline at end of file +.. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS From 7364995eaabf49d35652754158151a232af08a22 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 20 Sep 2010 21:39:27 -0400 Subject: [PATCH 33/81] Version bump (v0.7.1) --- HISTORY.rst | 7 +++++++ setup.py | 2 +- tablib/core.py | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index ca0470f..d4b58d4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,13 @@ History ======= +0.7.1 (2010-09-20) +------------------ + +* Reverting methods back to properties. +* Windows bug compenated in documentation. + + 0.7.0 (2010-09-20) ------------------ diff --git a/setup.py b/setup.py index c853439..8816512 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.7.0', + version='0.7.1', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), diff --git a/tablib/core.py b/tablib/core.py index 1cdfeb2..0167c34 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -21,8 +21,8 @@ from helpers import * # __all__ = ['Dataset', 'DataBook'] __name__ = 'tablib' -__version__ = '0.7.0' -__build__ = 0x000700 +__version__ = '0.7.1' +__build__ = 0x000701 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' From 17e90e71e5406fc8621c254e58ae6cf169e38c34 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 02:54:43 -0400 Subject: [PATCH 34/81] test --- test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test.py diff --git a/test.py b/test.py new file mode 100644 index 0000000..0f021e4 --- /dev/null +++ b/test.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +import tablib + +data = tablib.Dataset() + +data.headers = ['a', 'b', 'c'] +data.append([1,2,3]) +data.append([1,2,3]) + +print data.dict + +new_data = tablib.formats.json.import_set(str(data.json)) +#print new_data.yaml + + + +# data.headers = ['one', 'two', 'three'] +# print data.dict \ No newline at end of file From fbe6fe161254a780ca47d0424f46069d0c34c352 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 02:55:21 -0400 Subject: [PATCH 35/81] fix old push --- test.py | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 0f021e4..0000000 --- a/test.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -import tablib - -data = tablib.Dataset() - -data.headers = ['a', 'b', 'c'] -data.append([1,2,3]) -data.append([1,2,3]) - -print data.dict - -new_data = tablib.formats.json.import_set(str(data.json)) -#print new_data.yaml - - - -# data.headers = ['one', 'two', 'three'] -# print data.dict \ No newline at end of file From b8f923f8c5713da12ffbf42bd3794f3cef2674bc Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:03:01 -0400 Subject: [PATCH 36/81] added Luke Lee to Authors --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 722a130..3d48743 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,4 +10,4 @@ Development Lead Patches and Suggestions ``````````````````````` -- A Lucky Someone \ No newline at end of file +- Luke Lee \ No newline at end of file From fbabb430ca7159cf0570193704367234e4c2b90b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:04:36 -0400 Subject: [PATCH 37/81] small setup.py fix --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 8816512..dc8142b 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,6 @@ def publish(): """Publish to PyPi""" os.system("python setup.py sdist upload") - if sys.argv[-1] == "publish": publish() sys.exit() From 579dbf0cc0686d568cb1386ccbbd81837c90e49b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:43:39 -0400 Subject: [PATCH 38/81] Added docstring. Removed unneeded import. --- tablib/core.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 0167c34..fae4547 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -1,21 +1,17 @@ # -*- coding: utf-8 -*- -# _____ ______ ______ _________ -# __ /_______ ____ /_ ___ /_ _____ ______ / -# _ __/_ __ `/__ __ \__ __ \_ _ \_ __ / -# / /_ / /_/ / _ /_/ /_ /_/ // __// /_/ / -# \__/ \__,_/ /_.___/ /_.___/ \___/ \__,_/ +""" Tablib - Core Library +""" import csv import cStringIO -import random import simplejson as json import xlwt import yaml -from helpers import * +from helpers import Struct # __all__ = ['Dataset', 'DataBook'] From 0e6bd079cc05cc3d7312a2c6e002d1d536ab7da1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:43:45 -0400 Subject: [PATCH 39/81] Improved docstring. --- tablib/helpers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tablib/helpers.py b/tablib/helpers.py index 0a91e56..a3b94b3 100644 --- a/tablib/helpers.py +++ b/tablib/helpers.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +""" Tablib - General Helpers. +""" + import sys From 703b1da04cf3b3c883b26ad9746b16e59da377d3 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:45:22 -0400 Subject: [PATCH 40/81] General cleanups for pylint. --- tablib/core.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index fae4547..1022e07 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -11,12 +11,8 @@ import simplejson as json import xlwt import yaml -from helpers import Struct - -# __all__ = ['Dataset', 'DataBook'] - -__name__ = 'tablib' +__title__ = 'tablib' __version__ = '0.7.1' __build__ = 0x000701 __author__ = 'Kenneth Reitz' @@ -36,12 +32,12 @@ class Dataset(object): try: self.headers = kwargs['headers'] - except KeyError, why: + except KeyError: self.headers = None try: self.title = kwargs['title'] - except KeyError, why: + except KeyError: self.title = None @@ -120,10 +116,10 @@ class Dataset(object): """Returns the width of the Dataset.""" try: return len(self._data[0]) - except IndexError, why: + except IndexError: try: return len(self.headers) - except TypeError, e: + except TypeError: return 0 @property From 8d6a52aaf5d228fa48d55f0133ea52e93537683e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:49:31 -0400 Subject: [PATCH 41/81] Cleanups for pylint. --- tablib/core.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 1022e07..f0eb43d 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -129,13 +129,13 @@ class Dataset(object): @headers.setter - def headers(self, collection): + def headers_set(self, collection): """Validating headers setter.""" self._validate(collection) if collection: try: self.__headers = list(collection) - except TypeError, why: + except TypeError: raise TypeError else: self.__headers = None @@ -260,19 +260,19 @@ class Databook(object): """Returns XLS representation of DataBook.""" - wb = xlwt.Workbook(encoding='utf8') + workb = xlwt.Workbook(encoding='utf8') for i, dset in enumerate(self._datasets): - ws = wb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i)) + works = workb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i)) #for row in self._package(dicts=False): for i, row in enumerate(dset._package(dicts=False)): for j, col in enumerate(row): - ws.write(i, j, col) + works.write(i, j, col) stream = cStringIO.StringIO() - wb.save(stream) + workb.save(stream) return stream.getvalue() From c3fa29a166bc91c202eee6faa432283b14fc46f3 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:51:56 -0400 Subject: [PATCH 42/81] Added public method for pylint. --- tablib/helpers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tablib/helpers.py b/tablib/helpers.py index a3b94b3..31b4558 100644 --- a/tablib/helpers.py +++ b/tablib/helpers.py @@ -15,6 +15,10 @@ class Struct(object): def __getitem__(self, key): return getattr(self, key, None) + def dictionary(self): + """Returns dictionary representation of object.""" + return self.__dict__ + def piped(): """Returns piped input via stdin, else False.""" From c01b66a16a84bd171dde1d22be39fea595e87ed4 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:53:20 -0400 Subject: [PATCH 43/81] Moving that back. --- tablib/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index f0eb43d..b8c147c 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -129,7 +129,7 @@ class Dataset(object): @headers.setter - def headers_set(self, collection): + def headers(self, collection): """Validating headers setter.""" self._validate(collection) if collection: From 93fb89b8b6915a277c66df458e9dd7b47a5a4be8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 04:58:24 -0400 Subject: [PATCH 44/81] Cleanup * imports. --- tablib/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tablib/__init__.py b/tablib/__init__.py index 5d20240..cf38bc5 100644 --- a/tablib/__init__.py +++ b/tablib/__init__.py @@ -1 +1,7 @@ -from core import * \ No newline at end of file +from tablib.core import ( + Databook, Dataset, InvalidDatasetType, + InvalidDimensions, UnsupportedFormat +) + +""" Tablib. +""" \ No newline at end of file From e52b8dd329903f96206a28dc0c0b1ab6ef455166 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:01:05 -0400 Subject: [PATCH 45/81] Added methods to struct for pylint. --- tablib/helpers.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tablib/helpers.py b/tablib/helpers.py index 31b4558..f75c466 100644 --- a/tablib/helpers.py +++ b/tablib/helpers.py @@ -19,6 +19,15 @@ class Struct(object): """Returns dictionary representation of object.""" return self.__dict__ + def items(self): + """Returns items within object.""" + return self.__dict__.items() + + def keys(self): + """Returns keys within object.""" + return self.__dict__.keys() + + def piped(): """Returns piped input via stdin, else False.""" From 4bb4a05bcbb044a9eaaac2e1e7eb11b41d3d9739 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:02:58 -0400 Subject: [PATCH 46/81] Longer varnames for pylint. --- tablib/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index b8c147c..bd07f10 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -172,15 +172,15 @@ class Dataset(object): def xls(self): """Returns XLS representation of Dataset.""" - wb = xlwt.Workbook(encoding='utf8') - ws = wb.add_sheet(self.title if self.title else 'Tabbed Dataset') + workb = xlwt.Workbook(encoding='utf8') + works = workb.add_sheet(self.title if self.title else 'Tabbed Dataset') for i, row in enumerate(self._package(dicts=False)): for j, col in enumerate(row): - ws.write(i, j, col) + works.write(i, j, col) stream = cStringIO.StringIO() - wb.save(stream) + workb.save(stream) return stream.getvalue() From 121cf46aec71486645031e73343c7f24f4c603ad Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:04:51 -0400 Subject: [PATCH 47/81] Corrected always-false condition. --- tablib/core.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index bd07f10..551a326 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -226,10 +226,7 @@ class Databook(object): def __repr__(self): - try: - return '<%s databook>' % (self.title.lower()) - except AttributeError: - return '' + return '' def add_sheet(self, dataset): From 82f3d84c7dfff4e31e36a645c3ff7d07a564df8f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:06:04 -0400 Subject: [PATCH 48/81] Added docstring. --- tablib/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tablib/__init__.py b/tablib/__init__.py index cf38bc5..fadd8dd 100644 --- a/tablib/__init__.py +++ b/tablib/__init__.py @@ -1,7 +1,8 @@ +""" Tablib. +""" + from tablib.core import ( Databook, Dataset, InvalidDatasetType, InvalidDimensions, UnsupportedFormat ) -""" Tablib. -""" \ No newline at end of file From f9c168e4bc9194228982f631e31331264a180119 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:08:35 -0400 Subject: [PATCH 49/81] Added coverage bin. --- .coverage | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .coverage diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..1bfb85e --- /dev/null +++ b/.coverage @@ -0,0 +1,4 @@ +}q(U collectorqU coverage v3.4qUlinesq}q(U1/Users/kreitz/repos/private/tablib/test_tablib.pyq]q(KKKK K KKKKKKKKKKKK K#K%K&K)K*K-K1K2K4K7K:K;K=K?KAKBKEKFKGKIKLKOKQKSKTKUKXK[K]K^K`KaKcKeKhKkKlKmKnKoKpKsKwKxKyKzK{K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKeU5/Users/kreitz/repos/private/tablib/tablib/__init__.pyq]q KaU1/Users/kreitz/repos/private/tablib/tablib/core.pyq +]q (K +K K KKKKKKKKKKKK K"K#K$K%K&K'K)K*K+K,K.K/K0K1K4K8K9K:K;K Date: Tue, 21 Sep 2010 02:42:08 -0400 Subject: [PATCH 50/81] Only CSV Left. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c0333e7..387a807 100644 --- a/README.rst +++ b/README.rst @@ -131,7 +131,7 @@ If you'd like to contribute, simply fork `the repository`_, commit your changes Roadmap ------- -- Import datasets from CSV, JSON, YAML +- Import datasets from CSV. - Release CLI Interface - Auto-detect import format - Add possible other exports (SQL?) From ac1666e3aea58c410b74a85ede2f2549212f571e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:14:07 -0400 Subject: [PATCH 51/81] removing garbage --- .coverage | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .coverage diff --git a/.coverage b/.coverage deleted file mode 100644 index 1bfb85e..0000000 --- a/.coverage +++ /dev/null @@ -1,4 +0,0 @@ -}q(U collectorqU coverage v3.4qUlinesq}q(U1/Users/kreitz/repos/private/tablib/test_tablib.pyq]q(KKKK K KKKKKKKKKKKK K#K%K&K)K*K-K1K2K4K7K:K;K=K?KAKBKEKFKGKIKLKOKQKSKTKUKXK[K]K^K`KaKcKeKhKkKlKmKnKoKpKsKwKxKyKzK{K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKeU5/Users/kreitz/repos/private/tablib/tablib/__init__.pyq]q KaU1/Users/kreitz/repos/private/tablib/tablib/core.pyq -]q (K -K K KKKKKKKKKKKK K"K#K$K%K&K'K)K*K+K,K.K/K0K1K4K8K9K:K;K Date: Sat, 25 Sep 2010 05:17:03 -0400 Subject: [PATCH 52/81] Pylint preps. --- tablib/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tablib/core.py b/tablib/core.py index 551a326..4342ebe 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -238,6 +238,7 @@ class Databook(object): def _package(self): + """Packages Databook for delivery.""" collector = [] for dset in self._datasets: collector.append(dict( From 5a993ac281f5dbfd0cee2039c61af0701e5fa323 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:49:14 -0400 Subject: [PATCH 53/81] Working on it. --- tablib/core.py | 138 ++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 82 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 551a326..2c9811a 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- -""" Tablib - Core Library -""" +# _____ ______ ______ _________ +# __ /_______ ____ /_ ___ /_ _____ ______ / +# _ __/_ __ `/__ __ \__ __ \_ _ \_ __ / +# / /_ / /_/ / _ /_/ /_ /_/ // __// /_/ / +# \__/ \__,_/ /_.___/ /_.___/ \___/ \__,_/ import csv @@ -11,6 +14,8 @@ import simplejson as json import xlwt import yaml +from tablib.formats import formats + __title__ = 'tablib' __version__ = '0.7.1' @@ -24,22 +29,20 @@ class Dataset(object): """Epic Tabular-Dataset object. """ def __init__(self, *args, **kwargs): - self._data = None - self._saved_file = None - self._saved_format = None self._data = list(args) self.__headers = None try: self.headers = kwargs['headers'] - except KeyError: + except KeyError, why: self.headers = None try: self.title = kwargs['title'] - except KeyError: + except KeyError, why: self.title = None + self._register_formats() def __len__(self): return self.height @@ -71,6 +74,16 @@ class Dataset(object): except AttributeError: return '' + + @classmethod + def _register_formats(cls): + """Adds format properties.""" + for fmt in formats: + try: + setattr(cls, fmt.title, property(fmt.export_set)) + except Exception, why: + pass + def _validate(self, row=None, col=None, safety=False): """Assures size of every row in dataset is of proper proportions.""" @@ -105,6 +118,7 @@ class Dataset(object): return data + @property def height(self): """Returns the height of the Dataset.""" @@ -116,12 +130,13 @@ class Dataset(object): """Returns the width of the Dataset.""" try: return len(self._data[0]) - except IndexError: + except IndexError, why: try: return len(self.headers) - except TypeError: + except TypeError, e: return 0 - + + @property def headers(self): """Headers property.""" @@ -135,7 +150,7 @@ class Dataset(object): if collection: try: self.__headers = list(collection) - except TypeError: + except TypeError, why: raise TypeError else: self.__headers = None @@ -146,42 +161,21 @@ class Dataset(object): """Returns python dict of Dataset.""" return self._package() - - @property - def json(self): - """Returns JSON representation of Dataset.""" - return json.dumps(self.dict) - - @property - def yaml(self): - """Returns YAML representation of Dataset.""" - return yaml.dump(self.dict) - - @property - def csv(self): - """Returns CSV representation of Dataset.""" - stream = cStringIO.StringIO() - _csv = csv.writer(stream) - - for row in self._package(dicts=False): - _csv.writerow(row) - - return stream.getvalue() - - @property - def xls(self): - """Returns XLS representation of Dataset.""" - - workb = xlwt.Workbook(encoding='utf8') - works = workb.add_sheet(self.title if self.title else 'Tabbed Dataset') - - for i, row in enumerate(self._package(dicts=False)): - for j, col in enumerate(row): - works.write(i, j, col) - - stream = cStringIO.StringIO() - workb.save(stream) - return stream.getvalue() + + @dict.setter + def dict(self, pickle): + """Returns python dict of Dataset.""" + if not len(pickle): + return + if isinstance(pickle[0], list): + for row in pickle: + self.append(row) + elif isinstance(pickle[0], dict): + self.headers = pickle[0].keys() + for row in pickle: + self.append(row.values()) + else: + raise UnsupportedFormat def append(self, row=None, col=None): @@ -223,10 +217,24 @@ class Databook(object): def __init__(self, sets=[]): self._datasets = sets + self._register_formats() def __repr__(self): - return '' + try: + return '<%s databook>' % (self.title.lower()) + except AttributeError: + return '' + + + @classmethod + def _register_formats(cls): + """Adds format properties.""" + for fmt in formats.formats: + try: + setattr(cls, fmt.title, property(fmt.export_book)) + except Exception, why: + pass def add_sheet(self, dataset): @@ -252,40 +260,6 @@ class Databook(object): """The number of the Datasets within DataBook.""" return len(self._datasets) - @property - def xls(self): - """Returns XLS representation of DataBook.""" - - - workb = xlwt.Workbook(encoding='utf8') - - for i, dset in enumerate(self._datasets): - works = workb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i)) - - #for row in self._package(dicts=False): - for i, row in enumerate(dset._package(dicts=False)): - for j, col in enumerate(row): - works.write(i, j, col) - - - stream = cStringIO.StringIO() - workb.save(stream) - return stream.getvalue() - - - @property - def json(self): - """Returns JSON representation of Databook.""" - - return json.dumps(self._package()) - - - @property - def yaml(self): - """Returns YAML representation of Databook.""" - - return yaml.dump(self._package()) - class InvalidDatasetType(Exception): From 63d025888aeaf61022524f09d520e4b29687bdc5 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:49:21 -0400 Subject: [PATCH 54/81] Added format importers. --- tablib/formats/__init__.py | 11 ++++++++++ tablib/formats/_csv.py | 41 +++++++++++++++++++++++++++++++++++++ tablib/formats/_json.py | 32 +++++++++++++++++++++++++++++ tablib/formats/_xls.py | 42 ++++++++++++++++++++++++++++++++++++++ tablib/formats/_yaml.py | 27 ++++++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 tablib/formats/__init__.py create mode 100644 tablib/formats/_csv.py create mode 100644 tablib/formats/_json.py create mode 100644 tablib/formats/_xls.py create mode 100644 tablib/formats/_yaml.py diff --git a/tablib/formats/__init__.py b/tablib/formats/__init__.py new file mode 100644 index 0000000..b9c7451 --- /dev/null +++ b/tablib/formats/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- + +""" Tablib - formats +""" + +import _csv as csv +import _json as json +import _xls as xls +import _yaml as yaml + +formats = (csv, json, xls, yaml) diff --git a/tablib/formats/_csv.py b/tablib/formats/_csv.py new file mode 100644 index 0000000..0554976 --- /dev/null +++ b/tablib/formats/_csv.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +import cStringIO +import csv +import os + +import simplejson as json + +import tablib + + +title = 'csv' +extentions = ('csv',) + + + +def export_set(dataset): + """Returns CSV representation of Dataset.""" + stream = cStringIO.StringIO() + _csv = csv.writer(stream) + + for row in dataset._package(dicts=False): + _csv.writerow(row) + + return stream.getvalue() + + +def import_set(in_stream, headers=True): + """Returns dataset from CSV stream.""" + + data = tablib.core.Dataset() + + rows = csv.reader(in_stream.split()) + for i, row in enumerate(rows): + + if (i == 1) and (headers): + data.headers = row + else: + data.append(row) + + return data \ No newline at end of file diff --git a/tablib/formats/_json.py b/tablib/formats/_json.py new file mode 100644 index 0000000..acbaf57 --- /dev/null +++ b/tablib/formats/_json.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import simplejson as json +import tablib.core + +title = 'json' +extentions = ('json', 'jsn') + + +def export_set(dataset): + """Returns JSON representation of Dataset.""" + return json.dumps(dataset.dict) + + +def export_book(databook): + """Returns JSON representation of Databook.""" + + return json.dumps(databook._package()) + + +def detect(contents): + """Return True if contets are JSON.""" + return False + + +def import_set(in_stream): + """Returns dataset from JSON stream.""" + data = tablib.core.Dataset() + data.dict = json.loads(in_stream) + + return data + diff --git a/tablib/formats/_xls.py b/tablib/formats/_xls.py new file mode 100644 index 0000000..67bd31c --- /dev/null +++ b/tablib/formats/_xls.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +import xlwt +import cStringIO + + +title = 'xls' +extentions = ('xls') + + +def export_set(dataset): + """Returns XLS representation of Dataset.""" + + wb = xlwt.Workbook(encoding='utf8') + ws = wb.add_sheet(dataset.title if dataset.title else 'Tabbed Dataset') + + for i, row in enumerate(dataset._package(dicts=False)): + for j, col in enumerate(row): + ws.write(i, j, col) + + stream = cStringIO.StringIO() + wb.save(stream) + return stream.getvalue() + + +def export_book(databook): + """Returns XLS representation of DataBook.""" + + wb = xlwt.Workbook(encoding='utf8') + + for i, dset in enumerate(databook._datasets): + ws = wb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i)) + + #for row in self._package(dicts=False): + for i, row in enumerate(dset._package(dicts=False)): + for j, col in enumerate(row): + ws.write(i, j, col) + + + stream = cStringIO.StringIO() + wb.save(stream) + return stream.getvalue() \ No newline at end of file diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py new file mode 100644 index 0000000..35c2bf2 --- /dev/null +++ b/tablib/formats/_yaml.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import yaml +import tablib + +title = 'yaml' +extentions = ('yaml', 'yml') + + + +def export_set(dataset): + """Returns YAML representation of Dataset.""" + return yaml.dump(dataset.dict) + + +def export_book(databook): + """Returns YAML representation of Databook.""" + return yaml.dump(databook._package()) + + +def import_set(in_stream): + """Returns dataset from YAML stream.""" + + data = tablib.core.Dataset() + data.dict = yaml.load(in_stream) + + return data \ No newline at end of file From cab63e02c873ffa86a4688342d35ae72ca321625 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:53:13 -0400 Subject: [PATCH 55/81] Module namespace change. --- tablib/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index 2c9811a..52a8faa 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -230,7 +230,7 @@ class Databook(object): @classmethod def _register_formats(cls): """Adds format properties.""" - for fmt in formats.formats: + for fmt in formats: try: setattr(cls, fmt.title, property(fmt.export_book)) except Exception, why: From 4c0c879d657b0d8c791135de8e5b8420bf410a96 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:53:19 -0400 Subject: [PATCH 56/81] Updated tests. --- test_tablib.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/test_tablib.py b/test_tablib.py index 959a01c..0f79a20 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -181,6 +181,45 @@ class TablibTestCase(unittest.TestCase): data.csv data.xls - + + def test_book_export_no_exceptions(self): + """Test that varoius exports don't error out.""" + + book = tablib.Databook() + book.add_sheet(data) + + book.json + book.yaml + book.xls + + + def test_json_import(self): + """Generate and import JSON serialization.""" + data.append(self.john) + new_data = tablib.formats.json.import_set(str(data.json)) + + new_data.headers = self.headers + new_data = tablib.formats.json.import_set(str(new_data.json)) + + def test_yaml_import(self): + """Generate and import YAML serialization.""" + data.append(self.john) + new_data = tablib.formats.yaml.import_set(str(data.json)) + + new_data.headers = self.headers + new_data = tablib.formats.yaml.import_set(str(new_data.json)) + + def test_csv_import(self): + """Generate and import CSV serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers +# new_data = tablib.formats.csv.import_set(str(data.csv)) + +# new_data.headers = self.headers + new_data = tablib.formats.csv.import_set(str(data.csv)) +# print new_data + + if __name__ == '__main__': unittest.main() From b1d282744cfcc20fd5fc7478e64832b6b484cdfb Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:57:42 -0400 Subject: [PATCH 57/81] Docstring updates. --- tablib/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tablib/core.py b/tablib/core.py index 52a8faa..bc1cbbf 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -246,6 +246,7 @@ class Databook(object): def _package(self): + """Packages Databook for delivery.""" collector = [] for dset in self._datasets: collector.append(dict( From 942dd3dadfc8de2956b1179b0d4ae608e68fc64c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:58:40 -0400 Subject: [PATCH 58/81] Added tablib core docstring placeholder. --- tablib/core.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index bc1cbbf..508d8c9 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -1,11 +1,7 @@ # -*- coding: utf-8 -*- -# _____ ______ ______ _________ -# __ /_______ ____ /_ ___ /_ _____ ______ / -# _ __/_ __ `/__ __ \__ __ \_ _ \_ __ / -# / /_ / /_/ / _ /_/ /_ /_/ // __// /_/ / -# \__/ \__,_/ /_.___/ /_.___/ \___/ \__,_/ - +""" Tablib - core. +""" import csv import cStringIO @@ -34,12 +30,12 @@ class Dataset(object): try: self.headers = kwargs['headers'] - except KeyError, why: + except KeyError: self.headers = None try: self.title = kwargs['title'] - except KeyError, why: + except KeyError: self.title = None self._register_formats() @@ -81,7 +77,7 @@ class Dataset(object): for fmt in formats: try: setattr(cls, fmt.title, property(fmt.export_set)) - except Exception, why: + except Exception: pass @@ -130,10 +126,10 @@ class Dataset(object): """Returns the width of the Dataset.""" try: return len(self._data[0]) - except IndexError, why: + except IndexError: try: return len(self.headers) - except TypeError, e: + except TypeError: return 0 @@ -150,7 +146,7 @@ class Dataset(object): if collection: try: self.__headers = list(collection) - except TypeError, why: + except TypeError: raise TypeError else: self.__headers = None @@ -233,7 +229,7 @@ class Databook(object): for fmt in formats: try: setattr(cls, fmt.title, property(fmt.export_book)) - except Exception, why: + except Exception: pass From 8d7e5732cd95c23cfa5947342312e7e519f8e311 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 05:59:02 -0400 Subject: [PATCH 59/81] Typo. --- tablib/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index 508d8c9..3f79a36 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -234,7 +234,7 @@ class Databook(object): def add_sheet(self, dataset): - """Add given dataset .""" + """Adds given dataset.""" if type(dataset) is Dataset: self._datasets.append(dataset) else: From 80cb42e8dd787a2ceffb37fe7a2380a97d000f4e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 06:20:34 -0400 Subject: [PATCH 60/81] Archaic imports in place! --- tablib/formats/_csv.py | 2 +- tablib/formats/_json.py | 21 ++++++++++++++------- tablib/formats/_yaml.py | 15 ++++++++++++++- test_tablib.py | 10 ++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/tablib/formats/_csv.py b/tablib/formats/_csv.py index 0554976..a66f2e0 100644 --- a/tablib/formats/_csv.py +++ b/tablib/formats/_csv.py @@ -33,7 +33,7 @@ def import_set(in_stream, headers=True): rows = csv.reader(in_stream.split()) for i, row in enumerate(rows): - if (i == 1) and (headers): + if (i == 0) and (headers): data.headers = row else: data.append(row) diff --git a/tablib/formats/_json.py b/tablib/formats/_json.py index acbaf57..18885c7 100644 --- a/tablib/formats/_json.py +++ b/tablib/formats/_json.py @@ -14,19 +14,26 @@ def export_set(dataset): def export_book(databook): """Returns JSON representation of Databook.""" - return json.dumps(databook._package()) - - -def detect(contents): - """Return True if contets are JSON.""" - return False - + def import_set(in_stream): """Returns dataset from JSON stream.""" + data = tablib.core.Dataset() data.dict = json.loads(in_stream) return data + +def import_book(in_stream): + """Returns databook from JSON stream.""" + + book = tablib.core.Databook() + for sheet in json.loads(in_stream): + data = tablib.core.Dataset() + data.title = sheet['title'] + data.dict = sheet['data'] + book.add_sheet(data) + + return book \ No newline at end of file diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py index 35c2bf2..d54e29a 100644 --- a/tablib/formats/_yaml.py +++ b/tablib/formats/_yaml.py @@ -24,4 +24,17 @@ def import_set(in_stream): data = tablib.core.Dataset() data.dict = yaml.load(in_stream) - return data \ No newline at end of file + return data + + +def import_book(in_stream): + """Returns databook from YAML stream.""" + + book = tablib.core.Databook() + for sheet in yaml.load(in_stream): + data = tablib.core.Dataset() + data.title = sheet['title'] + data.dict = sheet['data'] + book.add_sheet(data) + + return book \ No newline at end of file diff --git a/test_tablib.py b/test_tablib.py index 0f79a20..6758daa 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -200,6 +200,11 @@ class TablibTestCase(unittest.TestCase): new_data.headers = self.headers new_data = tablib.formats.json.import_set(str(new_data.json)) + + book = tablib.Databook() + book.add_sheet(new_data) + new_book = tablib.formats.json.import_book(str(book.json)) + def test_yaml_import(self): """Generate and import YAML serialization.""" @@ -208,6 +213,11 @@ class TablibTestCase(unittest.TestCase): new_data.headers = self.headers new_data = tablib.formats.yaml.import_set(str(new_data.json)) + + book = tablib.Databook() + book.add_sheet(new_data) + new_book = tablib.formats.yaml.import_book(str(book.yaml)) + def test_csv_import(self): """Generate and import CSV serialization.""" From a9c7a5067dffa9f5d67708941c0eefca7aa7c203 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 06:22:40 -0400 Subject: [PATCH 61/81] Added dataset wipe. --- tablib/core.py | 6 ++++++ test_tablib.py | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/tablib/core.py b/tablib/core.py index 3f79a36..e368bab 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -204,6 +204,12 @@ class Dataset(object): self._data.insert(i, tuple(row)) elif col: pass + + + def wipe(self): + """Erases all data from Dataset.""" + self._data = list() + self.__headers = None class Databook(object): diff --git a/test_tablib.py b/test_tablib.py index 6758daa..54ab6f3 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -230,6 +230,21 @@ class TablibTestCase(unittest.TestCase): new_data = tablib.formats.csv.import_set(str(data.csv)) # print new_data + 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) if __name__ == '__main__': unittest.main() From 4f035caf1b8bf9f6f0f594682651f55d192f5a68 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 10:40:59 -0400 Subject: [PATCH 62/81] Added dataset wipe. --- test_tablib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 54ab6f3..6b4efa8 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -224,9 +224,9 @@ class TablibTestCase(unittest.TestCase): data.append(self.john) data.append(self.george) data.headers = self.headers -# new_data = tablib.formats.csv.import_set(str(data.csv)) + new_data = tablib.formats.csv.import_set(str(data.csv)) -# new_data.headers = self.headers + new_data.headers = self.headers new_data = tablib.formats.csv.import_set(str(data.csv)) # print new_data From dfa26a7d53097c32283f2876be2e0b1ecf1b312f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 10:49:06 -0400 Subject: [PATCH 63/81] Typos. --- test_tablib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_tablib.py b/test_tablib.py index 6b4efa8..73f8efc 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -228,7 +228,7 @@ class TablibTestCase(unittest.TestCase): new_data.headers = self.headers new_data = tablib.formats.csv.import_set(str(data.csv)) -# print new_data + def test_wipe(self): """Purge a dataset.""" @@ -245,6 +245,7 @@ class TablibTestCase(unittest.TestCase): data.append(new_row) self.assertTrue(data.width == len(new_row)) self.assertTrue(data[0] == new_row) + if __name__ == '__main__': unittest.main() From 4117503ed5f2229c54df68bc9ab339f7ea7cb36d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:23:01 -0400 Subject: [PATCH 64/81] Elegant imports in place! --- tablib/core.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index e368bab..9500d20 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -76,8 +76,12 @@ class Dataset(object): """Adds format properties.""" for fmt in formats: try: - setattr(cls, fmt.title, property(fmt.export_set)) - except Exception: + try: + setattr(cls, fmt.title, property(fmt.export_set, fmt.import_set)) + except AttributeError: + setattr(cls, fmt.title, property(fmt.export_set)) + + except AttributeError: pass @@ -234,8 +238,12 @@ class Databook(object): """Adds format properties.""" for fmt in formats: try: - setattr(cls, fmt.title, property(fmt.export_book)) - except Exception: + try: + setattr(cls, fmt.title, property(fmt.export_book, fmt.import_book)) + except AttributeError: + setattr(cls, fmt.title, property(fmt.export_book)) + + except AttributeError: pass From 65836d5acea764584540082b45d8d58dac2bd52e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:24:16 -0400 Subject: [PATCH 65/81] Updated elegant imports for instance properties. Data wipes. --- tablib/formats/_csv.py | 10 ++++------ tablib/formats/_json.py | 8 +++----- tablib/formats/_xls.py | 2 +- tablib/formats/_yaml.py | 8 +++----- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tablib/formats/_csv.py b/tablib/formats/_csv.py index a66f2e0..6dba44b 100644 --- a/tablib/formats/_csv.py +++ b/tablib/formats/_csv.py @@ -25,17 +25,15 @@ def export_set(dataset): return stream.getvalue() -def import_set(in_stream, headers=True): +def import_set(dset, in_stream, headers=True): """Returns dataset from CSV stream.""" - data = tablib.core.Dataset() + dset.wipe() rows = csv.reader(in_stream.split()) for i, row in enumerate(rows): if (i == 0) and (headers): - data.headers = row + dset.headers = row else: - data.append(row) - - return data \ No newline at end of file + dset.append(row) diff --git a/tablib/formats/_json.py b/tablib/formats/_json.py index 18885c7..d60cd21 100644 --- a/tablib/formats/_json.py +++ b/tablib/formats/_json.py @@ -17,13 +17,11 @@ def export_book(databook): return json.dumps(databook._package()) -def import_set(in_stream): +def import_set(dset, in_stream): """Returns dataset from JSON stream.""" - data = tablib.core.Dataset() - data.dict = json.loads(in_stream) - - return data + dset.wipe() + dset.dict = json.loads(in_stream) def import_book(in_stream): diff --git a/tablib/formats/_xls.py b/tablib/formats/_xls.py index 67bd31c..979fa62 100644 --- a/tablib/formats/_xls.py +++ b/tablib/formats/_xls.py @@ -5,7 +5,7 @@ import cStringIO title = 'xls' -extentions = ('xls') +extentions = ('xls',) def export_set(dataset): diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py index d54e29a..6cec90c 100644 --- a/tablib/formats/_yaml.py +++ b/tablib/formats/_yaml.py @@ -18,13 +18,11 @@ def export_book(databook): return yaml.dump(databook._package()) -def import_set(in_stream): +def import_set(dset): """Returns dataset from YAML stream.""" - data = tablib.core.Dataset() - data.dict = yaml.load(in_stream) - - return data + dset.wipe() + dset.dict = yaml.load(in_stream) def import_book(in_stream): From 99154aa6d615555baef8cf850db780f6e93585d0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:24:59 -0400 Subject: [PATCH 66/81] Merge branches 'feature/import-seamless' and 'feature/imports' into feature/imports From 59ccc0b4224c383d55bbab8535c4e8e74cf46c99 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:39:09 -0400 Subject: [PATCH 67/81] YAML input support. --- tablib/formats/_yaml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py index 6cec90c..74d9155 100644 --- a/tablib/formats/_yaml.py +++ b/tablib/formats/_yaml.py @@ -18,7 +18,7 @@ def export_book(databook): return yaml.dump(databook._package()) -def import_set(dset): +def import_set(dset, in_stream): """Returns dataset from YAML stream.""" dset.wipe() From 7623bfe7b09817b3d64e234d630c225b5b3d0bba Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:40:05 -0400 Subject: [PATCH 68/81] Updated tests for set imports. --- test_tablib.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index 73f8efc..cb8549c 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -193,41 +193,43 @@ class TablibTestCase(unittest.TestCase): book.xls - def test_json_import(self): + def test_json_import_set(self): """Generate and import JSON serialization.""" data.append(self.john) - new_data = tablib.formats.json.import_set(str(data.json)) + data.append(self.george) + data.headers = self.headers - new_data.headers = self.headers - new_data = tablib.formats.json.import_set(str(new_data.json)) - - book = tablib.Databook() - book.add_sheet(new_data) - new_book = tablib.formats.json.import_book(str(book.json)) + _json = data.json + + data.json = _json + + self.assertEqual(_json, data.json) - def test_yaml_import(self): + def test_yaml_import_set(self): """Generate and import YAML serialization.""" data.append(self.john) - new_data = tablib.formats.yaml.import_set(str(data.json)) + data.append(self.george) + data.headers = self.headers - new_data.headers = self.headers - new_data = tablib.formats.yaml.import_set(str(new_data.json)) - - book = tablib.Databook() - book.add_sheet(new_data) - new_book = tablib.formats.yaml.import_book(str(book.yaml)) + _yaml = data.yaml + + data.yaml = _yaml + + self.assertEqual(_yaml, data.yaml) - def test_csv_import(self): + def test_csv_import_set(self): """Generate and import CSV serialization.""" data.append(self.john) data.append(self.george) data.headers = self.headers - new_data = tablib.formats.csv.import_set(str(data.csv)) - new_data.headers = self.headers - new_data = tablib.formats.csv.import_set(str(data.csv)) + _csv = data.csv + + data.csv = _csv + + self.assertEqual(_csv, data.csv) def test_wipe(self): From f1bdf43aab2e6c6a2641fd52086918e3fa0e5b42 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:50:06 -0400 Subject: [PATCH 69/81] Book wiper. --- tablib/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index 9500d20..849e4bc 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -232,7 +232,10 @@ class Databook(object): except AttributeError: return '' - + def wipe(self): + """Wipe book clean.""" + self._datasets = [] + @classmethod def _register_formats(cls): """Adds format properties.""" From a73bbe16450054e4238018a68f97319d1da60d8f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:56:20 -0400 Subject: [PATCH 70/81] Elegant databook importers. --- tablib/formats/_json.py | 8 +++----- tablib/formats/_yaml.py | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tablib/formats/_json.py b/tablib/formats/_json.py index d60cd21..c2dd524 100644 --- a/tablib/formats/_json.py +++ b/tablib/formats/_json.py @@ -24,14 +24,12 @@ def import_set(dset, in_stream): dset.dict = json.loads(in_stream) -def import_book(in_stream): +def import_book(dbook, in_stream): """Returns databook from JSON stream.""" - book = tablib.core.Databook() + dbook.wipe() for sheet in json.loads(in_stream): data = tablib.core.Dataset() data.title = sheet['title'] data.dict = sheet['data'] - book.add_sheet(data) - - return book \ No newline at end of file + dbook.add_sheet(data) diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py index 74d9155..665e06d 100644 --- a/tablib/formats/_yaml.py +++ b/tablib/formats/_yaml.py @@ -25,14 +25,13 @@ def import_set(dset, in_stream): dset.dict = yaml.load(in_stream) -def import_book(in_stream): +def import_book(dbook, in_stream): """Returns databook from YAML stream.""" - book = tablib.core.Databook() + dbook.wipe() + for sheet in yaml.load(in_stream): data = tablib.core.Dataset() data.title = sheet['title'] data.dict = sheet['data'] - book.add_sheet(data) - - return book \ No newline at end of file + dbook.add_sheet(data) \ No newline at end of file From b5f0cf9d374bceb57d5a5900a77ca0fa1930563a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 15:56:43 -0400 Subject: [PATCH 71/81] Tests elegant book imports. --- test_tablib.py | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/test_tablib.py b/test_tablib.py index cb8549c..67b693d 100755 --- a/test_tablib.py +++ b/test_tablib.py @@ -13,8 +13,10 @@ class TablibTestCase(unittest.TestCase): def setUp(self): """Create simple data set with headers.""" - global data + + global data, book data = tablib.Dataset() + book = tablib.Databook() self.headers = ('first_name', 'last_name', 'gpa') self.john = ('John', 'Adams', 90) @@ -194,7 +196,7 @@ class TablibTestCase(unittest.TestCase): def test_json_import_set(self): - """Generate and import JSON serialization.""" + """Generate and import JSON set serialization.""" data.append(self.john) data.append(self.george) data.headers = self.headers @@ -204,10 +206,24 @@ class TablibTestCase(unittest.TestCase): data.json = _json self.assertEqual(_json, data.json) - + + + 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, book.json) + def test_yaml_import_set(self): - """Generate and import YAML serialization.""" + """Generate and import YAML set serialization.""" data.append(self.john) data.append(self.george) data.headers = self.headers @@ -217,10 +233,24 @@ class TablibTestCase(unittest.TestCase): data.yaml = _yaml self.assertEqual(_yaml, data.yaml) + + + def test_yaml_import_book(self): + """Generate and import YAML book serialization.""" + data.append(self.john) + data.append(self.george) + data.headers = self.headers + + book.add_sheet(data) + _yaml = book.yaml + + book.yaml = _yaml + + self.assertEqual(_yaml, book.yaml) def test_csv_import_set(self): - """Generate and import CSV serialization.""" + """Generate and import CSV set serialization.""" data.append(self.john) data.append(self.george) data.headers = self.headers From 07ac723971152198a1a4367d5e15a58aa9977204 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:46:52 -0400 Subject: [PATCH 72/81] Readme update for imports. --- README.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 387a807..9eca8d0 100644 --- a/README.rst +++ b/README.rst @@ -15,12 +15,17 @@ Tablib is a format-agnostic tabular dataset library, written in Python. Output formats supported: -- Excel -- JSON -- YAML -- CSV +- Excel (Sets + Books) +- JSON (Sets + Books) +- YAML (Sets + Books) +- CSV (Sets) + +Import formats supported: + +- JSON (Sets + Books) +- YAML (Sets + Books) +- CSV (Sets) -At this time, Tablib supports the **export** of it's powerful Dataset object instances into any of the above formats. Import is underway. Note that tablib *purposefully* excludes XML support. It always will. From d5515c17b80a4f8cf030b014eff331e1a2fb0538 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:47:04 -0400 Subject: [PATCH 73/81] Removed useless imports. --- tablib/core.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 849e4bc..fb9861a 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -3,13 +3,6 @@ """ Tablib - core. """ -import csv -import cStringIO - -import simplejson as json -import xlwt -import yaml - from tablib.formats import formats From 7505d8d985459f4050a9cd720f0a9b8fb516e639 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:49:21 -0400 Subject: [PATCH 74/81] Adding docstrings for pylint coverage. --- tablib/core.py | 2 +- tablib/formats/_csv.py | 3 +++ tablib/formats/_json.py | 3 +++ tablib/formats/_xls.py | 3 +++ tablib/formats/_yaml.py | 5 +++++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tablib/core.py b/tablib/core.py index fb9861a..168d664 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -""" Tablib - core. +""" Tablib - Core Library. """ from tablib.formats import formats diff --git a/tablib/formats/_csv.py b/tablib/formats/_csv.py index 6dba44b..8b19da7 100644 --- a/tablib/formats/_csv.py +++ b/tablib/formats/_csv.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +""" Tablib - CSV Support. +""" + import cStringIO import csv import os diff --git a/tablib/formats/_json.py b/tablib/formats/_json.py index c2dd524..1f92b58 100644 --- a/tablib/formats/_json.py +++ b/tablib/formats/_json.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +""" Tablib - JSON Support +""" + import simplejson as json import tablib.core diff --git a/tablib/formats/_xls.py b/tablib/formats/_xls.py index 979fa62..1a739af 100644 --- a/tablib/formats/_xls.py +++ b/tablib/formats/_xls.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +""" Tablib - XLS Support. +""" + import xlwt import cStringIO diff --git a/tablib/formats/_yaml.py b/tablib/formats/_yaml.py index 665e06d..4cac8aa 100644 --- a/tablib/formats/_yaml.py +++ b/tablib/formats/_yaml.py @@ -1,8 +1,13 @@ # -*- coding: utf-8 -*- +""" Tablib - YAML Support. +""" + import yaml import tablib + + title = 'yaml' extentions = ('yaml', 'yml') From 66867527d2d3da934b62efb65f1c587b037566f6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:51:09 -0400 Subject: [PATCH 75/81] Format import cleanups. --- tablib/core.py | 2 +- tablib/formats/__init__.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tablib/core.py b/tablib/core.py index 168d664..b557e3e 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -3,7 +3,7 @@ """ Tablib - Core Library. """ -from tablib.formats import formats +from tablib.formats import FORMATS as formats __title__ = 'tablib' diff --git a/tablib/formats/__init__.py b/tablib/formats/__init__.py index b9c7451..e8c9007 100644 --- a/tablib/formats/__init__.py +++ b/tablib/formats/__init__.py @@ -3,9 +3,9 @@ """ Tablib - formats """ -import _csv as csv -import _json as json -import _xls as xls -import _yaml as yaml +import tablib.formats._csv as csv +import tablib.formats._json as json +import tablib.formats._xls as xls +import tablib.formats._yaml as yaml -formats = (csv, json, xls, yaml) +FORMATS = (csv, json, xls, yaml) From 86d84b555dbc531f8c941e8481803d48b0d55448 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:53:33 -0400 Subject: [PATCH 76/81] Import cleanup. --- tablib/formats/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tablib/formats/__init__.py b/tablib/formats/__init__.py index e8c9007..b22a959 100644 --- a/tablib/formats/__init__.py +++ b/tablib/formats/__init__.py @@ -3,9 +3,9 @@ """ Tablib - formats """ -import tablib.formats._csv as csv -import tablib.formats._json as json -import tablib.formats._xls as xls -import tablib.formats._yaml as yaml +import _csv as csv +import _json as json +import _xls as xls +import _yaml as yaml FORMATS = (csv, json, xls, yaml) From 969d9d957d73e942220200a2786f761f2791d51d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 16:59:27 -0400 Subject: [PATCH 77/81] Version Bump (to v0.8.0) --- setup.py | 2 +- tablib/core.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index dc8142b..0c95cb4 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.7.1', + version='0.8.0', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), diff --git a/tablib/core.py b/tablib/core.py index b557e3e..cdaf0d5 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -7,8 +7,8 @@ from tablib.formats import FORMATS as formats __title__ = 'tablib' -__version__ = '0.7.1' -__build__ = 0x000701 +__version__ = '0.8.0' +__build__ = 0x000800 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' From f8899106297606d391fcdfa1a75c276bc7ed272d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 17:12:50 -0400 Subject: [PATCH 78/81] Big documentation update. --- README.rst | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 9eca8d0..df59abb 100644 --- a/README.rst +++ b/README.rst @@ -26,9 +26,16 @@ Import formats supported: - YAML (Sets + Books) - CSV (Sets) - Note that tablib *purposefully* excludes XML support. It always will. +Overview +-------- + +`tablib.Dataset()` + A Dataset is a table of tabular data. It may or may not have a header row. They can be build and maniuplated as raw Python datatypes (Lists of tuples|dictonaries). Datasets can be imported from JSON, YAML, and CSV; they can be exported to Excel (XLS), JSON, YAML, and CSV. + +`tablib.Databook()` + A Databook is a set of Datasets. The most common form of a Databook is an Excel file with multiple spreadsheets. Databooks can be imported from JSON and YAML; they can be exported to Excel (XLS), JSON, and YAML. Usage ----- @@ -69,6 +76,9 @@ Easily delete rows: :: >>> del data[1] +Exports +------- + Drumroll please........... JSON! @@ -114,8 +124,41 @@ EXCEL! >>> open('people.xls', 'wb').write(data.xls) It's that easy. + +Imports! +-------- + +JSON +++++ + +:: + + >>> data.json = '[{"last_name": "Adams","age": 90,"first_name": "John"}]' + >>> print data[0] + ('John', 'Adams', 90) + + +YAML +++++ +:: + + >>> data.yaml = '- {age: 90, first_name: John, last_name: Adams}' + >>> print data[0] + ('John', 'Adams', 90) + +CSV ++++ +:: + + >>> data.yaml = 'age, first_name, last_name\n90, John, Adams' + >>> print data[0] + ('John', 'Adams', 90) - + >>> print data.yaml + - {age: 90, first_name: John, last_name: Adams} + + + Installation ------------ @@ -136,13 +179,10 @@ If you'd like to contribute, simply fork `the repository`_, commit your changes Roadmap ------- -- Import datasets from CSV. - Release CLI Interface - Auto-detect import format - Add possible other exports (SQL?) -- Possibly plugin-ify format architecture - Ability to assign types to rows (set, regex=, &c.) -- Plugin support .. _`the repository`: http://github.com/kennethreitz/tablib .. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS From 8136f4b09eac5ed160fd49ec70f2c1338df6ec8d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 25 Sep 2010 17:18:48 -0400 Subject: [PATCH 79/81] Updated history for v0.8.0. --- HISTORY.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index d4b58d4..06d8257 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,13 @@ History ======= +0.8.0 (2010-09-25) +------------------ +* New format plugin system! +* Imports! ELEGANT Imports! +* Tests. Lots of tests. + + 0.7.1 (2010-09-20) ------------------ From 5ba92b0f6b09ec96e20377ff8925d7b4cfae48e1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 28 Sep 2010 08:37:32 -0400 Subject: [PATCH 80/81] Packaging fix. Version bump. --- HISTORY.rst | 5 +++++ setup.py | 4 ++-- tablib/core.py | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 06d8257..9f86fe2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,11 @@ History ======= +0.8.1 (2010-09-28) +------------------ +* Packaging Fix + + 0.8.0 (2010-09-25) ------------------ * New format plugin system! diff --git a/setup.py b/setup.py index 0c95cb4..13ad1e8 100644 --- a/setup.py +++ b/setup.py @@ -17,14 +17,14 @@ if sys.argv[-1] == "publish": setup( name='tablib', - version='0.8.0', + version='0.8.1', description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)', long_description=open('README.rst').read() + '\n\n' + open('HISTORY.rst').read(), author='Kenneth Reitz', author_email='me@kennethreitz.com', url='http://github.com/kennethreitz/tablib', - packages=['tablib'], + packages=['tablib'm 'tablib.formats'], install_requires=['xlwt', 'simplejson', 'PyYAML'], license='MIT', classifiers=( diff --git a/tablib/core.py b/tablib/core.py index cdaf0d5..ddb9769 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -7,8 +7,8 @@ from tablib.formats import FORMATS as formats __title__ = 'tablib' -__version__ = '0.8.0' -__build__ = 0x000800 +__version__ = '0.8.1' +__build__ = 0x000801 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2010 Kenneth Reitz' From 6407afba3eedaf27c2614a362f0842470a8f4fae Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 28 Sep 2010 08:46:31 -0400 Subject: [PATCH 81/81] typo fix. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 13ad1e8..920c148 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ setup( author='Kenneth Reitz', author_email='me@kennethreitz.com', url='http://github.com/kennethreitz/tablib', - packages=['tablib'm 'tablib.formats'], + packages=['tablib', 'tablib.formats'], install_requires=['xlwt', 'simplejson', 'PyYAML'], license='MIT', classifiers=(