summaryrefslogtreecommitdiff
path: root/tablib/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'tablib/core.py')
-rw-r--r--tablib/core.py80
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."