Commits

Lynn Rees  committed 39e7668

- reorg

  • Participants
  • Parent commits d22fe6c

Comments (0)

Files changed (24)

+syntax:glob
+.DS_Store
+*.pyc
+*.egg-info
+*~
+.figleaf
+.coverage
+build/
+dist/
+.project
+.pydevproject
+.git/
+.settings/

File AUTHORS

-Tablib is written and maintained by Kenneth Reitz and
-various contributors:
-
-Development Lead
-````````````````
-
-- Kenneth Reitz <me@kennethreitz.com>
-
-
-Patches and Suggestions
-```````````````````````
-
-- Luke Lee

File HISTORY.rst

-History
-=======
-
-0.8.1 (2010-09-28)
-------------------
-* Packaging Fix
-
-
-0.8.0 (2010-09-25)
-------------------
-* New format plugin system!
-* Imports! ELEGANT Imports!
-* Tests. Lots of tests.
-
-
-0.7.1 (2010-09-20)
-------------------
-
-* Reverting methods back to properties. 
-* Windows bug compenated in documentation.
-
-
-0.7.0 (2010-09-20)
-------------------
-
-* 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)
-------------------
-* Added Dataset.append() support for columns.
-
-
-0.6.2 (2010-09-13)
-------------------
-* Fixed Dataset.append() error on empty dataset.
-* Updated Dataset.headers property w/ validation.
-* Added Testing Fixtures.
-
-0.6.1 (2010-09-12)
-------------------
-
-* Packaging hotfixes.
-
-
-0.6.0 (2010-09-11)
-------------------
-
-* Public Release.
-* Export Support for XLS, JSON, YAML, and CSV.
-* DataBook Export for XLS, JSON, and YAML.
-* Python Dict Property Support.
-
 Copyright (c) 2010 Kenneth Reitz.
+Copyright (c) 2010 L. C. Rees
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

File PKG-INFO

-Metadata-Version: 1.0
-Name: tablib
-Version: 0.8.1
-Summary: Format agnostic tabular data library (XLS, JSON, YAML, CSV)
-Home-page: http://github.com/kennethreitz/tablib
-Author: Kenneth Reitz
-Author-email: me@kennethreitz.com
-License: MIT
-Description: Tablib: format-agnostic tabular dataset library
-        ===============================================
-        
-        ::
-        
-        	_____         ______  ___________ ______  
-        	__  /_______ ____  /_ ___  /___(_)___  /_ 
-        	_  __/_  __ `/__  __ \__  / __  / __  __ \
-        	/ /_  / /_/ / _  /_/ /_  /  _  /  _  /_/ /
-        	\__/  \__,_/  /_.___/ /_/   /_/   /_.___/
-        
-        
-        
-        Tablib is a format-agnostic tabular dataset library, written in Python. 
-        
-        Output formats supported:
-        
-        - Excel (Sets + Books)
-        - JSON (Sets + Books)
-        - YAML (Sets + Books)
-        - CSV (Sets)
-        
-        Import formats supported:
-        
-        - JSON (Sets + Books)
-        - 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
-        -----
-        
-            
-        Populate fresh data files: ::
-            
-            headers = ('first_name', 'last_name')
-        
-            data = [
-                ('John', 'Adams'),
-                ('George', 'Washington')
-            ]
-            
-            data = tablib.Dataset(*data, headers=headers)
-        
-        
-        Intelligently add new rows: ::
-        
-            >>> data.append(('Henry', 'Ford'))
-        
-        Intelligently add new columns: ::
-        
-            >>> data.append(col=('age', 90, 67, 83))
-            
-        Slice rows:  ::
-        
-            >>> print data[:2]
-            [('John', 'Adams', 90), ('George', 'Washington', 67)]
-            
-        
-        Slice columns by header: ::
-        
-            >>> print data['first_name']
-            ['John', 'George', 'Henry']
-        
-        Easily delete rows: ::
-        
-            >>> del data[1]
-        
-        Exports
-        -------
-        
-        Drumroll please...........
-        
-        JSON! 
-        +++++
-        ::
-        
-        	>>> print data.json
-        	[
-        	  {
-        	    "last_name": "Adams",
-        	    "age": 90,
-        	    "first_name": "John"
-        	  },
-        	  {
-        	    "last_name": "Ford",
-        	    "age": 83,
-        	    "first_name": "Henry"
-        	  }
-        	]
-        	
-        
-        YAML! 
-        +++++
-        ::
-        
-        	>>> print data.yaml
-        	- {age: 90, first_name: John, last_name: Adams}
-        	- {age: 83, first_name: Henry, last_name: Ford}
-        	
-        CSV... 
-        ++++++
-        ::
-        
-        	>>> print data.csv
-        	first_name,last_name,age 
-        	John,Adams,90 
-        	Henry,Ford,83 
-        	
-        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
-        ------------
-        
-        To install tablib, simply: ::
-        
-        	$ pip install tablib
-        	
-        Or, if you absolutely must: ::
-        
-        	$ easy_install tablib
-            
-        
-        Contribute
-        ----------
-        
-        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
-        -------
-        - Release CLI Interface
-        - Auto-detect import format
-        - Add possible other exports (SQL?)
-        - Ability to assign types to rows (set, regex=, &c.)
-        
-        .. _`the repository`: http://github.com/kennethreitz/tablib
-        .. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS
-        
-        
-        History
-        =======
-        
-        0.8.1 (2010-09-28)
-        ------------------
-        * Packaging Fix
-        
-        
-        0.8.0 (2010-09-25)
-        ------------------
-        * New format plugin system!
-        * Imports! ELEGANT Imports!
-        * Tests. Lots of tests.
-        
-        
-        0.7.1 (2010-09-20)
-        ------------------
-        
-        * Reverting methods back to properties. 
-        * Windows bug compenated in documentation.
-        
-        
-        0.7.0 (2010-09-20)
-        ------------------
-        
-        * 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)
-        ------------------
-        * Added Dataset.append() support for columns.
-        
-        
-        0.6.2 (2010-09-13)
-        ------------------
-        * Fixed Dataset.append() error on empty dataset.
-        * Updated Dataset.headers property w/ validation.
-        * Added Testing Fixtures.
-        
-        0.6.1 (2010-09-12)
-        ------------------
-        
-        * Packaging hotfixes.
-        
-        
-        0.6.0 (2010-09-11)
-        ------------------
-        
-        * Public Release.
-        * Export Support for XLS, JSON, YAML, and CSV.
-        * DataBook Export for XLS, JSON, and YAML.
-        * Python Dict Property Support.
-        
-        
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7

File README.rst

-Tablib: format-agnostic tabular dataset library
-===============================================
-
-::
-
-	_____         ______  ___________ ______  
-	__  /_______ ____  /_ ___  /___(_)___  /_ 
-	_  __/_  __ `/__  __ \__  / __  / __  __ \
-	/ /_  / /_/ / _  /_/ /_  /  _  /  _  /_/ /
-	\__/  \__,_/  /_.___/ /_/   /_/   /_.___/
-
-
-
-Tablib is a format-agnostic tabular dataset library, written in Python. 
-
-Output formats supported:
-
-- Excel (Sets + Books)
-- JSON (Sets + Books)
-- YAML (Sets + Books)
-- CSV (Sets)
-
-Import formats supported:
-
-- JSON (Sets + Books)
-- 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
------
-
-    
-Populate fresh data files: ::
-    
-    headers = ('first_name', 'last_name')
-
-    data = [
-        ('John', 'Adams'),
-        ('George', 'Washington')
-    ]
-    
-    data = tablib.Dataset(*data, headers=headers)
-
-
-Intelligently add new rows: ::
-
-    >>> data.append(('Henry', 'Ford'))
-
-Intelligently add new columns: ::
-
-    >>> data.append(col=('age', 90, 67, 83))
-    
-Slice rows:  ::
-
-    >>> print data[:2]
-    [('John', 'Adams', 90), ('George', 'Washington', 67)]
-    
-
-Slice columns by header: ::
-
-    >>> print data['first_name']
-    ['John', 'George', 'Henry']
-
-Easily delete rows: ::
-
-    >>> del data[1]
-
-Exports
--------
-
-Drumroll please...........
-
-JSON! 
-+++++
-::
-
-	>>> print data.json
-	[
-	  {
-	    "last_name": "Adams",
-	    "age": 90,
-	    "first_name": "John"
-	  },
-	  {
-	    "last_name": "Ford",
-	    "age": 83,
-	    "first_name": "Henry"
-	  }
-	]
-	
-
-YAML! 
-+++++
-::
-
-	>>> print data.yaml
-	- {age: 90, first_name: John, last_name: Adams}
-	- {age: 83, first_name: Henry, last_name: Ford}
-	
-CSV... 
-++++++
-::
-
-	>>> print data.csv
-	first_name,last_name,age 
-	John,Adams,90 
-	Henry,Ford,83 
-	
-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
-------------
-
-To install tablib, simply: ::
-
-	$ pip install tablib
-	
-Or, if you absolutely must: ::
-
-	$ easy_install tablib
-    
-
-Contribute
-----------
-
-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
--------
-- Release CLI Interface
-- Auto-detect import format
-- Add possible other exports (SQL?)
-- Ability to assign types to rows (set, regex=, &c.)
-
-.. _`the repository`: http://github.com/kennethreitz/tablib
-.. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
+#import ez_setup
+#ez_setup.use_setuptools()
 
-import os
-import sys
-
-from distutils.core import setup
-
-
-def publish():
-	"""Publish to PyPi"""
-	os.system("python setup.py sdist upload")
-
-if sys.argv[-1] == "publish":
-	publish()
-	sys.exit()
+try:
+    from setuptools import setup
+except:
+    from distutils.core import setup
 
 setup(
-	name='tablib',
-	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', 'tablib.formats'],
-	install_requires=['xlwt', 'simplejson', 'PyYAML'],
+	name='tabola',
+	version='0.0.6',
+	author='L. C. Rees',
+	author_email='lcrees@gmail.com',
+	url='http://pypi.python.com/tabola/',
+	packages=['tabola', 'tabola.formats'],
+	install_requires=['xlwt', 'simplejson', 'PyYAML', 'xlrd'],
 	license='MIT',
 	classifiers=(
 		'Development Status :: 4 - Beta',
 		'License :: OSI Approved :: MIT License',
 		'Programming Language :: Python',
-        # 'Programming Language :: Python :: 2.5',
-        'Programming Language :: Python :: 2.6',
-		'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python',
 	),
-    # entry_points={
-    #   'console_scripts': [
-    #       'tabbed = tablib.cli:start',
-    #   ],
-    # }
-)
+    zip_safe = True,
+)

File tablib/__init__.py

-""" Tablib.
-"""
-
-from tablib.core import (
-	Databook, Dataset, InvalidDatasetType,
-	InvalidDimensions, UnsupportedFormat
-)
-

File tablib/core.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - Core Library.
-"""
-
-from tablib.formats import FORMATS as formats
-
-
-__title__ = 'tablib'
-__version__ = '0.8.1'
-__build__ = 0x000801
-__author__ = 'Kenneth Reitz'
-__license__ = 'MIT'
-__copyright__ = 'Copyright 2010 Kenneth Reitz'
-
-
-class Dataset(object):
-	"""Epic Tabular-Dataset object. """
-
-	def __init__(self, *args, **kwargs):
-		self._data = list(args)
-		self.__headers = None
-
-		try:
-			self.headers = kwargs['headers']
-		except KeyError:
-			self.headers = None
-
-		try:
-			self.title = kwargs['title']
-		except KeyError:
-			self.title = None
-
-		self._register_formats()
-
-	def __len__(self):
-		return self.height
-
-
-	def __getitem__(self, 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]
-			else:
-				raise KeyError
-		else:
-			return self._data[key]
-
-
-	def __setitem__(self, key, value):
-		self._validate(value)
-		self._data[key] = tuple(value)
-
-
-	def __delitem__(self, key):
-		del self._data[key]
-
-
-	def __repr__(self):
-		try:
-			return '<%s dataset>' % (self.title.lower())
-		except AttributeError:
-			return '<dataset object>'
-
-	
-	@classmethod
-	def _register_formats(cls):
-		"""Adds format properties."""
-		for fmt in formats:
-			try:
-				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
-
-
-	def _validate(self, row=None, col=None, safety=False):
-		"""Assures size of every row in dataset is of proper proportions."""
-		if row:
-			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:
-			is_valid = all((len(x)== self.width for x in self._data))
-
-		if is_valid:
-			return True
-		else:
-			if not safety:
-				raise InvalidDimensions
-			return False
-
-
-	def _package(self, dicts=True):
-		"""Packages Dataset into lists of dictionaries for transmission."""
-
-		if self.headers:
-			if dicts:
-				data = [dict(zip(self.headers, data_row)) for data_row in self ._data]
-			else:
-				data = [list(self.headers)] + list(self._data)
-		else:
-			data = [list(row) for row in self._data]
-
-		return data
-
-	
-	@property
-	def height(self):
-		"""Returns the height of the Dataset."""
-		return len(self._data)
-
-
-	@property
-	def width(self):
-		"""Returns the width of the Dataset."""
-		try:
-			return len(self._data[0])
-		except IndexError:
-			try:
-				return len(self.headers)
-			except TypeError:
-				return 0
-
-
-	@property
-	def headers(self):
-		"""Headers property."""
-		return self.__headers
-
-
-	@headers.setter
-	def headers(self, collection):
-		"""Validating headers setter."""
-		self._validate(collection)
-		if collection:
-			try:
-				self.__headers = list(collection)
-			except TypeError:
-				raise TypeError
-		else:
-			self.__headers = None
-
-
-	@property
-	def dict(self):
-		"""Returns python dict of Dataset."""
-		return self._package()
-
-	
-	@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):
-		"""Adds a row to the end of Dataset"""
-		if 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 insert(self, i, row=None, col=None):
-		"""Inserts a row at given position in Dataset"""
-		if row:
-			self._validate(row)
-			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):
-	"""A book of Dataset objects.
-	   Currently, this exists only for XLS workbook support.
-	"""
-
-	def __init__(self, sets=[]):
-		self._datasets = sets
-		self._register_formats()
-
-
-	def __repr__(self):
-		try:
-			return '<%s databook>' % (self.title.lower())
-		except AttributeError:
-			return '<databook object>'
-
-	def wipe(self):
-		"""Wipe book clean."""
-		self._datasets = []
-		
-	@classmethod
-	def _register_formats(cls):
-		"""Adds format properties."""
-		for fmt in formats:
-			try:
-				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
-
-
-	def add_sheet(self, dataset):
-		"""Adds given dataset."""
-		if type(dataset) is Dataset:
-			self._datasets.append(dataset)
-		else:
-			raise InvalidDatasetType
-
-
-	def _package(self):
-		"""Packages Databook for delivery."""
-		collector = []
-		for dset in self._datasets:
-			collector.append(dict(
-				title = dset.title,
-				data = dset.dict
-			))
-		return collector
-
-
-	@property
-	def size(self):
-		"""The number of the Datasets within DataBook."""
-		return len(self._datasets)
-
-
-
-class InvalidDatasetType(Exception):
-	"Only Datasets can be added to a DataBook"
-
-
-class InvalidDimensions(Exception):
-	"Invalid size"
-
-	
-class UnsupportedFormat(NotImplementedError):
-	"Format is not supported"

File tablib/formats/__init__.py

-# -*- 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)

File tablib/formats/_csv.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - CSV Support.
-"""
-
-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(dset, in_stream, headers=True):
-	"""Returns dataset from CSV stream."""
-
-	dset.wipe()
-
-	rows = csv.reader(in_stream.split())
-	for i, row in enumerate(rows):
-
-		if (i == 0) and (headers):
-			dset.headers = row
-		else:
-			dset.append(row)

File tablib/formats/_json.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - JSON Support
-"""
-
-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 import_set(dset, in_stream):
-	"""Returns dataset from JSON stream."""
-	
-	dset.wipe()
-	dset.dict = json.loads(in_stream)
-
-
-def import_book(dbook, in_stream):
-	"""Returns databook from JSON stream."""
-
-	dbook.wipe()
-	for sheet in json.loads(in_stream):
-		data = tablib.core.Dataset()
-		data.title = sheet['title']
-		data.dict = sheet['data']
-		dbook.add_sheet(data)

File tablib/formats/_xls.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - XLS Support.
-"""
-
-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()

File tablib/formats/_yaml.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - YAML Support.
-"""
-
-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(dset, in_stream):
-	"""Returns dataset from YAML stream."""
-
-	dset.wipe()
-	dset.dict = yaml.load(in_stream)
-
-
-def import_book(dbook, in_stream):
-	"""Returns databook from YAML stream."""
-
-	dbook.wipe()
-
-	for sheet in yaml.load(in_stream):
-		data = tablib.core.Dataset()
-		data.title = sheet['title']
-		data.dict = sheet['data']
-		dbook.add_sheet(data)

File tablib/helpers.py

-# -*- coding: utf-8 -*-
-
-""" Tablib - General Helpers.
-"""
-
-import sys
-
-
-class Struct(object):
-	"""Your attributes are belong to us."""
-	
-	def __init__(self, **entries): 
-		self.__dict__.update(entries)
-		
-	def __getitem__(self, key):
-		return getattr(self, key, None)
-
-	def dictionary(self):
-		"""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."""
-	with sys.stdin as stdin:
-		# TTY is only way to detect if stdin contains data
-		return stdin.read() if not stdin.isatty() else None
-

File tabola/__init__.py

+'''tabola.'''
+
+from tabola.core import (
+	Databook, Dataset, InvalidDatasetType, InvalidDimensions, UnsupportedFormat,
+) 

File tabola/core.py

+'''tabola'''
+
+from tabola.formats import FORMATS as formats
+
+def all(iterable):
+    for element in iterable:
+        if not element: return False
+    return True
+
+class InvalidDatasetType(Exception):
+
+    '''Only Datasets can be added to a DataBook.'''
+
+
+class InvalidDimensions(Exception):
+    
+    '''Invalid size.'''
+
+    
+class UnsupportedFormat(NotImplementedError):
+    
+    '''Format is not supported'''
+
+
+class Dataset(object):
+
+    '''Tabular - Dataset object'''
+
+    def __init__(self, *args, **kw):
+        self._data = list(args)
+        self.headers = kw.get('headers', tuple())
+        self.title = kw.get('title')
+        self._register_formats()
+
+    def __len__(self):
+        return self.height
+
+    def __getitem__(self, key):
+        if isinstance(key, basestring):
+            if key in self._headers:
+                # get 'key' index from each data
+                pos = self._headers.index(key)
+                return list(r[pos] for r in self._data)
+            else:
+                raise KeyError
+        else:
+            return self._data[key]
+
+    def __setitem__(self, key, value):
+        self._validate_row(value)
+        self._data[key] = tuple(value)
+
+    def __delitem__(self, key):
+        del self._data[key]
+        
+    def __iter__(self):
+        return self._data.__iter__()
+        
+    def _package(self, dicts=True):
+        '''Packages Dataset into lists of dictionaries for transmission.'''
+        if self.headers:
+            if dicts:
+                data = list(dict(zip(self.headers, r)) for r in self ._data)
+            else:
+                data = [list(self.headers)] + list(self._data)
+        else:
+            data = list(list(r) for r in self._data)
+        return data
+    
+    @classmethod
+    def _register_formats(cls):
+        '''Adds format properties.'''
+        for f in formats:
+            try:
+                try:
+                    setattr(cls, f.title, property(f.export_set, f.import_set))
+                except AttributeError:
+                    setattr(cls, f.title, property(f.export_set))
+            except AttributeError: pass
+
+    def _get_headers(self):
+        '''Headers property.'''
+        return self._headers
+
+    def _set_headers(self, collection):
+        '''Validating headers setter.'''
+        if self._validate_headers(collection):
+            try:
+                self._headers = list(collection)
+            except TypeError:
+                self._headers = []
+        else:
+            self._headers = []
+            
+    def _del_headers(self):
+        self._headers = None
+            
+    headers = property(_get_headers, _set_headers, _del_headers)
+
+    def _get_dict(self):
+        '''Returns python dict of Dataset.'''
+        return self._package()
+    
+    def _set_dict(self, rows):
+        if not len(rows): return None
+        if isinstance(rows[0], list):
+            self.clear()
+            for row in rows: self.append_row(row)
+        elif isinstance(rows[0], dict):
+            self.clear()
+            self.headers = rows[0].keys()
+            for row in rows: self.append_row(row.values())
+        else:
+            raise UnsupportedFormat
+        
+    dict = property(_get_dict, _set_dict)
+    
+    def _validate_column(self, col):
+        if self.headers:
+            is_valid = (len(col) - 1) == self.height
+        else:
+            is_valid = len(col) == self.height if self.height else True
+        if is_valid: return True
+        raise InvalidDimensions()
+    
+    def _validate_headers(self, header):
+        return all((len(x)==self.width for x in self._data))
+    
+    def _validate_row(self, row):
+        if len(row) == self.width if self.width else True: return True
+        raise InvalidDimensions()
+    
+    @property
+    def height(self):
+        '''Returns the height of the Dataset.'''
+        return len(self._data)
+
+    @property
+    def width(self):
+        '''Returns the width of the Dataset.'''
+        try:
+            return len(self._data[0])
+        except IndexError:
+            try:
+                return len(self.headers)
+            except TypeError:
+                return 0
+            
+    def append_column(self, column):
+        if self._validate_column(column):
+            if self.headers:
+                # pop the first item off and add to headers
+                self.headers.append(column[0])
+                column = column[1:]
+            if self.height and self.width:
+                for i, row in enumerate(self._data):
+                    _row = list(row)
+                    _row.append(column[i])
+                    self._data[i] = tuple(_row)
+            else:
+                self._data = [tuple([r]) for r in column]
+
+    def append_row(self, row):
+        '''Adds a row to the end of Dataset'''
+        if self._validate_row(row): self._data.append(tuple(row))
+        
+    def clear(self):
+        '''Erases all data from Dataset.'''
+        self._headers = None
+        self._data = list()
+        
+    def get_row_dict(self, key):
+        if self.headers: return dict(zip(self.headers, self.__getitem__(key))) 
+        raise UnsupportedFormat()
+
+    def insert_row(self, i, row):
+        '''Inserts a row at given position in Dataset'''
+        if self._validate(row): self._data.insert(i, tuple(row))
+    
+    def iter_row_dicts(self):
+        if self.headers: return self._package() 
+        raise UnsupportedFormat()
+    
+
+class Databook(object):
+    
+    '''A book of Dataset objects.'''
+
+    def __init__(self, sets=[]):
+        self._datasets = sets
+        self._register_formats()
+        
+    def __len__(self):
+        '''The number of Datasets within Databook.'''
+        return len(self._datasets)    
+    
+    def __iter__(self):
+        return self._datasets.__iter__()
+    
+    def _package(self):
+        '''Packages Databook for delivery.'''
+        return list(dict(title=d.title, data=d.dict) for d in self._datasets)
+        
+    @classmethod
+    def _register_formats(cls):
+        '''Adds format properties.'''
+        for f in formats:
+            try:
+                try:
+                    setattr(cls, f.title, property(f.export_book, f.import_book))
+                except AttributeError:
+                    setattr(cls, f.title, property(f.export_book))                    
+            except AttributeError: pass
+
+    def append_dataset(self, dataset):
+        '''Adds given dataset.'''
+        if isinstance(dataset, Dataset):
+            self._datasets.append(dataset)
+        else:
+            raise InvalidDatasetType()
+
+    def clear(self):
+        self._datasets = []

File tabola/formats/__init__.py

+'''tabola - formats'''
+
+import _csv as csv
+import _json as json
+import _xls as xls
+import _yaml as yaml
+import _iif as iif
+
+FORMATS = (csv, json, xls, yaml, iif)

File tabola/formats/_csv.py

+'''tabola - CSV Support.'''
+
+import csv
+import cStringIO
+
+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(False): _csv.writerow(row)
+	return stream.getvalue()
+
+def import_set(dset, in_stream, headers=True):
+	'''Returns dataset from CSV stream.'''
+	dset.clear()
+	rows = csv.reader(in_stream.split())
+	for i, row in enumerate(rows):
+		if i == 0 and headers:
+			dset.headers = row
+		else:
+			dset.append_row(row)

File tabola/formats/_iif.py

+'''tabola - CSV Support.'''
+
+import csv
+import cStringIO
+
+title = 'iif'
+extentions = ('iif',)
+
+def export_set(dataset):
+	'''Returns CSV representation of Dataset.'''
+	stream = cStringIO.StringIO()
+	_csv = csv.writer(stream, delimiter='\t')
+	for row in dataset._package(False): _csv.writerow(row)
+	return stream.getvalue()
+
+def import_set(dset, in_stream, headers=True):
+	'''Returns dataset from CSV stream.'''
+	dset.clear()
+	rows = csv.reader(in_stream.split(), delimiter='\t')
+	for i, row in enumerate(rows):
+		if i == 0 and headers:
+			dset.headers = row
+		else:
+			dset.append_row(row)

File tabola/formats/_json.py

+'''ablib - JSON Support.'''
+
+try:
+    import simplejson as json
+except ImportError:
+    from python import json
+    
+import tabola.core
+
+title = 'json'
+extensions = ('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 import_set(dset, in_stream):
+    '''Returns dataset from JSON stream.'''
+    dset.clear()
+    dset.dict = json.loads(in_stream)
+
+def import_book(dbook, in_stream):
+    '''Returns databook from JSON stream.'''
+    dbook.clear()
+    for sheet in json.loads(in_stream):
+        data = tabola.core.Dataset()
+        data.title = sheet['title']
+        data.dict = sheet['data']
+        dbook.append_dataset(data)

File tabola/formats/_xls.py

+'''tabola - XLS Support.'''
+
+import cStringIO
+
+import xlrd
+import xlwt
+
+import tabola.core
+
+title = 'xls'
+extensions = ('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(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 i, row in enumerate(dset._package(False)):
+            for j, col in enumerate(row): ws.write(i, j, col)
+    stream = cStringIO.StringIO()
+    wb.save(stream)
+    return stream.getvalue()
+
+def import_set(dset, sheet, headers=True):
+    '''Returns dataset from CSV stream.'''
+    dset.clear()
+    dset.title = sheet.name
+    for row in xrange(sheet.nrows):
+        new_row = list()
+        for col in xrange(sheet.ncols):
+            new_row.append(sheet.cell_value(row, col))
+        if row == 0 and headers:
+            dset.headers = new_row
+        else:
+            dset.append_row(new_row)
+    
+def import_book(databook, in_stream, headers=True):
+    '''Returns dataset from CSV stream.'''
+    databook.clear()
+    wb = xlrd.open_workbook(file_contents=in_stream)
+    for sheet in wb.sheets():
+        dataset = tabola.core.Dataset()
+        dataset.title = sheet.name
+        for row in xrange(sheet.nrows):
+            new_row = list()
+            for col in xrange(sheet.ncols):
+                new_row.append(sheet.cell_value(row, col))
+            if row == 0 and headers:
+                dataset.headers = new_row
+            else:
+                dataset.append_row(new_row)
+        databook.append_dataset(dataset)

File tabola/formats/_yaml.py

+'''tabola - YAML Support.'''
+
+import yaml
+
+import tabola.core
+
+title = 'yaml'
+extensions = ('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(dset, in_stream):
+	'''Returns dataset from YAML stream.'''
+	dset.clear()
+	dset.dict = yaml.load(in_stream)
+
+def import_book(dbook, in_stream):
+	'''Returns databook from YAML stream.'''
+	dbook.clear()
+	for sheet in yaml.load(in_stream):
+		data = tabola.core.Dataset()
+		data.title = sheet['title']
+		data.dict = sheet['data']
+		dbook.append_dataset(data)

File tabola/tabola_test.py

+# -*- coding: utf-8 -*-
+
+import unittest
+
+import tabola
+
+
+class TablibTestCase(unittest.TestCase):
+
+    def setUp(self):
+        '''Create simple data set with headers.'''
+        global data, book
+        data = tabola.Dataset()
+        book = tabola.Databook()
+        self.headers = ('first_name', 'last_name', 'gpa')
+        self.john = ('John', 'Adams', 90)
+        self.george = ('George', 'Washington', 67)
+        self.tom = ('Thomas', 'Jefferson', 50)
+        self.founders = tabola.Dataset(headers=self.headers)
+        self.founders.append_row(self.john)
+        self.founders.append_row(self.george)
+        self.founders.append_row(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)
+        data.append_row(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
+        headers and data.
+        '''
+        data.headers = ['first', 'second']
+        new_row = (1, 2, 3, 4)
+        self.assertRaises(tabola.InvalidDimensions, data.append_row, new_row)
+
+    def test_add_column(self):
+        '''Verify adding column works with/without headers.'''
+
+        data.append_row(['kenneth'])
+        data.append_row(['bessie'])
+        new_col = ['reitz', 'monke']
+        data.append_column(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_column(new_col)
+        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.'''
+        new_col = ('reitz', 'monke')
+        data.append_column(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):
+        '''Verify adding new column with headers.'''
+        data.headers = ('first', 'last')
+        new_col = ('age',)
+        data.append_column(new_col)
+        self.assertEquals(len(data.headers), 3)
+        self.assertEquals(data.width, 3)
+        new_col = ('foo', 'bar')
+        self.assertRaises(tabola.InvalidDimensions, data.append_column, new_col)
+
+    def test_header_slicing(self):
+        '''Verify slicing by headers.'''
+        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.'''
+        # 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[-1], self.tom)
+        self.assertEqual(self.founders[3:], [])
+        # 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_delete(self):
+        '''Verify deleting from dataset works.'''
+        # Delete from front of object
+        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)
+
+    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)
+
+    def test_unicode_append(self):
+        '''Passes in a single unicode charecter and exports.'''
+        new_row = ('�', '�')
+        data.append_row(new_row)
+        data.json
+        data.yaml
+        data.csv
+        data.xls
+ 
+    def test_book_export_no_exceptions(self):
+        '''Test that varoius exports don't error out.'''
+        book = tabola.Databook()
+        book.append_dataset(data)
+        book.json
+        book.yaml
+        book.xls
+
+    def test_json_import_set(self):
+        '''Generate and import JSON set serialization.'''
+        data.append_row(self.john)
+        data.append_row(self.george)
+        data.headers = self.headers
+        _json = data.json
+        data.json = _json
+        self.assertEqual(_json, data.json)
+
+    def test_json_import_book(self):
+        '''Generate and import JSON book serialization.'''
+        data.append_row(self.john)
+        data.append_row(self.george)
+        data.headers = self.headers
+        book.append_dataset(data)
+        _json = book.json
+        book.json = _json
+        self.assertEqual(_json, book.json)
+
+    def test_yaml_import_set(self):
+        '''Generate and import YAML set serialization.'''
+        data.append_row(self.john)
+        data.append_row(self.george)
+        data.headers = self.headers
+        _yaml = data.yaml
+        data.yaml = _yaml
+        self.assertEqual(_yaml, data.yaml)
+        
+    def test_yaml_import_book(self):
+        '''Generate and import YAML book serialization.'''
+        data.append_row(self.john)
+        data.append_row(self.george)
+        data.headers = self.headers
+        book.append_dataset(data)
+        _yaml = book.yaml
+        book.yaml = _yaml
+        self.assertEqual(_yaml, book.yaml)
+        
+    def test_csv_import_set(self):
+        '''Generate and import CSV set serialization.'''
+        data.append_row(self.john)
+        data.append_row(self.george)
+        data.headers = self.headers
+        _csv = data.csv
+        data.csv = _csv
+        self.assertEqual(_csv, data.csv)
+
+    def test_wipe(self):
+        '''Purge a dataset.'''
+        new_row = (1, 2, 3)
+        data.append_row(new_row)
+        # Verify width/data
+        self.assertTrue(data.width==len(new_row))
+        self.assertTrue(data[0]==new_row)        
+        data.clear()
+        new_row = (1, 2, 3, 4)
+        data.append_row(new_row)
+        self.assertTrue(data.width==len(new_row))
+        self.assertTrue(data[0]==new_row)
+    
+
+if __name__ == '__main__':
+    unittest.main()