diff options
| author | Kenneth Reitz <me@kennethreitz.com> | 2011-06-21 19:42:56 -0400 |
|---|---|---|
| committer | Kenneth Reitz <me@kennethreitz.com> | 2011-06-21 19:42:56 -0400 |
| commit | 004b3da680b821d0dcedbe52ee6fb5a2a45c9ad5 (patch) | |
| tree | 20065c575a7349e0806a21f3312973eb975338f5 /tablib | |
| parent | d4923533eb3091cd4dddbe74cbddf50b158f74fe (diff) | |
| download | tablib-004b3da680b821d0dcedbe52ee6fb5a2a45c9ad5.tar.gz | |
Major API Changes
Related #21
Diffstat (limited to 'tablib')
| -rw-r--r-- | tablib/core.py | 308 |
1 files changed, 198 insertions, 110 deletions
diff --git a/tablib/core.py b/tablib/core.py index 16b3dff..9c561fd 100644 --- a/tablib/core.py +++ b/tablib/core.py @@ -62,8 +62,14 @@ class Row(object): def __setstate__(self, state): for (k, v) in list(state.items()): setattr(self, k, v) + def rpush(self, value): + self.insert(0, value) + + def lpush(self, value): + self.insert(len(value), value) + def append(self, value): - self._row.append(value) + self.rpush(value) def insert(self, index, value): self._row.insert(index, value) @@ -200,6 +206,10 @@ class Dataset(object): return '<dataset object>' + # --------- + # Internals + # --------- + @classmethod def _register_formats(cls): """Adds format properties.""" @@ -236,6 +246,7 @@ class Dataset(object): def _package(self, dicts=True, ordered=True): """Packages Dataset into lists of dictionaries for transmission.""" + # TODO: Dicts default to false? _data = list(self._data) @@ -269,46 +280,6 @@ class Dataset(object): return data - def _clean_col(self, col): - """Prepares the given column for insert/append.""" - - col = list(col) - - if self.headers: - header = [col.pop(0)] - else: - header = [] - - if len(col) == 1 and hasattr(col[0], '__call__'): - - col = list(map(col[0], self._data)) - col = tuple(header + col) - - return col - - - @property - def height(self): - """The number of rows currently in the :class:`Dataset`. - Cannot be directly modified. - """ - return len(self._data) - - - @property - def width(self): - """The number of columns currently in the :class:`Dataset`. - Cannot be directly modified. - """ - - try: - return len(self._data[0]) - except IndexError: - try: - return len(self.headers) - except TypeError: - return 0 - def _get_headers(self): """An *optional* list of strings to be used for header rows and attribute names. @@ -332,6 +303,7 @@ class Dataset(object): headers = property(_get_headers, _set_headers) + def _get_dict(self): """A native Python representation of the :class:`Dataset` object. If headers have been set, a list of Python dictionaries will be returned. If no headers have been set, @@ -379,6 +351,52 @@ class Dataset(object): dict = property(_get_dict, _set_dict) + def _clean_col(self, col): + """Prepares the given column for insert/append.""" + + col = list(col) + + if self.headers: + header = [col.pop(0)] + else: + header = [] + + if len(col) == 1 and hasattr(col[0], '__call__'): + + col = list(map(col[0], self._data)) + col = tuple(header + col) + + return col + + + @property + def height(self): + """The number of rows currently in the :class:`Dataset`. + Cannot be directly modified. + """ + return len(self._data) + + + @property + def width(self): + """The number of columns currently in the :class:`Dataset`. + Cannot be directly modified. + """ + + try: + return len(self._data[0]) + except IndexError: + try: + return len(self.headers) + except TypeError: + return 0 + + + # ------- + # Formats + # ------- + + @property def xls(): """A Legacy Excel Spreadsheet representation of the :class:`Dataset` object, with :ref:`separators`. Cannot be set. @@ -493,15 +511,128 @@ class Dataset(object): pass - def append(self, row=None, col=None, header=None, tags=list()): - """Adds a row or column to the :class:`Dataset`. - Usage is :class:`Dataset.insert` for documentation. + # ---- + # Rows + # ---- + + def insert(self, index, row, tags=list()): + """Inserts a row to the :class:`Dataset` at the given index. + + Rows and columns inserted must be the correct size (height or width). + + The default behaviour is to insert the given row to the :class:`Dataset` + object at the given index. If the ``col`` parameter is given, however, + a new column will be insert to the :class:`Dataset` object instead. + + You can also insert a column of a single callable object, which will + add a new column with the return values of the callable each as an + item in the column. :: + + data.append(col=random.randint) + + See :ref:`dyncols` for an in-depth example. + + .. versionchanged:: 0.9.0 + If inserting a column, and :class:`Dataset.headers` is set, the + header attribute must be set, and will be considered the header for + that row. + + .. versionadded:: 0.9.0 + If inserting a row, you can add :ref:`tags <tags>` to the row you are inserting. + This gives you the ability to :class:`filter <Dataset.filter>` your + :class:`Dataset` later. + """ + + self._validate(row) + self._data.insert(index, Row(row, tags=tags)) + + + def rpush(self, row, tags=list()): + """Adds a row to the end of the :class:`Dataset`. + See :class:`Dataset.insert` for additional documentation. + """ + + self.insert(self.height, row=row, tags=tags) + + + def lpush(self, row, tags=list()): + """Adds a row to the top of the :class:`Dataset`. + See :class:`Dataset.insert` for additional documentation. + """ + + self.insert(0, row=row, tags=tags) + + + def append(self, row, tags=list()): + """Adds a row to the :class:`Dataset`. + See :class:`Dataset.insert` for additional documentation. + """ + + self.rpush(row, tags) + + + # ------- + # Columns + # ------- + + def insert_col(self, index, col=None, header=None): + """Inserts a column to the :class:`Dataset` at the given index. + + Columns inserted must be the correct height. + + You can also insert a column of a single callable object, which will + add a new column with the return values of the callable each as an + item in the column. :: + + data.append_col(col=random.randint) + + If inserting a column, and :class:`Dataset.headers` is set, the + header attribute must be set, and will be considered the header for + that row. + + See :ref:`dyncols` for an in-depth example. + """ + + col = list(col) + + # Callable Columns... + if len(col) == 1 and hasattr(col[0], '__call__'): + col = list(map(col[0], self._data)) + + col = self._clean_col(col) + self._validate(col=col) + + if self.headers: + # pop the first item off, add to headers + if not header: + raise HeadersNeeded() + self.headers.insert(index, header) + + if self.height and self.width: + + for i, row in enumerate(self._data): + + row.insert(index, col[i]) + self._data[i] = row + else: + self._data = [Row([row]) for row in col] + + + + def rpush_col(self, col, header=None): + """Adds a column to the end of the :class:`Dataset`. + See :class:`Dataset.insert` for additional documentation. """ - if row is not None: - self.insert(self.height, row=row, tags=tags) - elif col is not None: - self.insert(self.width, col=col, header=header) + self.insert_col(self.width, col, header=header) + + + def lpush_col(self, col, header=None): + """Adds a column to the top of the :class:`Dataset`. + See :class:`Dataset.insert` for additional documentation. + """ + + self.insert_col(0, col, header=header) def insert_separator(self, index, text='-'): @@ -523,6 +654,18 @@ class Dataset(object): self.insert_separator(index, text) + def append_col(self, col, header=None): + """Adds a column to the :class:`Dataset`. + See :class:`Dataset.insert_col` for additional documentation. + """ + + self.rpush_col(col, header) + + + # ---- + # Misc + # ---- + def add_formatter(self, col, handler): """Adds a :ref:`formatter` to the :class:`Dataset`. @@ -546,63 +689,6 @@ class Dataset(object): 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. - - Rows and columns inserted must be the correct size (height or width). - - The default behaviour is to insert the given row to the :class:`Dataset` - object at the given index. If the ``col`` parameter is given, however, - a new column will be insert to the :class:`Dataset` object instead. - - You can also insert a column of a single callable object, which will - add a new column with the return values of the callable each as an - item in the column. :: - - data.append(col=random.randint) - - See :ref:`dyncols` for an in-depth example. - - .. versionchanged:: 0.9.0 - If inserting a column, and :class:`Dataset.headers` is set, the - header attribute must be set, and will be considered the header for - that row. - - .. versionadded:: 0.9.0 - If inserting a row, you can add :ref:`tags <tags>` to the row you are inserting. - This gives you the ability to :class:`filter <Dataset.filter>` your - :class:`Dataset` later. - - """ - if row: - self._validate(row) - self._data.insert(index, Row(row, tags=tags)) - elif col: - col = list(col) - - # Callable Columns... - if len(col) == 1 and hasattr(col[0], '__call__'): - col = list(map(col[0], self._data)) - - col = self._clean_col(col) - self._validate(col=col) - - if self.headers: - # pop the first item off, add to headers - if not header: - raise HeadersNeeded() - self.headers.insert(index, header) - - if self.height and self.width: - - for i, row in enumerate(self._data): - - row.insert(index, col[i]) - self._data[i] = row - else: - self._data = [Row([row]) for row in col] - - def filter(self, tag): """Returns a new instance of the :class:`Dataset`, excluding any rows that do not contain the given :ref:`tags <tags>`. @@ -617,8 +703,10 @@ class Dataset(object): """Sort a :class:`Dataset` by a specific column, given string (for header) or integer (for column index). The order can be reversed by setting ``reverse`` to ``True``. + Returns a new :class:`Dataset` instance where columns have been - sorted.""" + sorted. + """ if isinstance(col, str): @@ -679,7 +767,7 @@ class Dataset(object): return _dset - def stack_rows(self, other): + def stack(self, other): """Stack two :class:`Dataset` instances together by joining at the row level, and return new combined ``Dataset`` instance.""" @@ -702,7 +790,7 @@ class Dataset(object): return _dset - def stack_columns(self, other): + def stack_cols(self, other): """Stack two :class:`Dataset` instances together by joining at the column level, and return a new combined ``Dataset`` instance. If either ``Dataset`` @@ -726,10 +814,10 @@ class Dataset(object): _dset = Dataset() for column in self.headers: - _dset.append(col=self[column]) + _dset.append_col(col=self[column]) for column in other.headers: - _dset.append(col=other[column]) + _dset.append_col(col=other[column]) _dset.headers = new_headers |
