Compare commits

..

7 Commits

Author SHA1 Message Date
Timo Furrer 3c66697280 Merge pull request #315 from cls1991/develop
DataBook().load function params error.
2019-03-02 12:13:11 +01:00
cls1991 13334b7996 DataBook().load function params error 2017-10-24 19:33:35 +08:00
kennethreitz 77a5c8d3fb Merge pull request #309 from cristiano2lopes/delegate-type-coercion-to-openpyxl
Delegate type coercion to openpyxl
2017-09-11 11:51:53 -04:00
Cristiano Lopes 79d66cd250 Handle raised exceptions while setting the value on the cell
Convert the value to unicode, if not enough i think the bubbling of the
exception is the best thing to do
2017-09-11 13:05:31 +01:00
Cristiano Lopes 77469ef655 Delegate type coercion to openpyxl 2017-09-11 12:47:51 +01:00
kennethreitz e21676d3bd Merge pull request #302 from kirsn/patch-2
`Nose` link corrected
2017-08-29 22:58:35 -04:00
Kiran Subbaraman 7c59e1ae86 Nose link corrected
It now points to https://github.com/nose-devs/nose
2017-08-28 13:41:10 +05:30
27 changed files with 332 additions and 357 deletions
-3
View File
@@ -26,6 +26,3 @@ junit-py27.xml
# tox noise # tox noise
.tox .tox
# pyenv noise
.python-version
-2
View File
@@ -32,5 +32,3 @@ Patches and Suggestions
- Rabin Nankhwa - Rabin Nankhwa
- Marco Dallagiacoma - Marco Dallagiacoma
- Mathias Loesch - Mathias Loesch
- Tushar Makkar
- Andrii Soldatenko
-11
View File
@@ -1,17 +1,6 @@
History History
------- -------
0.11.4 (2017-01-23)
+++++++++++++++++++
- Use built-in `json` package if available
- Support Python 3.5+ in classifiers
** Bugfixes **
- Fixed textual representation for Dataset with no headers
- Handle decimal types
0.11.3 (2016-02-16) 0.11.3 (2016-02-16)
+++++++++++++++++++ +++++++++++++++++++
+1 -1
View File
@@ -1,7 +1,7 @@
Tablib: format-agnostic tabular dataset library Tablib: format-agnostic tabular dataset library
=============================================== ===============================================
.. image:: https://travis-ci.org/kennethreitz/tablib.svg?branch=master .. image:: https://travis-ci.org/kennethreitz/tablib.svg?branch=develop
:target: https://travis-ci.org/kennethreitz/tablib :target: https://travis-ci.org/kennethreitz/tablib
:: ::
+1 -1
View File
@@ -155,7 +155,7 @@ Once installed, we can generate our xUnit report with a single command. ::
This will generate a **nosetests.xml** file, which can then be analyzed. This will generate a **nosetests.xml** file, which can then be analyzed.
.. _Nose: http://somethingaboutorange.com/mrl/projects/nose/ .. _Nose: https://github.com/nose-devs/nose
+2 -2
View File
@@ -158,9 +158,9 @@ To do so, we access the :class:`Dataset` as if it were a standard Python diction
You can also access the column using its index. :: You can also access the column using its index. ::
>>> data.headers >>> d.headers
['Last Name', 'First Name', 'Age'] ['Last Name', 'First Name', 'Age']
>>> data.get_col(1) >>> d.get_col(1)
['Kenneth', 'Bessie'] ['Kenneth', 'Bessie']
Let's find the average age. :: Let's find the average age. ::
+2 -4
View File
@@ -73,7 +73,7 @@ setup(
url='http://python-tablib.org', url='http://python-tablib.org',
packages=packages, packages=packages,
license='MIT', license='MIT',
classifiers=[ classifiers=(
'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'Natural Language :: English', 'Natural Language :: English',
@@ -87,8 +87,6 @@ setup(
'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5', ),
'Programming Language :: Python :: 3.6',
],
tests_require=['pytest'], tests_require=['pytest'],
) )
-1
View File
@@ -34,7 +34,6 @@ if is_py3:
from io import StringIO from io import StringIO
# py3 mappings # py3 mappings
ifilter = filter
unicode = str unicode = str
bytes = bytes bytes = bytes
basestring = str basestring = str
+3 -6
View File
@@ -18,8 +18,8 @@ from tablib.compat import OrderedDict, unicode
__title__ = 'tablib' __title__ = 'tablib'
__version__ = '0.11.4' __version__ = '0.11.3'
__build__ = 0x001104 __build__ = 0x001103
__author__ = 'Kenneth Reitz' __author__ = 'Kenneth Reitz'
__license__ = 'MIT' __license__ = 'MIT'
__copyright__ = 'Copyright 2016 Kenneth Reitz' __copyright__ = 'Copyright 2016 Kenneth Reitz'
@@ -143,7 +143,6 @@ class Dataset(object):
:param \*args: (optional) list of rows to populate Dataset :param \*args: (optional) list of rows to populate Dataset
:param headers: (optional) list strings for Dataset header row :param headers: (optional) list strings for Dataset header row
:param title: (optional) string to use as title of the Dataset
.. admonition:: Format Attributes Definition .. admonition:: Format Attributes Definition
@@ -224,7 +223,6 @@ class Dataset(object):
result = [] result = []
# Add unicode representation of headers. # Add unicode representation of headers.
if self.__headers:
result.append([unicode(h) for h in self.__headers]) result.append([unicode(h) for h in self.__headers])
# Add unicode representation of rows. # Add unicode representation of rows.
@@ -234,7 +232,6 @@ class Dataset(object):
field_lens = list(map(max, zip(*lens))) field_lens = list(map(max, zip(*lens)))
# delimiter between header and data # delimiter between header and data
if self.__headers:
result.insert(1, ['-' * length for length in field_lens]) result.insert(1, ['-' * length for length in field_lens])
format_string = '|'.join('{%s:%s}' % item for item in enumerate(field_lens)) format_string = '|'.join('{%s:%s}' % item for item in enumerate(field_lens))
@@ -1108,7 +1105,7 @@ class Databook(object):
"""The number of the :class:`Dataset` objects within :class:`Databook`.""" """The number of the :class:`Dataset` objects within :class:`Databook`."""
return len(self._datasets) return len(self._datasets)
def load(self, format, in_stream, **kwargs): def load(self, in_stream, format, **kwargs):
""" """
Import `in_stream` to the :class:`Databook` object using the `format`. Import `in_stream` to the :class:`Databook` object using the `format`.
-1
View File
@@ -55,7 +55,6 @@ def export_set(dataset):
else: else:
stream = StringIO(dbf_stream.read()) stream = StringIO(dbf_stream.read())
dbf_stream.close() dbf_stream.close()
os.close(temp_file)
os.remove(temp_uri) os.remove(temp_uri)
return stream.getvalue() return stream.getvalue()
+4 -7
View File
@@ -58,13 +58,10 @@ def export_book(databook):
stream = StringIO() stream = StringIO()
# Allow unicode characters in output
wrapper = codecs.getwriter("utf8")(stream)
for i, dset in enumerate(databook._datasets): for i, dset in enumerate(databook._datasets):
title = (dset.title if dset.title else 'Set %s' % (i)) title = (dset.title if dset.title else 'Set %s' % (i))
wrapper.write('<%s>%s</%s>\n' % (BOOK_ENDINGS, title, BOOK_ENDINGS)) stream.write('<%s>%s</%s>\n' % (BOOK_ENDINGS, title, BOOK_ENDINGS))
wrapper.write(dset.html) stream.write(dset.html)
wrapper.write('\n') stream.write('\n')
return stream.getvalue().decode('utf-8') return stream.getvalue()
+3 -12
View File
@@ -2,14 +2,11 @@
""" Tablib - JSON Support """ Tablib - JSON Support
""" """
import decimal
import tablib import tablib
try: import sys
import json from tablib.packages import omnijson as json
except ImportError:
from tablib.packages import omnijson as json
title = 'json' title = 'json'
@@ -17,13 +14,7 @@ extensions = ('json', 'jsn')
def date_handler(obj): def date_handler(obj):
if isinstance(obj, decimal.Decimal): return obj.isoformat() if hasattr(obj, 'isoformat') else obj
return str(obj)
elif hasattr(obj, 'isoformat'):
return obj.isoformat()
else:
return obj
# return obj.isoformat() if hasattr(obj, 'isoformat') else obj
def export_set(dataset): def export_set(dataset):
+10 -12
View File
@@ -17,6 +17,7 @@ import tablib
Workbook = openpyxl.workbook.Workbook Workbook = openpyxl.workbook.Workbook
ExcelWriter = openpyxl.writer.excel.ExcelWriter ExcelWriter = openpyxl.writer.excel.ExcelWriter
get_column_letter = openpyxl.cell.get_column_letter get_column_letter = openpyxl.cell.get_column_letter
DataTypeException = openpyxl.shared.exc.DataTypeException
from tablib.compat import unicode from tablib.compat import unicode
@@ -120,7 +121,6 @@ def dset_sheet(dataset, ws, freeze_panes=True):
if (row_number == 1) and dataset.headers: if (row_number == 1) and dataset.headers:
# ws.cell('%s%s'%(col_idx, row_number)).value = unicode( # ws.cell('%s%s'%(col_idx, row_number)).value = unicode(
# '%s' % col, errors='ignore') # '%s' % col, errors='ignore')
ws.cell('%s%s'%(col_idx, row_number)).value = unicode(col)
style = ws.get_style('%s%s' % (col_idx, row_number)) style = ws.get_style('%s%s' % (col_idx, row_number))
style.font.bold = True style.font.bold = True
if freeze_panes: if freeze_panes:
@@ -130,23 +130,21 @@ def dset_sheet(dataset, ws, freeze_panes=True):
# bold separators # bold separators
elif len(row) < dataset.width: elif len(row) < dataset.width:
ws.cell('%s%s'%(col_idx, row_number)).value = unicode(
'%s' % col, errors='ignore')
style = ws.get_style('%s%s' % (col_idx, row_number)) style = ws.get_style('%s%s' % (col_idx, row_number))
style.font.bold = True style.font.bold = True
# wrap the rest # wrap the rest
else: else:
try: try:
if '\n' in col: str_col_value = unicode(col)
ws.cell('%s%s'%(col_idx, row_number)).value = unicode( except TypeError:
'%s' % col, errors='ignore') str_col_value = ''
if '\n' in str_col_value:
style = ws.get_style('%s%s' % (col_idx, row_number)) style = ws.get_style('%s%s' % (col_idx, row_number))
style.alignment.wrap_text style.alignment.wrap_text
else:
ws.cell('%s%s'%(col_idx, row_number)).value = unicode(
'%s' % col, errors='ignore')
except TypeError:
ws.cell('%s%s'%(col_idx, row_number)).value = unicode(col)
try:
ws.cell('%s%s' % (col_idx, row_number)).value = col
except (ValueError, TypeError, DataTypeException):
ws.cell('%s%s' % (col_idx, row_number)).value = unicode(col)
+4 -1
View File
@@ -13,12 +13,16 @@ except ImportError:
else: else:
import tablib.packages.yaml as yaml import tablib.packages.yaml as yaml
import tablib import tablib
title = 'yaml' title = 'yaml'
extensions = ('yaml', 'yml') extensions = ('yaml', 'yml')
def export_set(dataset): def export_set(dataset):
"""Returns YAML representation of Dataset.""" """Returns YAML representation of Dataset."""
@@ -48,7 +52,6 @@ def import_book(dbook, in_stream):
data.dict = sheet['data'] data.dict = sheet['data']
dbook.add_sheet(data) dbook.add_sheet(data)
def detect(stream): def detect(stream):
"""Returns True if given stream is valid YAML.""" """Returns True if given stream is valid YAML."""
try: try:
+13 -18
View File
@@ -63,10 +63,9 @@ __author__ = "Jeff Kunce <kuncej@mail.conservation.state.mo.us>"
__all__ = ["Dbf"] __all__ = ["Dbf"]
from . import header from . import header
from . import record from .import record
from utils import INVALID_VALUE from utils import INVALID_VALUE
class Dbf(object): class Dbf(object):
"""DBF accessor. """DBF accessor.
@@ -89,7 +88,7 @@ class Dbf(object):
RecordClass = record.DbfRecord RecordClass = record.DbfRecord
INVALID_VALUE = INVALID_VALUE INVALID_VALUE = INVALID_VALUE
# initialization and creation helpers ## initialization and creation helpers
def __init__(self, f, readOnly=False, new=False, ignoreErrors=False): def __init__(self, f, readOnly=False, new=False, ignoreErrors=False):
"""Initialize instance. """Initialize instance.
@@ -138,7 +137,7 @@ class Dbf(object):
self._new = bool(new) self._new = bool(new)
self._changed = False self._changed = False
# properties ## properties
closed = property(lambda self: self.stream.closed) closed = property(lambda self: self.stream.closed)
recordCount = property(lambda self: self.header.recordCount) recordCount = property(lambda self: self.header.recordCount)
@@ -150,7 +149,6 @@ class Dbf(object):
def ignoreErrors(self, value): def ignoreErrors(self, value):
"""Update `ignoreErrors` flag on the header object and self""" """Update `ignoreErrors` flag on the header object and self"""
self.header.ignoreErrors = self._ignore_errors = bool(value) self.header.ignoreErrors = self._ignore_errors = bool(value)
ignoreErrors = property( ignoreErrors = property(
lambda self: self._ignore_errors, lambda self: self._ignore_errors,
ignoreErrors, ignoreErrors,
@@ -161,7 +159,7 @@ class Dbf(object):
""") """)
# protected methods ## protected methods
def _fixIndex(self, index): def _fixIndex(self, index):
"""Return fixed index. """Return fixed index.
@@ -187,7 +185,7 @@ class Dbf(object):
raise IndexError("Record index out of range") raise IndexError("Record index out of range")
return index return index
# iterface methods ## iterface methods
def close(self): def close(self):
self.flush() self.flush()
@@ -230,7 +228,7 @@ class Dbf(object):
raise TypeError("At least one record was added, " raise TypeError("At least one record was added, "
"structure can't be changed") "structure can't be changed")
# 'magic' methods (representation and sequence interface) ## 'magic' methods (representation and sequence interface)
def __repr__(self): def __repr__(self):
return "Dbf stream '%s'\n" % self.stream + repr(self.header) return "Dbf stream '%s'\n" % self.stream + repr(self.header)
@@ -250,20 +248,19 @@ class Dbf(object):
self._changed = True self._changed = True
self._new = False self._new = False
# def __del__(self): #def __del__(self):
# """Flush stream upon deletion of the object.""" # """Flush stream upon deletion of the object."""
# self.flush() # self.flush()
def demo_read(filename): def demoRead(filename):
_dbf = Dbf(filename, True) _dbf = Dbf(filename, True)
for _rec in _dbf: for _rec in _dbf:
print print
print(repr(_rec)) print(repr(_rec))
_dbf.close() _dbf.close()
def demoCreate(filename):
def demo_create(filename):
_dbf = Dbf(filename, new=True) _dbf = Dbf(filename, new=True)
_dbf.addField( _dbf.addField(
("NAME", "C", 15), ("NAME", "C", 15),
@@ -286,12 +283,10 @@ def demo_create(filename):
print(repr(_dbf)) print(repr(_dbf))
_dbf.close() _dbf.close()
if (__name__=='__main__'):
if __name__ == '__main__':
import sys import sys
_name = len(sys.argv) > 1 and sys.argv[1] or "county.dbf" _name = len(sys.argv) > 1 and sys.argv[1] or "county.dbf"
demo_create(_name) demoCreate(_name)
demo_read(_name) demoRead(_name)
# vim: set et sw=4 sts=4 : # vim: set et sw=4 sts=4 :
+15 -16
View File
@@ -29,7 +29,6 @@ from fields import *
from header import * from header import *
from record import * from record import *
class _FieldDefinition(object): class _FieldDefinition(object):
"""Field definition. """Field definition.
@@ -152,28 +151,28 @@ class dbf_new(object):
_dbfh.write(stream) _dbfh.write(stream)
if __name__ == '__main__': if (__name__=='__main__'):
# create a new DBF-File # create a new DBF-File
dbfn = dbf_new() dbfn=dbf_new()
dbfn.add_field("name", 'C', 80) dbfn.add_field("name",'C',80)
dbfn.add_field("price", 'N', 10, 2) dbfn.add_field("price",'N',10,2)
dbfn.add_field("date", 'D', 8) dbfn.add_field("date",'D',8)
dbfn.write("tst.dbf") dbfn.write("tst.dbf")
# test new dbf # test new dbf
print "*** created tst.dbf: ***" print "*** created tst.dbf: ***"
dbft = Dbf('tst.dbf', readOnly=0) dbft = Dbf('tst.dbf', readOnly=0)
print repr(dbft) print repr(dbft)
# add a record # add a record
rec = DbfRecord(dbft) rec=DbfRecord(dbft)
rec['name'] = 'something' rec['name']='something'
rec['price'] = 10.5 rec['price']=10.5
rec['date'] = (2000, 1, 12) rec['date']=(2000,1,12)
rec.store() rec.store()
# add another record # add another record
rec = DbfRecord(dbft) rec=DbfRecord(dbft)
rec['name'] = 'foo and bar' rec['name']='foo and bar'
rec['price'] = 12234 rec['price']=12234
rec['date'] = (1992, 7, 15) rec['date']=(1992,7,15)
rec.store() rec.store()
# show the records # show the records
@@ -182,8 +181,8 @@ if __name__ == '__main__':
for i1 in range(len(dbft)): for i1 in range(len(dbft)):
rec = dbft[i1] rec = dbft[i1]
for fldName in dbft.fieldNames: for fldName in dbft.fieldNames:
print '%s:\t %s' % (fldName, rec[fldName]) print '%s:\t %s'%(fldName, rec[fldName])
print print
dbft.close() dbft.close()
# vim: set et sts=4 sw=4 : # vim: set et sts=4 sw=4 :
+11 -16
View File
@@ -66,7 +66,6 @@ from . import header
from . import record from . import record
from .utils import INVALID_VALUE from .utils import INVALID_VALUE
class Dbf(object): class Dbf(object):
"""DBF accessor. """DBF accessor.
@@ -89,7 +88,7 @@ class Dbf(object):
RecordClass = record.DbfRecord RecordClass = record.DbfRecord
INVALID_VALUE = INVALID_VALUE INVALID_VALUE = INVALID_VALUE
# initialization and creation helpers ## initialization and creation helpers
def __init__(self, f, readOnly=False, new=False, ignoreErrors=False): def __init__(self, f, readOnly=False, new=False, ignoreErrors=False):
"""Initialize instance. """Initialize instance.
@@ -138,7 +137,7 @@ class Dbf(object):
self._new = bool(new) self._new = bool(new)
self._changed = False self._changed = False
# properties ## properties
closed = property(lambda self: self.stream.closed) closed = property(lambda self: self.stream.closed)
recordCount = property(lambda self: self.header.recordCount) recordCount = property(lambda self: self.header.recordCount)
@@ -150,7 +149,6 @@ class Dbf(object):
def ignoreErrors(self, value): def ignoreErrors(self, value):
"""Update `ignoreErrors` flag on the header object and self""" """Update `ignoreErrors` flag on the header object and self"""
self.header.ignoreErrors = self._ignore_errors = bool(value) self.header.ignoreErrors = self._ignore_errors = bool(value)
ignoreErrors = property( ignoreErrors = property(
lambda self: self._ignore_errors, lambda self: self._ignore_errors,
ignoreErrors, ignoreErrors,
@@ -161,7 +159,7 @@ class Dbf(object):
""") """)
# protected methods ## protected methods
def _fixIndex(self, index): def _fixIndex(self, index):
"""Return fixed index. """Return fixed index.
@@ -187,7 +185,7 @@ class Dbf(object):
raise IndexError("Record index out of range") raise IndexError("Record index out of range")
return index return index
# iterface methods ## iterface methods
def close(self): def close(self):
self.flush() self.flush()
@@ -231,7 +229,7 @@ class Dbf(object):
raise TypeError("At least one record was added, " raise TypeError("At least one record was added, "
"structure can't be changed") "structure can't be changed")
# 'magic' methods (representation and sequence interface) ## 'magic' methods (representation and sequence interface)
def __repr__(self): def __repr__(self):
return "Dbf stream '%s'\n" % self.stream + repr(self.header) return "Dbf stream '%s'\n" % self.stream + repr(self.header)
@@ -251,20 +249,19 @@ class Dbf(object):
self._changed = True self._changed = True
self._new = False self._new = False
# def __del__(self): #def __del__(self):
# """Flush stream upon deletion of the object.""" # """Flush stream upon deletion of the object."""
# self.flush() # self.flush()
def demo_read(filename): def demoRead(filename):
_dbf = Dbf(filename, True) _dbf = Dbf(filename, True)
for _rec in _dbf: for _rec in _dbf:
print() print()
print(repr(_rec)) print(repr(_rec))
_dbf.close() _dbf.close()
def demoCreate(filename):
def demo_create(filename):
_dbf = Dbf(filename, new=True) _dbf = Dbf(filename, new=True)
_dbf.addField( _dbf.addField(
("NAME", "C", 15), ("NAME", "C", 15),
@@ -287,12 +284,10 @@ def demo_create(filename):
print(repr(_dbf)) print(repr(_dbf))
_dbf.close() _dbf.close()
if (__name__=='__main__'):
if __name__ == '__main__':
import sys import sys
_name = len(sys.argv) > 1 and sys.argv[1] or "county.dbf" _name = len(sys.argv) > 1 and sys.argv[1] or "county.dbf"
demo_create(_name) demoCreate(_name)
demo_read(_name) demoRead(_name)
# vim: set et sw=4 sts=4 : # vim: set et sw=4 sts=4 :
+14 -15
View File
@@ -29,7 +29,6 @@ from .fields import *
from .header import * from .header import *
from .record import * from .record import *
class _FieldDefinition(object): class _FieldDefinition(object):
"""Field definition. """Field definition.
@@ -146,28 +145,28 @@ class dbf_new(object):
_dbfStream.close() _dbfStream.close()
if __name__ == '__main__': if (__name__=='__main__'):
# create a new DBF-File # create a new DBF-File
dbfn = dbf_new() dbfn=dbf_new()
dbfn.add_field("name", 'C', 80) dbfn.add_field("name",'C',80)
dbfn.add_field("price", 'N', 10, 2) dbfn.add_field("price",'N',10,2)
dbfn.add_field("date", 'D', 8) dbfn.add_field("date",'D',8)
dbfn.write("tst.dbf") dbfn.write("tst.dbf")
# test new dbf # test new dbf
print("*** created tst.dbf: ***") print("*** created tst.dbf: ***")
dbft = Dbf('tst.dbf', readOnly=0) dbft = Dbf('tst.dbf', readOnly=0)
print(repr(dbft)) print(repr(dbft))
# add a record # add a record
rec = DbfRecord(dbft) rec=DbfRecord(dbft)
rec['name'] = 'something' rec['name']='something'
rec['price'] = 10.5 rec['price']=10.5
rec['date'] = (2000, 1, 12) rec['date']=(2000,1,12)
rec.store() rec.store()
# add another record # add another record
rec = DbfRecord(dbft) rec=DbfRecord(dbft)
rec['name'] = 'foo and bar' rec['name']='foo and bar'
rec['price'] = 12234 rec['price']=12234
rec['date'] = (1992, 7, 15) rec['date']=(1992,7,15)
rec.store() rec.store()
# show the records # show the records
@@ -176,7 +175,7 @@ if __name__ == '__main__':
for i1 in range(len(dbft)): for i1 in range(len(dbft)):
rec = dbft[i1] rec = dbft[i1]
for fldName in dbft.fieldNames: for fldName in dbft.fieldNames:
print('%s:\t %s' % (fldName, rec[fldName])) print('%s:\t %s'%(fldName, rec[fldName]))
print() print()
dbft.close() dbft.close()
+4 -2
View File
@@ -71,8 +71,10 @@ class element:
for key, value in kwargs.iteritems( ): for key, value in kwargs.iteritems( ):
if value is not None: # when value is None that means stuff like <... checked> if value is not None: # when value is None that means stuff like <... checked>
key = key.strip('_') # strip this so class_ will mean class, etc. key = key.strip('_') # strip this so class_ will mean class, etc.
if key in ['http_equiv', 'accept_charset']: if key == 'http_equiv': # special cases, maybe change _ to - overall?
key.replace('_','-') key = 'http-equiv'
elif key == 'accept_charset':
key = 'accept-charset'
out = u"%s %s=\"%s\"" % ( out, key, escape( value ) ) out = u"%s %s=\"%s\"" % ( out, key, escape( value ) )
else: else:
out = u"%s %s" % ( out, key ) out = u"%s %s" % ( out, key )
+2 -2
View File
@@ -4,7 +4,7 @@ import sys
from antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException from antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException
import struct import struct
import ExcelFormulaParser import ExcelFormulaParser
from re import compile as recompile, match, UNICODE, IGNORECASE, VERBOSE from re import compile as recompile, match, LOCALE, UNICODE, IGNORECASE, VERBOSE
int_const_pattern = r"\d+\b" int_const_pattern = r"\d+\b"
@@ -51,7 +51,7 @@ pattern_type_tuples = (
_re = recompile( _re = recompile(
'(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')', '(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')',
VERBOSE+IGNORECASE) VERBOSE+LOCALE+IGNORECASE)
_toktype = [None] + [i[1] for i in pattern_type_tuples] _toktype = [None] + [i[1] for i in pattern_type_tuples]
# need dummy at start because re.MatchObject.lastindex counts from 1 # need dummy at start because re.MatchObject.lastindex counts from 1
+2 -2
View File
@@ -2,7 +2,7 @@ import sys
from .antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException from .antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException
import struct import struct
from . import ExcelFormulaParser from . import ExcelFormulaParser
from re import compile as recompile, match, UNICODE, IGNORECASE, VERBOSE from re import compile as recompile, match, LOCALE, UNICODE, IGNORECASE, VERBOSE
int_const_pattern = r"\d+\b" int_const_pattern = r"\d+\b"
@@ -49,7 +49,7 @@ pattern_type_tuples = (
_re = recompile( _re = recompile(
'(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')', '(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')',
VERBOSE+IGNORECASE) VERBOSE+LOCALE+IGNORECASE)
_toktype = [None] + [i[1] for i in pattern_type_tuples] _toktype = [None] + [i[1] for i in pattern_type_tuples]
# need dummy at start because re.MatchObject.lastindex counts from 1 # need dummy at start because re.MatchObject.lastindex counts from 1
+10 -9
View File
@@ -1,16 +1,15 @@
__all__ = ['Composer', 'ComposerError'] __all__ = ['Composer', 'ComposerError']
from error import MarkedYAMLError from error import MarkedYAMLError
from events import StreamEndEvent, StreamStartEvent, AliasEvent, SequenceEndEvent, SequenceStartEvent, MappingEndEvent,\ from events import *
MappingStartEvent, ScalarEvent from nodes import *
from nodes import MappingNode, ScalarNode, SequenceNode
class ComposerError(MarkedYAMLError): class ComposerError(MarkedYAMLError):
pass pass
class Composer(object): class Composer(object):
def __init__(self): def __init__(self):
self.anchors = {} self.anchors = {}
@@ -71,7 +70,8 @@ class Composer(object):
return self.anchors[anchor] return self.anchors[anchor]
event = self.peek_event() event = self.peek_event()
anchor = event.anchor anchor = event.anchor
if anchor is not None and anchor in self.anchors: if anchor is not None:
if anchor in self.anchors:
raise ComposerError("found duplicate anchor %r; first occurence" raise ComposerError("found duplicate anchor %r; first occurence"
% anchor.encode('utf-8'), self.anchors[anchor].start_mark, % anchor.encode('utf-8'), self.anchors[anchor].start_mark,
"second occurence", event.start_mark) "second occurence", event.start_mark)
@@ -125,14 +125,15 @@ class Composer(object):
if anchor is not None: if anchor is not None:
self.anchors[anchor] = node self.anchors[anchor] = node
while not self.check_event(MappingEndEvent): while not self.check_event(MappingEndEvent):
# key_event = self.peek_event() #key_event = self.peek_event()
item_key = self.compose_node(node, None) item_key = self.compose_node(node, None)
# if item_key in node.value: #if item_key in node.value:
# raise ComposerError("while composing a mapping", start_event.start_mark, # raise ComposerError("while composing a mapping", start_event.start_mark,
# "found duplicate key", key_event.start_mark) # "found duplicate key", key_event.start_mark)
item_value = self.compose_node(node, item_key) item_value = self.compose_node(node, item_key)
# node.value[item_key] = item_value #node.value[item_key] = item_value
node.value.append((item_key, item_value)) node.value.append((item_key, item_value))
end_event = self.get_event() end_event = self.get_event()
node.end_mark = end_event.end_mark node.end_mark = end_event.end_mark
return node return node
+20 -27
View File
@@ -1,3 +1,4 @@
__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor', __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
'ConstructorError'] 'ConstructorError']
@@ -11,17 +12,13 @@ try:
except NameError: except NameError:
from sets import Set as set from sets import Set as set
import binascii import binascii, re, sys, types
import re
import sys
import types
class ConstructorError(MarkedYAMLError): class ConstructorError(MarkedYAMLError):
pass pass
class BaseConstructor(object): class BaseConstructor(object):
yaml_constructors = {} yaml_constructors = {}
yaml_multi_constructors = {} yaml_multi_constructors = {}
@@ -158,18 +155,16 @@ class BaseConstructor(object):
if not 'yaml_constructors' in cls.__dict__: if not 'yaml_constructors' in cls.__dict__:
cls.yaml_constructors = cls.yaml_constructors.copy() cls.yaml_constructors = cls.yaml_constructors.copy()
cls.yaml_constructors[tag] = constructor cls.yaml_constructors[tag] = constructor
add_constructor = classmethod(add_constructor) add_constructor = classmethod(add_constructor)
def add_multi_constructor(cls, tag_prefix, multi_constructor): def add_multi_constructor(cls, tag_prefix, multi_constructor):
if not 'yaml_multi_constructors' in cls.__dict__: if not 'yaml_multi_constructors' in cls.__dict__:
cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy() cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
cls.yaml_multi_constructors[tag_prefix] = multi_constructor cls.yaml_multi_constructors[tag_prefix] = multi_constructor
add_multi_constructor = classmethod(add_multi_constructor) add_multi_constructor = classmethod(add_multi_constructor)
class SafeConstructor(BaseConstructor): class SafeConstructor(BaseConstructor):
def construct_scalar(self, node): def construct_scalar(self, node):
if isinstance(node, MappingNode): if isinstance(node, MappingNode):
for key_node, value_node in node.value: for key_node, value_node in node.value:
@@ -245,27 +240,27 @@ class SafeConstructor(BaseConstructor):
if value == '0': if value == '0':
return 0 return 0
elif value.startswith('0b'): elif value.startswith('0b'):
return sign * int(value[2:], 2) return sign*int(value[2:], 2)
elif value.startswith('0x'): elif value.startswith('0x'):
return sign * int(value[2:], 16) return sign*int(value[2:], 16)
elif value[0] == '0': elif value[0] == '0':
return sign * int(value, 8) return sign*int(value, 8)
elif ':' in value: elif ':' in value:
digits = [int(part) for part in value.split(':')] digits = [int(part) for part in value.split(':')]
digits.reverse() digits.reverse()
base = 1 base = 1
value = 0 value = 0
for digit in digits: for digit in digits:
value += digit * base value += digit*base
base *= 60 base *= 60
return sign * value return sign*value
else: else:
return sign * int(value) return sign*int(value)
inf_value = 1e300 inf_value = 1e300
while inf_value != inf_value * inf_value: while inf_value != inf_value*inf_value:
inf_value *= inf_value inf_value *= inf_value
nan_value = -inf_value / inf_value # Trying to make a quiet NaN (like C99). nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
def construct_yaml_float(self, node): def construct_yaml_float(self, node):
value = str(self.construct_scalar(node)) value = str(self.construct_scalar(node))
@@ -276,7 +271,7 @@ class SafeConstructor(BaseConstructor):
if value[0] in '+-': if value[0] in '+-':
value = value[1:] value = value[1:]
if value == '.inf': if value == '.inf':
return sign * self.inf_value return sign*self.inf_value
elif value == '.nan': elif value == '.nan':
return self.nan_value return self.nan_value
elif ':' in value: elif ':' in value:
@@ -285,11 +280,11 @@ class SafeConstructor(BaseConstructor):
base = 1 base = 1
value = 0.0 value = 0.0
for digit in digits: for digit in digits:
value += digit * base value += digit*base
base *= 60 base *= 60
return sign * value return sign*value
else: else:
return sign * float(value) return sign*float(value)
def construct_yaml_binary(self, node): def construct_yaml_binary(self, node):
value = self.construct_scalar(node) value = self.construct_scalar(node)
@@ -423,7 +418,6 @@ class SafeConstructor(BaseConstructor):
"could not determine a constructor for the tag %r" % node.tag.encode('utf-8'), "could not determine a constructor for the tag %r" % node.tag.encode('utf-8'),
node.start_mark) node.start_mark)
SafeConstructor.add_constructor( SafeConstructor.add_constructor(
u'tag:yaml.org,2002:null', u'tag:yaml.org,2002:null',
SafeConstructor.construct_yaml_null) SafeConstructor.construct_yaml_null)
@@ -475,8 +469,8 @@ SafeConstructor.add_constructor(
SafeConstructor.add_constructor(None, SafeConstructor.add_constructor(None,
SafeConstructor.construct_undefined) SafeConstructor.construct_undefined)
class Constructor(SafeConstructor): class Constructor(SafeConstructor):
def construct_python_str(self, node): def construct_python_str(self, node):
return self.construct_scalar(node).encode('utf-8') return self.construct_scalar(node).encode('utf-8')
@@ -509,7 +503,7 @@ class Constructor(SafeConstructor):
"expected non-empty name appended to the tag", mark) "expected non-empty name appended to the tag", mark)
if u'.' in name: if u'.' in name:
# Python 2.4 only # Python 2.4 only
# module_name, object_name = name.rsplit('.', 1) #module_name, object_name = name.rsplit('.', 1)
items = name.split('.') items = name.split('.')
object_name = items.pop() object_name = items.pop()
module_name = '.'.join(items) module_name = '.'.join(items)
@@ -544,8 +538,7 @@ class Constructor(SafeConstructor):
node.start_mark) node.start_mark)
return self.find_python_module(suffix, node.start_mark) return self.find_python_module(suffix, node.start_mark)
class classobj: class classobj: pass
pass
def make_python_instance(self, suffix, node, def make_python_instance(self, suffix, node,
args=None, kwds=None, newobj=False): args=None, kwds=None, newobj=False):
@@ -625,7 +618,6 @@ class Constructor(SafeConstructor):
def construct_python_object_new(self, suffix, node): def construct_python_object_new(self, suffix, node):
return self.construct_python_object_apply(suffix, node, newobj=True) return self.construct_python_object_apply(suffix, node, newobj=True)
Constructor.add_constructor( Constructor.add_constructor(
u'tag:yaml.org,2002:python/none', u'tag:yaml.org,2002:python/none',
Constructor.construct_yaml_null) Constructor.construct_yaml_null)
@@ -689,3 +681,4 @@ Constructor.add_multi_constructor(
Constructor.add_multi_constructor( Constructor.add_multi_constructor(
u'tag:yaml.org,2002:python/object/new:', u'tag:yaml.org,2002:python/object/new:',
Constructor.construct_python_object_new) Constructor.construct_python_object_new)
+6 -5
View File
@@ -1,15 +1,15 @@
__all__ = ['Composer', 'ComposerError'] __all__ = ['Composer', 'ComposerError']
from .error import MarkedYAMLError from .error import MarkedYAMLError
from .events import * from .events import *
from .nodes import * from .nodes import *
class ComposerError(MarkedYAMLError): class ComposerError(MarkedYAMLError):
pass pass
class Composer: class Composer:
def __init__(self): def __init__(self):
self.anchors = {} self.anchors = {}
@@ -125,14 +125,15 @@ class Composer:
if anchor is not None: if anchor is not None:
self.anchors[anchor] = node self.anchors[anchor] = node
while not self.check_event(MappingEndEvent): while not self.check_event(MappingEndEvent):
# key_event = self.peek_event() #key_event = self.peek_event()
item_key = self.compose_node(node, None) item_key = self.compose_node(node, None)
# if item_key in node.value: #if item_key in node.value:
# raise ComposerError("while composing a mapping", start_event.start_mark, # raise ComposerError("while composing a mapping", start_event.start_mark,
# "found duplicate key", key_event.start_mark) # "found duplicate key", key_event.start_mark)
item_value = self.compose_node(node, item_key) item_value = self.compose_node(node, item_key)
# node.value[item_key] = item_value #node.value[item_key] = item_value
node.value.append((item_key, item_value)) node.value.append((item_key, item_value))
end_event = self.get_event() end_event = self.get_event()
node.end_mark = end_event.end_mark node.end_mark = end_event.end_mark
return node return node
+1
View File
@@ -683,3 +683,4 @@ Constructor.add_multi_constructor(
Constructor.add_multi_constructor( Constructor.add_multi_constructor(
'tag:yaml.org,2002:python/object/new:', 'tag:yaml.org,2002:python/object/new:',
Constructor.construct_python_object_new) Constructor.construct_python_object_new)
+69 -46
View File
@@ -6,14 +6,14 @@ import json
import unittest import unittest
import sys import sys
import os import os
import datetime
import tablib import tablib
from tablib.compat import markup, unicode, is_py3 from tablib.compat import markup, unicode, is_py3
from tablib.core import Row from tablib.core import Row
class TablibTestCase(unittest.TestCase): class TablibTestCase(unittest.TestCase):
"""Tablib test cases.""" """Tablib test cases."""
@@ -35,10 +35,12 @@ class TablibTestCase(unittest.TestCase):
self.founders.append(self.george) self.founders.append(self.george)
self.founders.append(self.tom) self.founders.append(self.tom)
def tearDown(self): def tearDown(self):
"""Teardown.""" """Teardown."""
pass pass
def test_empty_append(self): def test_empty_append(self):
"""Verify append() correctly adds tuple with no headers.""" """Verify append() correctly adds tuple with no headers."""
new_row = (1, 2, 3) new_row = (1, 2, 3)
@@ -48,6 +50,7 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue(data.width == len(new_row)) self.assertTrue(data.width == len(new_row))
self.assertTrue(data[0] == new_row) self.assertTrue(data[0] == new_row)
def test_empty_append_with_headers(self): def test_empty_append_with_headers(self):
"""Verify append() correctly detects mismatch of number of """Verify append() correctly detects mismatch of number of
headers and data. headers and data.
@@ -69,6 +72,7 @@ class TablibTestCase(unittest.TestCase):
self.assertRaises(tablib.InvalidDimensions, set_header_callable) self.assertRaises(tablib.InvalidDimensions, set_header_callable)
def test_add_column(self): def test_add_column(self):
"""Verify adding column works with/without headers.""" """Verify adding column works with/without headers."""
@@ -89,6 +93,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(data['age'], new_col) self.assertEqual(data['age'], new_col)
def test_add_column_no_data_no_headers(self): def test_add_column_no_data_no_headers(self):
"""Verify adding new column with no headers.""" """Verify adding new column with no headers."""
@@ -100,6 +105,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(data.width, 1) self.assertEqual(data.width, 1)
self.assertEqual(data.height, len(new_col)) self.assertEqual(data.height, len(new_col))
def test_add_column_with_header_ignored(self): def test_add_column_with_header_ignored(self):
"""Verify append_col() ignores the header if data.headers has """Verify append_col() ignores the header if data.headers has
not previously been set not previously been set
@@ -114,13 +120,14 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(data.height, len(new_col)) self.assertEqual(data.height, len(new_col))
self.assertEqual(data.headers, None) self.assertEqual(data.headers, None)
def test_add_column_with_header_and_headers_only_exist(self): def test_add_column_with_header_and_headers_only_exist(self):
"""Verify append_col() with header correctly detects mismatch when """Verify append_col() with header correctly detects mismatch when
headers exist but there is no existing row data headers exist but there is no existing row data
""" """
data.headers = ['first_name'] data.headers = ['first_name']
# no data #no data
new_col = ('allen') new_col = ('allen')
@@ -129,6 +136,7 @@ class TablibTestCase(unittest.TestCase):
self.assertRaises(tablib.InvalidDimensions, append_col_callable) self.assertRaises(tablib.InvalidDimensions, append_col_callable)
def test_add_column_with_header_and_data_exists(self): def test_add_column_with_header_and_data_exists(self):
"""Verify append_col() works when headers and rows exists""" """Verify append_col() works when headers and rows exists"""
@@ -144,6 +152,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(data['age'], new_col) self.assertEqual(data['age'], new_col)
self.assertEqual(len(data.headers), len(self.headers) + 1) self.assertEqual(len(data.headers), len(self.headers) + 1)
def test_add_callable_column(self): def test_add_callable_column(self):
"""Verify adding column with values specified as callable.""" """Verify adding column with values specified as callable."""
@@ -151,6 +160,7 @@ class TablibTestCase(unittest.TestCase):
self.founders.append_col(new_col, header='first_again') self.founders.append_col(new_col, header='first_again')
def test_header_slicing(self): def test_header_slicing(self):
"""Verify slicing by headers.""" """Verify slicing by headers."""
@@ -163,6 +173,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(self.founders['gpa'], self.assertEqual(self.founders['gpa'],
[self.john[2], self.george[2], self.tom[2]]) [self.john[2], self.george[2], self.tom[2]])
def test_get_col(self): def test_get_col(self):
"""Verify getting columns by index""" """Verify getting columns by index"""
@@ -178,6 +189,7 @@ class TablibTestCase(unittest.TestCase):
self.founders.get_col(list(self.headers).index('gpa')), self.founders.get_col(list(self.headers).index('gpa')),
[self.john[2], self.george[2], self.tom[2]]) [self.john[2], self.george[2], self.tom[2]])
def test_data_slicing(self): def test_data_slicing(self):
"""Verify slicing by data.""" """Verify slicing by data."""
@@ -194,6 +206,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(self.founders[1:3], [self.george, self.tom]) self.assertEqual(self.founders[1:3], [self.george, self.tom])
self.assertEqual(self.founders[2:], [self.tom]) self.assertEqual(self.founders[2:], [self.tom])
def test_row_slicing(self): def test_row_slicing(self):
"""Verify Row's __getslice__ method. Issue #184.""" """Verify Row's __getslice__ method. Issue #184."""
@@ -205,6 +218,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(john[0:2], list(self.john[0:2])) self.assertEqual(john[0:2], list(self.john[0:2]))
self.assertEqual(john[0:-1], list(self.john[0:-1])) self.assertEqual(john[0:-1], list(self.john[0:-1]))
def test_delete(self): def test_delete(self):
"""Verify deleting from dataset works.""" """Verify deleting from dataset works."""
@@ -244,6 +258,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(csv, self.founders.csv) self.assertEqual(csv, self.founders.csv)
def test_tsv_export(self): def test_tsv_export(self):
"""Verify exporting dataset object as TSV.""" """Verify exporting dataset object as TSV."""
@@ -261,6 +276,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(tsv, self.founders.tsv) self.assertEqual(tsv, self.founders.tsv)
def test_html_export(self): def test_html_export(self):
"""HTML export""" """HTML export"""
@@ -272,6 +288,7 @@ class TablibTestCase(unittest.TestCase):
html.thead.close() html.thead.close()
for founder in self.founders: for founder in self.founders:
html.tr(markup.oneliner.td(founder)) html.tr(markup.oneliner.td(founder))
html.table.close() html.table.close()
@@ -279,6 +296,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(html, self.founders.html) self.assertEqual(html, self.founders.html)
def test_html_export_none_value(self): def test_html_export_none_value(self):
"""HTML export""" """HTML export"""
@@ -286,10 +304,10 @@ class TablibTestCase(unittest.TestCase):
html.table.open() html.table.open()
html.thead.open() html.thead.open()
html.tr(markup.oneliner.th(['foo', '', 'bar'])) html.tr(markup.oneliner.th(['foo','', 'bar']))
html.thead.close() html.thead.close()
html.tr(markup.oneliner.td(['foo', '', 'bar'])) html.tr(markup.oneliner.td(['foo','', 'bar']))
html.table.close() html.table.close()
html = str(html) html = str(html)
@@ -299,6 +317,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(html, d.html) self.assertEqual(html, d.html)
def test_latex_export(self): def test_latex_export(self):
"""LaTeX export""" """LaTeX export"""
@@ -322,14 +341,17 @@ class TablibTestCase(unittest.TestCase):
output = self.founders.latex output = self.founders.latex
self.assertEqual(output, expected) self.assertEqual(output, expected)
def test_latex_export_empty_dataset(self): def test_latex_export_empty_dataset(self):
self.assertTrue(tablib.Dataset().latex is not None) self.assertTrue(tablib.Dataset().latex is not None)
def test_latex_export_no_headers(self): def test_latex_export_no_headers(self):
d = tablib.Dataset() d = tablib.Dataset()
d.append(('one', 'two', 'three')) d.append(('one', 'two', 'three'))
self.assertTrue('one' in d.latex) self.assertTrue('one' in d.latex)
def test_latex_export_caption(self): def test_latex_export_caption(self):
d = tablib.Dataset() d = tablib.Dataset()
d.append(('one', 'two', 'three')) d.append(('one', 'two', 'three'))
@@ -338,6 +360,7 @@ class TablibTestCase(unittest.TestCase):
d.title = 'Title' d.title = 'Title'
self.assertTrue('\\caption{Title}' in d.latex) self.assertTrue('\\caption{Title}' in d.latex)
def test_latex_export_none_values(self): def test_latex_export_none_values(self):
headers = ['foo', None, 'bar'] headers = ['foo', None, 'bar']
d = tablib.Dataset(['foo', None, 'bar'], headers=headers) d = tablib.Dataset(['foo', None, 'bar'], headers=headers)
@@ -345,6 +368,7 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue('foo' in output) self.assertTrue('foo' in output)
self.assertFalse('None' in output) self.assertFalse('None' in output)
def test_latex_escaping(self): def test_latex_escaping(self):
d = tablib.Dataset(['~', '^']) d = tablib.Dataset(['~', '^'])
output = d.latex output = d.latex
@@ -354,15 +378,6 @@ class TablibTestCase(unittest.TestCase):
self.assertFalse('^' in output) self.assertFalse('^' in output)
self.assertTrue('textasciicircum' in output) self.assertTrue('textasciicircum' in output)
def test_str_no_columns(self):
d = tablib.Dataset(['a', 1], ['b', 2], ['c', 3])
output = '%s' % d
self.assertEqual(output.splitlines(), [
'a|1',
'b|2',
'c|3'
])
def test_unicode_append(self): def test_unicode_append(self):
"""Passes in a single unicode character and exports.""" """Passes in a single unicode character and exports."""
@@ -370,7 +385,8 @@ class TablibTestCase(unittest.TestCase):
if is_py3: if is_py3:
new_row = ('å', 'é') new_row = ('å', 'é')
else: else:
exec ("new_row = (u'å', u'é')") exec("new_row = (u'å', u'é')")
data.append(new_row) data.append(new_row)
@@ -384,25 +400,6 @@ class TablibTestCase(unittest.TestCase):
data.html data.html
data.latex data.latex
def test_datetime_append(self):
"""Passes in a single datetime and a single date and exports."""
new_row = (
datetime.datetime.now(),
datetime.datetime.today(),
)
data.append(new_row)
data.json
data.yaml
data.csv
data.tsv
data.xls
data.xlsx
data.ods
data.html
data.latex
def test_book_export_no_exceptions(self): def test_book_export_no_exceptions(self):
"""Test that various exports don't error out.""" """Test that various exports don't error out."""
@@ -415,7 +412,7 @@ class TablibTestCase(unittest.TestCase):
book.xls book.xls
book.xlsx book.xlsx
book.ods book.ods
book.html
def test_json_import_set(self): def test_json_import_set(self):
"""Generate and import JSON set serialization.""" """Generate and import JSON set serialization."""
@@ -429,6 +426,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(json.loads(_json), json.loads(data.json)) self.assertEqual(json.loads(_json), json.loads(data.json))
def test_json_import_book(self): def test_json_import_book(self):
"""Generate and import JSON book serialization.""" """Generate and import JSON book serialization."""
data.append(self.john) data.append(self.john)
@@ -442,6 +440,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(json.loads(_json), json.loads(book.json)) self.assertEqual(json.loads(_json), json.loads(book.json))
def test_yaml_import_set(self): def test_yaml_import_set(self):
"""Generate and import YAML set serialization.""" """Generate and import YAML set serialization."""
data.append(self.john) data.append(self.john)
@@ -454,6 +453,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(_yaml, data.yaml) self.assertEqual(_yaml, data.yaml)
def test_yaml_import_book(self): def test_yaml_import_book(self):
"""Generate and import YAML book serialization.""" """Generate and import YAML book serialization."""
data.append(self.john) data.append(self.john)
@@ -467,6 +467,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(_yaml, book.yaml) self.assertEqual(_yaml, book.yaml)
def test_csv_import_set(self): def test_csv_import_set(self):
"""Generate and import CSV set serialization.""" """Generate and import CSV set serialization."""
data.append(self.john) data.append(self.john)
@@ -517,6 +518,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(_csv, data.get_csv(delimiter=';')) self.assertEqual(_csv, data.get_csv(delimiter=';'))
def test_csv_import_set_with_newlines(self): def test_csv_import_set_with_newlines(self):
"""Generate and import CSV set serialization when row values have """Generate and import CSV set serialization when row values have
newlines.""" newlines."""
@@ -531,6 +533,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(_csv, data.csv) self.assertEqual(_csv, data.csv)
def test_tsv_import_set(self): def test_tsv_import_set(self):
"""Generate and import TSV set serialization.""" """Generate and import TSV set serialization."""
data.append(self.john) data.append(self.john)
@@ -543,6 +546,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(_tsv, data.tsv) self.assertEqual(_tsv, data.tsv)
def test_dbf_import_set(self): def test_dbf_import_set(self):
data.append(self.john) data.append(self.john)
data.append(self.george) data.append(self.george)
@@ -551,7 +555,7 @@ class TablibTestCase(unittest.TestCase):
_dbf = data.dbf _dbf = data.dbf
data.dbf = _dbf data.dbf = _dbf
# self.assertEqual(_dbf, data.dbf) #self.assertEqual(_dbf, data.dbf)
try: try:
self.assertEqual(_dbf, data.dbf) self.assertEqual(_dbf, data.dbf)
except AssertionError: except AssertionError:
@@ -592,8 +596,8 @@ class TablibTestCase(unittest.TestCase):
if is_py3: if is_py3:
# If in python3, decode regression string to binary. # If in python3, decode regression string to binary.
# _regression_dbf = bytes(_regression_dbf, 'utf-8') #_regression_dbf = bytes(_regression_dbf, 'utf-8')
# _regression_dbf = _regression_dbf.replace(b'\n', b'\r') #_regression_dbf = _regression_dbf.replace(b'\n', b'\r')
pass pass
try: try:
@@ -602,7 +606,7 @@ class TablibTestCase(unittest.TestCase):
index = 0 index = 0
found_so_far = '' found_so_far = ''
for reg_char, data_char in zip(_regression_dbf, data.dbf): for reg_char, data_char in zip(_regression_dbf, data.dbf):
# found_so_far += chr(data_char) #found_so_far += chr(data_char)
if reg_char != data_char and index not in [1, 2, 3]: if reg_char != data_char and index not in [1, 2, 3]:
raise AssertionError( raise AssertionError(
'Failing at char %s: %s vs %s (found %s)' % ( 'Failing at char %s: %s vs %s (found %s)' % (
@@ -660,6 +664,7 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue(tablib.formats.csv.detect(_csv)) self.assertTrue(tablib.formats.csv.detect(_csv))
self.assertFalse(tablib.formats.csv.detect(_bunk)) self.assertFalse(tablib.formats.csv.detect(_bunk))
def test_tsv_format_detect(self): def test_tsv_format_detect(self):
"""Test TSV format detection.""" """Test TSV format detection."""
@@ -675,6 +680,7 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue(tablib.formats.tsv.detect(_tsv)) self.assertTrue(tablib.formats.tsv.detect(_tsv))
self.assertFalse(tablib.formats.tsv.detect(_bunk)) self.assertFalse(tablib.formats.tsv.detect(_bunk))
def test_json_format_detect(self): def test_json_format_detect(self):
"""Test JSON format detection.""" """Test JSON format detection."""
@@ -686,6 +692,7 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue(tablib.formats.json.detect(_json)) self.assertTrue(tablib.formats.json.detect(_json))
self.assertFalse(tablib.formats.json.detect(_bunk)) self.assertFalse(tablib.formats.json.detect(_bunk))
def test_yaml_format_detect(self): def test_yaml_format_detect(self):
"""Test YAML format detection.""" """Test YAML format detection."""
@@ -699,6 +706,7 @@ class TablibTestCase(unittest.TestCase):
self.assertFalse(tablib.formats.yaml.detect(_bunk)) self.assertFalse(tablib.formats.yaml.detect(_bunk))
self.assertFalse(tablib.formats.yaml.detect(_tsv)) self.assertFalse(tablib.formats.yaml.detect(_tsv))
def test_auto_format_detect(self): def test_auto_format_detect(self):
"""Test auto format detection.""" """Test auto format detection."""
@@ -714,6 +722,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(tablib.detect_format(_json), 'json') self.assertEqual(tablib.detect_format(_json), 'json')
self.assertEqual(tablib.detect_format(_bunk), None) self.assertEqual(tablib.detect_format(_bunk), None)
def test_transpose(self): def test_transpose(self):
"""Transpose a dataset.""" """Transpose a dataset."""
@@ -722,11 +731,11 @@ class TablibTestCase(unittest.TestCase):
second_row = transposed_founders[1] second_row = transposed_founders[1]
self.assertEqual(transposed_founders.headers, self.assertEqual(transposed_founders.headers,
["first_name", "John", "George", "Thomas"]) ["first_name","John", "George", "Thomas"])
self.assertEqual(first_row, self.assertEqual(first_row,
("last_name", "Adams", "Washington", "Jefferson")) ("last_name","Adams", "Washington", "Jefferson"))
self.assertEqual(second_row, self.assertEqual(second_row,
("gpa", 90, 67, 50)) ("gpa",90, 67, 50))
def test_transpose_multiple_headers(self): def test_transpose_multiple_headers(self):
@@ -737,6 +746,7 @@ class TablibTestCase(unittest.TestCase):
data.append(('John', 'Tyler', 71)) data.append(('John', 'Tyler', 71))
self.assertEqual(data.transpose().transpose().dict, data.dict) self.assertEqual(data.transpose().transpose().dict, data.dict)
def test_row_stacking(self): def test_row_stacking(self):
"""Row stacking.""" """Row stacking."""
@@ -748,10 +758,12 @@ class TablibTestCase(unittest.TestCase):
row_stacked = self.founders.stack(to_join) row_stacked = self.founders.stack(to_join)
for column in row_stacked.headers: for column in row_stacked.headers:
original_data = self.founders[column] original_data = self.founders[column]
expected_data = original_data + original_data expected_data = original_data + original_data
self.assertEqual(row_stacked[column], expected_data) self.assertEqual(row_stacked[column], expected_data)
def test_column_stacking(self): def test_column_stacking(self):
"""Column stacking""" """Column stacking"""
@@ -763,6 +775,7 @@ class TablibTestCase(unittest.TestCase):
column_stacked = self.founders.stack_cols(to_join) column_stacked = self.founders.stack_cols(to_join)
for index, row in enumerate(column_stacked): for index, row in enumerate(column_stacked):
original_data = self.founders[index] original_data = self.founders[index]
expected_data = original_data + original_data expected_data = original_data + original_data
self.assertEqual(row, expected_data) self.assertEqual(row, expected_data)
@@ -770,6 +783,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(column_stacked[0], self.assertEqual(column_stacked[0],
("John", "Adams", 90, "John", "Adams", 90)) ("John", "Adams", 90, "John", "Adams", 90))
def test_sorting(self): def test_sorting(self):
"""Sort columns.""" """Sort columns."""
@@ -787,6 +801,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(second_row, expected_second) self.assertEqual(second_row, expected_second)
self.assertEqual(third_row, expected_third) self.assertEqual(third_row, expected_third)
def test_remove_duplicates(self): def test_remove_duplicates(self):
"""Unique Rows.""" """Unique Rows."""
@@ -805,6 +820,7 @@ class TablibTestCase(unittest.TestCase):
self.assertEqual(self.founders[2], self.tom) self.assertEqual(self.founders[2], self.tom)
self.assertEqual(self.founders.height, 3) self.assertEqual(self.founders.height, 3)
def test_wipe(self): def test_wipe(self):
"""Purge a dataset.""" """Purge a dataset."""
@@ -821,11 +837,12 @@ class TablibTestCase(unittest.TestCase):
self.assertTrue(data.width == len(new_row)) self.assertTrue(data.width == len(new_row))
self.assertTrue(data[0] == new_row) self.assertTrue(data[0] == new_row)
def test_subset(self): def test_subset(self):
"""Create a subset of a dataset""" """Create a subset of a dataset"""
rows = (0, 2) rows = (0, 2)
columns = ('first_name', 'gpa') columns = ('first_name','gpa')
data.headers = self.headers data.headers = self.headers
@@ -833,13 +850,14 @@ class TablibTestCase(unittest.TestCase):
data.append(self.george) data.append(self.george)
data.append(self.tom) data.append(self.tom)
# Verify data is truncated #Verify data is truncated
subset = data.subset(rows=rows, cols=columns) subset = data.subset(rows=rows, cols=columns)
self.assertEqual(type(subset), tablib.Dataset) self.assertEqual(type(subset), tablib.Dataset)
self.assertEqual(subset.headers, list(columns)) self.assertEqual(subset.headers, list(columns))
self.assertEqual(subset._data[0].list, ['John', 90]) self.assertEqual(subset._data[0].list, ['John', 90])
self.assertEqual(subset._data[1].list, ['Thomas', 50]) self.assertEqual(subset._data[1].list, ['Thomas', 50])
def test_formatters(self): def test_formatters(self):
"""Confirm formatters are being triggered.""" """Confirm formatters are being triggered."""
@@ -859,7 +877,8 @@ class TablibTestCase(unittest.TestCase):
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
data.append(['\xfc', '\xfd']) data.append(['\xfc', '\xfd'])
else: else:
exec ("data.append([u'\xfc', u'\xfd'])") exec("data.append([u'\xfc', u'\xfd'])")
data.csv data.csv
@@ -876,6 +895,7 @@ class TablibTestCase(unittest.TestCase):
csv_first_name = data[headers[0]] csv_first_name = data[headers[0]]
self.assertEqual(orig_first_name, csv_first_name) self.assertEqual(orig_first_name, csv_first_name)
def test_csv_column_delete(self): def test_csv_column_delete(self):
"""Build up a CSV and test deleting a column""" """Build up a CSV and test deleting a column"""
@@ -909,6 +929,7 @@ class TablibTestCase(unittest.TestCase):
self.founders.append(('Old', 'Man', 100500)) self.founders.append(('Old', 'Man', 100500))
self.assertEqual('first_name|last_name |gpa ', unicode(self.founders).split('\n')[0]) self.assertEqual('first_name|last_name |gpa ', unicode(self.founders).split('\n')[0])
def test_databook_add_sheet_accepts_only_dataset_instances(self): def test_databook_add_sheet_accepts_only_dataset_instances(self):
class NotDataset(object): class NotDataset(object):
def append(self, item): def append(self, item):
@@ -919,6 +940,7 @@ class TablibTestCase(unittest.TestCase):
self.assertRaises(tablib.InvalidDatasetType, book.add_sheet, dataset) self.assertRaises(tablib.InvalidDatasetType, book.add_sheet, dataset)
def test_databook_add_sheet_accepts_dataset_subclasses(self): def test_databook_add_sheet_accepts_dataset_subclasses(self):
class DatasetSubclass(tablib.Dataset): class DatasetSubclass(tablib.Dataset):
pass pass
@@ -933,6 +955,7 @@ class TablibTestCase(unittest.TestCase):
except tablib.InvalidDatasetType: except tablib.InvalidDatasetType:
self.fail("Subclass of tablib.Dataset should be accepted by Databook.add_sheet") self.fail("Subclass of tablib.Dataset should be accepted by Databook.add_sheet")
def test_csv_formatter_support_kwargs(self): def test_csv_formatter_support_kwargs(self):
"""Test CSV import and export with formatter configuration.""" """Test CSV import and export with formatter configuration."""
data.append(self.john) data.append(self.john)
+1 -1
View File
@@ -4,7 +4,7 @@
# and then run "tox" from this directory. # and then run "tox" from this directory.
[tox] [tox]
envlist = py26, py27, py32, py33, py34, py35, py36, pypy envlist = py26, py27, py32, py33, py34, pypy
[testenv] [testenv]
commands = python setup.py test commands = python setup.py test