diff options
Diffstat (limited to 'tablib/core.py')
| -rw-r--r-- | tablib/core.py | 80 |
1 files changed, 65 insertions, 15 deletions
diff --git a/tablib/core.py b/tablib/core.py index dfbcb6a..8ef6312 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -13,6 +13,7 @@ from copy import copy from operator import itemgetter from tablib import formats +import collections try: from collections import OrderedDict @@ -26,6 +27,7 @@ __build__ = 0x000904 __author__ = 'Kenneth Reitz' __license__ = 'MIT' __copyright__ = 'Copyright 2011 Kenneth Reitz' +__docformat__ = 'restructuredtext' class Row(object): @@ -62,7 +64,7 @@ class Row(object): return {slot: [getattr(self, slot) for slot in self.__slots__]} def __setstate__(self, state): - for (k, v) in state.items(): setattr(self, k, v) + for (k, v) in list(state.items()): setattr(self, k, v) def append(self, value): self._row.append(value) @@ -88,7 +90,7 @@ class Row(object): if tag == None: return False - elif isinstance(tag, basestring): + elif isinstance(tag, str): return (tag in self.tags) else: return bool(len(set(tag) & set(self.tags))) @@ -136,6 +138,9 @@ class Dataset(object): # ('title', index) tuples self._separators = [] + + # (column, callback) tuples + self._formatters = [] try: self.headers = kwargs['headers'] @@ -155,7 +160,7 @@ class Dataset(object): def __getitem__(self, key): - if isinstance(key, basestring): + if isinstance(key, str): if key in self.headers: pos = self.headers.index(key) # get 'key' index from each data return [row[pos] for row in self._data] @@ -175,7 +180,7 @@ class Dataset(object): def __delitem__(self, key): - if isinstance(key, basestring): + if isinstance(key, str): if key in self.headers: @@ -236,13 +241,29 @@ class Dataset(object): def _package(self, dicts=True): """Packages Dataset into lists of dictionaries for transmission.""" + _data = list(self._data) + + # Execute formatters + if self._formatters: + for row_i, row in enumerate(_data): + for col, callback in self._formatters: + try: + if col is None: + for j, c in enumerate(row): + _data[row_i][j] = callback(c) + else: + _data[row_i][col] = callback(row[col]) + except IndexError: + raise InvalidDatasetIndex + + if self.headers: if dicts: - data = [OrderedDict(zip(self.headers, data_row)) for data_row in self ._data] + data = [OrderedDict(list(zip(self.headers, data_row))) for data_row in _data] else: - data = [list(self.headers)] + list(self._data) + data = [list(self.headers)] + list(_data) else: - data = [list(row) for row in self._data] + data = [list(row) for row in _data] return data @@ -257,8 +278,8 @@ class Dataset(object): else: header = [] - if len(col) == 1 and callable(col[0]): - col = map(col[0], self._data) + if len(col) == 1 and isinstance(col[0], collections.Callable): + col = list(map(col[0], self._data)) col = tuple(header + col) return col @@ -347,9 +368,9 @@ class Dataset(object): # if list of objects elif isinstance(pickle[0], dict): self.wipe() - self.headers = pickle[0].keys() + self.headers = list(pickle[0].keys()) for row in pickle: - self.append(Row(row.values())) + self.append(Row(list(row.values()))) else: raise UnsupportedFormat @@ -385,6 +406,7 @@ class Dataset(object): """ pass + @property def tsv(): """A TSV representation of the :class:`Dataset` object. The top row will contain @@ -469,6 +491,29 @@ class Dataset(object): self.insert_separator(index, text) + def add_formatter(self, col, handler): + """Adds a :ref:`formatter` to the :class:`Dataset`. + + .. versionadded:: 0.9.5 + :param col: column to. Accepts index int or header str. + :param handler: reference to callback function to execute + against each cell value. + """ + + if isinstance(col, str): + if col in self.headers: + col = self.headers.index(col) # get 'key' index from each data + else: + raise KeyError + + if not col > self.width: + self._formatters.append((col, handler)) + else: + raise InvalidDatasetIndex + + return True + + def insert(self, index, row=None, col=None, header=None, tags=list()): """Inserts a row or column to the :class:`Dataset` at the given index. @@ -504,8 +549,8 @@ class Dataset(object): col = list(col) # Callable Columns... - if len(col) == 1 and callable(col[0]): - col = map(col[0], self._data) + if len(col) == 1 and isinstance(col[0], collections.Callable): + col = list(map(col[0], self._data)) col = self._clean_col(col) self._validate(col=col) @@ -543,7 +588,7 @@ class Dataset(object): Returns a new :class:`Dataset` instance where columns have been sorted.""" - if isinstance(col, basestring): + if isinstance(col, str): if not self.headers: raise HeadersNeeded @@ -658,12 +703,14 @@ class Dataset(object): return _dset + def wipe(self): """Removes all content and headers from the :class:`Dataset` object.""" self._data = list() self.__headers = None + class Databook(object): """A book of :class:`Dataset` objects. """ @@ -748,7 +795,7 @@ def import_set(stream): format.import_set(data, stream) return data - except AttributeError, e: + except AttributeError as e: return None @@ -758,6 +805,9 @@ class InvalidDatasetType(Exception): class InvalidDimensions(Exception): "Invalid size" + +class InvalidDatasetIndex(Exception): + "Outside of Dataset size" class HeadersNeeded(Exception): "Header parameter must be given when appending a column in this Dataset." |
