mirror of
https://github.com/kennethreitz/tablib.git
synced 2026-06-05 23:10:17 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f913853cae | |||
| ea1de420a3 | |||
| d0c8df95a3 | |||
| bb4e97f8aa | |||
| ffaeb64639 | |||
| f31ec562b4 | |||
| 68d7204b2d | |||
| a0cb44cc43 | |||
| b2cd061773 | |||
| 876b849950 |
+10
-5
@@ -31,11 +31,11 @@ Usage
|
|||||||
|
|
||||||
Populate fresh data files: ::
|
Populate fresh data files: ::
|
||||||
|
|
||||||
headers = ('first_name', 'last_name', 'gpa')
|
headers = ('first_name', 'last_name')
|
||||||
|
|
||||||
data = [
|
data = [
|
||||||
('John', 'Adams', 90),
|
('John', 'Adams'),
|
||||||
('George', 'Washington', 67)
|
('George', 'Washington')
|
||||||
]
|
]
|
||||||
|
|
||||||
data = tablib.Dataset(*data, headers=headers)
|
data = tablib.Dataset(*data, headers=headers)
|
||||||
@@ -43,7 +43,11 @@ Populate fresh data files: ::
|
|||||||
|
|
||||||
Intelligently add new rows: ::
|
Intelligently add new rows: ::
|
||||||
|
|
||||||
>>> data.append(('Henry', 'Ford', 83))
|
>>> data.append(('Henry', 'Ford'))
|
||||||
|
|
||||||
|
Intelligently add new columns: ::
|
||||||
|
|
||||||
|
>>> data.append(col=('age', 90, 67, 83))
|
||||||
|
|
||||||
Slice rows: ::
|
Slice rows: ::
|
||||||
|
|
||||||
@@ -122,7 +126,7 @@ Or, if you absolutely must: ::
|
|||||||
Contribute
|
Contribute
|
||||||
----------
|
----------
|
||||||
|
|
||||||
If you'd like to contribute, simply fork `the repository`_, commit your changes, and send a pull request. Make sure you add yourself to AUTHORS_.
|
If you'd like to contribute, simply fork `the repository`_, commit your changes to the **develop** branch (or branch off of it), and send a pull request. Make sure you add yourself to AUTHORS_.
|
||||||
|
|
||||||
|
|
||||||
Roadmap
|
Roadmap
|
||||||
@@ -133,6 +137,7 @@ Roadmap
|
|||||||
- Auto-detect import format
|
- Auto-detect import format
|
||||||
- Add possible other exports (SQL?)
|
- Add possible other exports (SQL?)
|
||||||
- Possibly plugin-ify format architecture
|
- Possibly plugin-ify format architecture
|
||||||
|
- Ability to assign types to rows (set, regex=, &c.)
|
||||||
- Plugin support
|
- Plugin support
|
||||||
|
|
||||||
.. _`the repository`: http://github.com/kennethreitz/tablib
|
.. _`the repository`: http://github.com/kennethreitz/tablib
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ if sys.argv[-1] == "publish":
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='tablib',
|
name='tablib',
|
||||||
version='0.6.2',
|
version='0.6.3',
|
||||||
description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)',
|
description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)',
|
||||||
long_description=open('README.rst').read() + '\n\n' +
|
long_description=open('README.rst').read() + '\n\n' +
|
||||||
open('HISTORY.rst').read(),
|
open('HISTORY.rst').read(),
|
||||||
|
|||||||
+58
-14
@@ -21,8 +21,8 @@ from helpers import *
|
|||||||
# __all__ = ['Dataset', 'DataBook']
|
# __all__ = ['Dataset', 'DataBook']
|
||||||
|
|
||||||
__name__ = 'tablib'
|
__name__ = 'tablib'
|
||||||
__version__ = '0.6.1'
|
__version__ = '0.6.3'
|
||||||
__build__ = 0x000601
|
__build__ = 0x000603
|
||||||
__author__ = 'Kenneth Reitz'
|
__author__ = 'Kenneth Reitz'
|
||||||
__license__ = 'MIT'
|
__license__ = 'MIT'
|
||||||
__copyright__ = 'Copyright 2010 Kenneth Reitz'
|
__copyright__ = 'Copyright 2010 Kenneth Reitz'
|
||||||
@@ -80,10 +80,15 @@ class Dataset(object):
|
|||||||
return '<dataset object>'
|
return '<dataset object>'
|
||||||
|
|
||||||
|
|
||||||
def _validate(self, row=None, safety=False):
|
def _validate(self, row=None, col=None, safety=False):
|
||||||
"""Assures size of every row in dataset is of proper proportions."""
|
"""Assures size of every row in dataset is of proper proportions."""
|
||||||
if row:
|
if row:
|
||||||
is_valid = (len(row) == self.width) if self.width else True
|
is_valid = (len(row) == self.width) if self.width else True
|
||||||
|
elif col:
|
||||||
|
if self.headers:
|
||||||
|
is_valid = (len(col) - 1) == self.height
|
||||||
|
else:
|
||||||
|
is_valid = (len(col) == self.height) if self.height else True
|
||||||
else:
|
else:
|
||||||
is_valid = all((len(x)== self.width for x in self._data))
|
is_valid = all((len(x)== self.width for x in self._data))
|
||||||
|
|
||||||
@@ -130,17 +135,27 @@ class Dataset(object):
|
|||||||
"""Headers property."""
|
"""Headers property."""
|
||||||
return self.__headers
|
return self.__headers
|
||||||
|
|
||||||
|
|
||||||
@headers.setter
|
@headers.setter
|
||||||
def headers(self, collection):
|
def headers(self, collection):
|
||||||
"""Validating headers setter."""
|
"""Validating headers setter."""
|
||||||
self._validate(collection)
|
self._validate(collection)
|
||||||
self.__headers = collection
|
if collection:
|
||||||
|
try:
|
||||||
|
self.__headers = list(collection)
|
||||||
|
except TypeError, why:
|
||||||
|
raise TypeError
|
||||||
|
else:
|
||||||
|
self.__headers = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dict(self):
|
def dict(self):
|
||||||
"""Returns python dict of Dataset."""
|
"""Returns python dict of Dataset."""
|
||||||
return self._package()
|
return self._package()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
"""Returns JSON representation of Dataset."""
|
"""Returns JSON representation of Dataset."""
|
||||||
@@ -180,16 +195,36 @@ class Dataset(object):
|
|||||||
return stream.getvalue()
|
return stream.getvalue()
|
||||||
|
|
||||||
|
|
||||||
def append(self, row):
|
def append(self, row=None, col=None):
|
||||||
"""Adds a row to the end of Dataset"""
|
"""Adds a row to the end of Dataset"""
|
||||||
self._validate(row)
|
if row:
|
||||||
self._data.append(tuple(row))
|
self._validate(row)
|
||||||
|
self._data.append(tuple(row))
|
||||||
|
elif col:
|
||||||
|
self._validate(col=col)
|
||||||
|
|
||||||
|
if self.headers:
|
||||||
|
# pop the first item off, add to headers
|
||||||
|
self.headers.append(col[0])
|
||||||
|
col = col[1:]
|
||||||
|
|
||||||
|
if self.height and self.width:
|
||||||
|
|
||||||
|
for i, row in enumerate(self._data):
|
||||||
|
_row = list(row)
|
||||||
|
_row.append(col[i])
|
||||||
|
self._data[i] = tuple(_row)
|
||||||
|
else:
|
||||||
|
self._data = [tuple([row]) for row in col]
|
||||||
|
|
||||||
|
|
||||||
def index(self, i, row):
|
def insert(self, i, row=None, col=None):
|
||||||
"""Inserts a row at given position in Dataset"""
|
"""Inserts a row at given position in Dataset"""
|
||||||
self._validate(row)
|
if row:
|
||||||
self._data.insert(i, tuple(row))
|
self._validate(row)
|
||||||
|
self._data.insert(i, tuple(row))
|
||||||
|
elif col:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DataBook(object):
|
class DataBook(object):
|
||||||
@@ -200,12 +235,14 @@ class DataBook(object):
|
|||||||
def __init__(self, sets=[]):
|
def __init__(self, sets=[]):
|
||||||
self._datasets = sets
|
self._datasets = sets
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
try:
|
try:
|
||||||
return '<%s databook>' % (self.title.lower())
|
return '<%s databook>' % (self.title.lower())
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return '<databook object>'
|
return '<databook object>'
|
||||||
|
|
||||||
|
|
||||||
def add_sheet(self, dataset):
|
def add_sheet(self, dataset):
|
||||||
"""Add given dataset ."""
|
"""Add given dataset ."""
|
||||||
if type(dataset) is Dataset:
|
if type(dataset) is Dataset:
|
||||||
@@ -213,6 +250,7 @@ class DataBook(object):
|
|||||||
else:
|
else:
|
||||||
raise InvalidDatasetType
|
raise InvalidDatasetType
|
||||||
|
|
||||||
|
|
||||||
def _package(self):
|
def _package(self):
|
||||||
collector = []
|
collector = []
|
||||||
for dset in self._datasets:
|
for dset in self._datasets:
|
||||||
@@ -222,6 +260,7 @@ class DataBook(object):
|
|||||||
))
|
))
|
||||||
return collector
|
return collector
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
"""The number of the Datasets within DataBook."""
|
"""The number of the Datasets within DataBook."""
|
||||||
@@ -235,8 +274,8 @@ class DataBook(object):
|
|||||||
stream = cStringIO.StringIO()
|
stream = cStringIO.StringIO()
|
||||||
wb = xlwt.Workbook()
|
wb = xlwt.Workbook()
|
||||||
|
|
||||||
for dset in self._datasets:
|
for i, dset in enumerate(self._datasets):
|
||||||
ws = wb.add_sheet(dset.title if dset.title else 'Tabbed Dataset %s' % (int(random.random() * 100000000)))
|
ws = wb.add_sheet(dset.title if dset.title else 'Sheet%s' % (i))
|
||||||
|
|
||||||
#for row in self._package(dicts=False):
|
#for row in self._package(dicts=False):
|
||||||
for i, row in enumerate(dset._package(dicts=False)):
|
for i, row in enumerate(dset._package(dicts=False)):
|
||||||
@@ -246,24 +285,29 @@ class DataBook(object):
|
|||||||
wb.save(stream)
|
wb.save(stream)
|
||||||
return stream.getvalue()
|
return stream.getvalue()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
"""Returns JSON representation of Databook."""
|
"""Returns JSON representation of Databook."""
|
||||||
|
|
||||||
return json.dumps(self._package())
|
return json.dumps(self._package())
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def yaml(self):
|
def yaml(self):
|
||||||
"""Returns YAML representation of Databook."""
|
"""Returns YAML representation of Databook."""
|
||||||
|
|
||||||
return yaml.dump(self._package())
|
return yaml.dump(self._package())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidDatasetType(Exception):
|
class InvalidDatasetType(Exception):
|
||||||
"Only Datasets can be added to a DataBook"
|
"Only Datasets can be added to a DataBook"
|
||||||
|
|
||||||
|
|
||||||
class InvalidDimensions(Exception):
|
class InvalidDimensions(Exception):
|
||||||
"Invalid size"
|
"Invalid size"
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedFormat(NotImplementedError):
|
class UnsupportedFormat(NotImplementedError):
|
||||||
"Format is not supported"
|
"Format is not supported"
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ class Struct(object):
|
|||||||
self.__dict__.update(entries)
|
self.__dict__.update(entries)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return getattr(self, key)
|
return getattr(self, key, None)
|
||||||
|
|
||||||
|
|
||||||
def piped():
|
def piped():
|
||||||
|
|||||||
+55
-8
@@ -7,15 +7,14 @@ import tablib
|
|||||||
|
|
||||||
class TablibTestCase(unittest.TestCase):
|
class TablibTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
global data
|
||||||
|
data = tablib.Dataset()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_empty_append(self):
|
def test_empty_append(self):
|
||||||
|
|
||||||
data = tablib.Dataset()
|
|
||||||
|
|
||||||
new_row = (1,2,3)
|
new_row = (1,2,3)
|
||||||
data.append(new_row)
|
data.append(new_row)
|
||||||
|
|
||||||
@@ -24,17 +23,65 @@ class TablibTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def test_empty_append_with_headers(self):
|
def test_empty_append_with_headers(self):
|
||||||
|
|
||||||
data = tablib.Dataset()
|
|
||||||
|
|
||||||
data.headers = ['first', 'second']
|
data.headers = ['first', 'second']
|
||||||
new_row = (1,2,3,4)
|
new_row = (1,2,3,4)
|
||||||
|
|
||||||
self.assertRaises(tablib.InvalidDimensions, data.append, new_row)
|
self.assertRaises(tablib.InvalidDimensions, data.append, new_row)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_column(self):
|
||||||
|
# No Headers
|
||||||
|
|
||||||
|
data.append(['kenneth'])
|
||||||
|
data.append(['bessie'])
|
||||||
|
|
||||||
|
new_col = ['reitz', 'monke']
|
||||||
|
|
||||||
|
data.append(col=new_col)
|
||||||
|
|
||||||
|
self.assertEquals(data[0], ('kenneth', 'reitz'))
|
||||||
|
self.assertEquals(data.width, 2)
|
||||||
|
|
||||||
|
# With Headers
|
||||||
|
data.headers = ('fname', 'lname')
|
||||||
|
new_col = ['age', 21, 22]
|
||||||
|
data.append(col=new_col)
|
||||||
|
|
||||||
|
self.assertEquals(data[new_col[0]], new_col[1:])
|
||||||
|
|
||||||
# def test_adding_header with (self):
|
|
||||||
|
|
||||||
|
def test_add_column_no_data_no_headers(self):
|
||||||
|
|
||||||
|
# no headers
|
||||||
|
|
||||||
|
new_col = ('reitz', 'monke')
|
||||||
|
|
||||||
|
data.append(col=new_col)
|
||||||
|
|
||||||
|
self.assertEquals(data[0], tuple([new_col[0]]))
|
||||||
|
self.assertEquals(data.width, 1)
|
||||||
|
self.assertEquals(data.height, len(new_col))
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_column_no_data_with_headers(self):
|
||||||
|
|
||||||
|
# no headers
|
||||||
|
|
||||||
|
data.headers = ('first', 'last')
|
||||||
|
|
||||||
|
new_col = ('age',)
|
||||||
|
data.append(col=new_col)
|
||||||
|
|
||||||
|
self.assertEquals(len(data.headers), 3)
|
||||||
|
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))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
Reference in New Issue
Block a user