package pyexcel-ods for debian (#13103)

This commit is contained in:
Jean-Baptiste Jaillet 2016-09-07 17:24:03 +02:00
parent 0f9df55aea
commit 05ad7a1717
23 changed files with 567 additions and 8 deletions

View File

@ -1,5 +0,0 @@
all: test
test:
bash test.sh

5
debian/changelog vendored Normal file
View File

@ -0,0 +1,5 @@
pyexcel-ods (0.2.1-1) unstable; urgency=low
* source package automatically created by stdeb 0.8.5
-- JB JAILLET <jbjaillet (at) entrouvert.com> Wed, 07 Sep 2016 17:04:48 +0200

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
7

14
debian/control vendored Normal file
View File

@ -0,0 +1,14 @@
Source: pyexcel-ods
Maintainer: C.W. <wangc_2011 (at) hotmail.com>
Section: python
Priority: optional
Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6.6-3), debhelper (>= 7)
Standards-Version: 3.9.1
Package: python-pyexcel-ods
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python-pyexcel-io
Description: A wrapper library to read, manipulate and write data in ods

1
debian/debhelper-build-stamp vendored Normal file
View File

@ -0,0 +1 @@
python-pyexcel-ods

1
debian/files vendored Normal file
View File

@ -0,0 +1 @@
python-pyexcel-ods_0.2.1-1_all.deb python optional

18
debian/python-pyexcel-ods.debhelper.log vendored Normal file
View File

@ -0,0 +1,18 @@
dh_update_autotools_config
dh_auto_configure
dh_auto_build
dh_auto_test
dh_prep
dh_auto_install
dh_installdocs
dh_installchangelogs
dh_perl
dh_link
dh_strip_nondeterminism
dh_compress
dh_fixperms
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb

View File

@ -0,0 +1,7 @@
# Automatically added by dh_python2:
if which pycompile >/dev/null 2>&1; then
pycompile -p python-pyexcel-ods
fi
# End automatically added section

View File

@ -0,0 +1,12 @@
# Automatically added by dh_python2:
if which pyclean >/dev/null 2>&1; then
pyclean -p python-pyexcel-ods
else
dpkg -L python-pyexcel-ods | grep \.py$ | while read file
do
rm -f "${file}"[co] >/dev/null
done
fi
# End automatically added section

5
debian/python-pyexcel-ods.substvars vendored Normal file
View File

@ -0,0 +1,5 @@
python:Versions=2.7
python:Provides=python2.7-pyexcel-ods
python:Depends=python (>= 2.7), python (<< 2.8), python:any (>= 2.6.6-7~), python-pyexcel-io, python-odfpy
misc:Depends=
misc:Pre-Depends=

View File

@ -0,0 +1,10 @@
Package: python-pyexcel-ods
Source: pyexcel-ods
Version: 0.2.1-1
Architecture: all
Maintainer: C.W. <wangc_2011 (at) hotmail.com>
Installed-Size: 51
Depends: python (>= 2.7), python (<< 2.8), python:any (>= 2.6.6-7~), python-pyexcel-io, python-odfpy
Section: python
Priority: optional
Description: A wrapper library to read, manipulate and write data in ods

View File

@ -0,0 +1,11 @@
382e385f7ba0949729257f8af7c68841 usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/PKG-INFO
a40cddfa02e595f1174d78170b5bfd28 usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/SOURCES.txt
68b329da9893e34099c7d8ad5cb9c940 usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/dependency_links.txt
68b329da9893e34099c7d8ad5cb9c940 usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/not-zip-safe
c7f72e55fb1aa913c0797dc075df4f54 usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/requires.txt
81ac5a55b219b0d802b725d63d59e1ce usr/lib/python2.7/dist-packages/pyexcel_ods-0.2.1.egg-info/top_level.txt
258aa93436a5f28196cec03ef7ddda96 usr/lib/python2.7/dist-packages/pyexcel_ods/__init__.py
aa20c884b58453ed3d2ee2c1076503dd usr/lib/python2.7/dist-packages/pyexcel_ods/converter.py
8c3f599e2b5199be705bf61c0ae5084f usr/lib/python2.7/dist-packages/pyexcel_ods/ods.py
017a36be933b7a49f024ca498f2d715e usr/share/doc/python-pyexcel-ods/changelog.Debian.gz
86d7b20cb2fd529aa828c4c1f97ed140 usr/share/doc/python-pyexcel-ods/changelog.gz

9
debian/python-pyexcel-ods/DEBIAN/postinst vendored Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -e
# Automatically added by dh_python2:
if which pycompile >/dev/null 2>&1; then
pycompile -p python-pyexcel-ods
fi
# End automatically added section

14
debian/python-pyexcel-ods/DEBIAN/prerm vendored Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
set -e
# Automatically added by dh_python2:
if which pyclean >/dev/null 2>&1; then
pyclean -p python-pyexcel-ods
else
dpkg -L python-pyexcel-ods | grep \.py$ | while read file
do
rm -f "${file}"[co] >/dev/null
done
fi
# End automatically added section

View File

@ -0,0 +1,29 @@
"""
pyexcel_ods
~~~~~~~~~~~~~~~~~~~
The lower level ods file format handler using odfpy
:copyright: (c) 2015-2016 by Onni Software Ltd & its contributors
:license: New BSD License
"""
# flake8: noqa
# this line has to be place above all else
# because of dynamic import
_FILE_TYPE = 'ods'
__pyexcel_io_plugins__ = [_FILE_TYPE]
from pyexcel_io.io import get_data as read_data, isstream, store_data as write_data
def save_data(afile, data, file_type=None, **keywords):
"""standalone module function for writing module supported file type"""
if isstream(afile) and file_type is None:
file_type = _FILE_TYPE
write_data(afile, data, file_type=file_type, **keywords)
def get_data(afile, file_type=None, **keywords):
"""standalone module function for reading module supported file type"""
if isstream(afile) and file_type is None:
file_type = _FILE_TYPE
return read_data(afile, file_type=file_type, **keywords)

View File

@ -0,0 +1,133 @@
import sys
import datetime
PY2 = sys.version_info[0] == 2
def float_value(value):
"""convert a value to float"""
ret = float(value)
return ret
def date_value(value):
"""convert to data value accroding ods specification"""
ret = "invalid"
try:
# catch strptime exceptions only
if len(value) == 10:
ret = datetime.datetime.strptime(
value,
"%Y-%m-%d")
ret = ret.date()
elif len(value) == 19:
ret = datetime.datetime.strptime(
value,
"%Y-%m-%dT%H:%M:%S")
elif len(value) > 19:
ret = datetime.datetime.strptime(
value[0:26],
"%Y-%m-%dT%H:%M:%S.%f")
except ValueError:
pass
if ret == "invalid":
raise Exception("Bad date value %s" % value)
return ret
def ods_date_value(value):
return value.strftime("%Y-%m-%d")
def time_value(value):
"""convert to time value accroding the specification"""
hour = int(value[2:4])
minute = int(value[5:7])
second = int(value[8:10])
if hour < 24:
ret = datetime.time(hour, minute, second)
else:
ret = datetime.timedelta(hours=hour, minutes=minute, seconds=second)
return ret
def ods_time_value(value):
return value.strftime("PT%HH%MM%SS")
def boolean_value(value):
"""get bolean value"""
if value == "true":
ret = True
else:
ret = False
return ret
def ods_bool_value(value):
"""convert a boolean value to text"""
if value is True:
return "true"
else:
return "false"
def ods_timedelta_value(cell):
"""convert a cell value to time delta"""
hours = cell.days * 24 + cell.seconds // 3600
minutes = (cell.seconds // 60) % 60
seconds = cell.seconds % 60
return "PT%02dH%02dM%02dS" % (hours, minutes, seconds)
ODS_FORMAT_CONVERSION = {
"float": float,
"date": datetime.date,
"time": datetime.time,
'timedelta': datetime.timedelta,
"boolean": bool,
"percentage": float,
"currency": float
}
ODS_WRITE_FORMAT_COVERSION = {
float: "float",
int: "float",
str: "string",
datetime.date: "date",
datetime.time: "time",
datetime.timedelta: "timedelta",
bool: "boolean"
}
if PY2:
ODS_WRITE_FORMAT_COVERSION[unicode] = "string"
VALUE_CONVERTERS = {
"float": float_value,
"date": date_value,
"time": time_value,
"timedelta": time_value,
"boolean": boolean_value,
"percentage": float_value,
"currency": float_value
}
ODS_VALUE_CONVERTERS = {
"date": ods_date_value,
"time": ods_time_value,
"boolean": ods_bool_value,
"timedelta": ods_timedelta_value
}
VALUE_TOKEN = {
"float": "value",
"date": "date-value",
"time": "time-value",
"boolean": "boolean-value",
"percentage": "value",
"currency": "value",
"timedelta": "time-value"
}

View File

@ -0,0 +1,287 @@
# Copyright 2011 Marco Conti
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Thanks to grt for the fixes
import sys
import math
from odf.table import TableRow, TableCell, Table
from odf.text import P
from odf.namespaces import OFFICENS
from odf.opendocument import OpenDocumentSpreadsheet, load
from pyexcel_io.book import BookReader, BookWriter
from pyexcel_io.sheet import SheetReader, SheetWriter
import pyexcel_ods.converter as converter
PY2 = sys.version_info[0] == 2
PY27_BELOW = PY2 and sys.version_info[1] < 7
if PY27_BELOW:
from ordereddict import OrderedDict
else:
from collections import OrderedDict
class ODSSheet(SheetReader):
"""native ods sheet"""
def __init__(self, sheet, auto_detect_int=True, **keywords):
SheetReader.__init__(self, sheet, **keywords)
self.auto_detect_int = auto_detect_int
self.rows = self.native_sheet.getElementsByType(TableRow)
self.cached_rows = {}
self._number_of_rows = len(self.rows)
self._number_of_columns = self._find_columns()
def number_of_rows(self):
return self._number_of_rows
def number_of_columns(self):
return self._number_of_columns
@property
def name(self):
return self.native_sheet.getAttribute("name")
def _cell_value(self, row, column):
current_row = self.rows[row]
cells = current_row.getElementsByType(TableCell)
cell_value = None
if str(row) in self.cached_rows:
row_cache = self.cached_rows[str(row)]
cell_value = row_cache[column]
return cell_value
try:
cell = cells[column]
cell_value = self._read_cell(cell)
except IndexError:
cell_value = None
return cell_value
def _read_row(self, cells):
tmp_row = []
for cell in cells:
# repeated value?
repeat = cell.getAttribute("numbercolumnsrepeated")
cell_value = self._read_cell(cell)
if repeat:
number_of_repeat = int(repeat)
tmp_row += [cell_value] * number_of_repeat
else:
tmp_row.append(cell_value)
return tmp_row
def _read_text_cell(self, cell):
text_content = []
paragraphs = cell.getElementsByType(P)
# for each text node
for paragraph in paragraphs:
for node in paragraph.childNodes:
if (node.nodeType == 3):
if PY2:
text_content.append(unicode(node.data))
else:
text_content.append(node.data)
return '\n'.join(text_content)
def _read_cell(self, cell):
cell_type = cell.getAttrNS(OFFICENS, "value-type")
value_token = converter.VALUE_TOKEN.get(cell_type, "value")
ret = None
if cell_type == "string":
text_content = self._read_text_cell(cell)
ret = text_content
else:
if cell_type in converter.VALUE_CONVERTERS:
value = cell.getAttrNS(OFFICENS, value_token)
n_value = converter.VALUE_CONVERTERS[cell_type](value)
if cell_type == 'float' and self.auto_detect_int:
if is_integer_ok_for_xl_float(n_value):
n_value = int(n_value)
ret = n_value
else:
text_content = self._read_text_cell(cell)
ret = text_content
return ret
def _find_columns(self):
max = -1
for row_index, row in enumerate(self.rows):
cells = row.getElementsByType(TableCell)
if self._check_for_column_repeat(cells):
row_cache = self._read_row(cells)
self.cached_rows.update({str(row_index): row_cache})
length = len(row_cache)
else:
length = len(cells)
if length > max:
max = length
return max
def _check_for_column_repeat(self, cells):
found_repeated_columns = False
for cell in cells:
repeat = cell.getAttribute("numbercolumnsrepeated")
if repeat:
found_repeated_columns = True
break
return found_repeated_columns
class ODSBook(BookReader):
"""read ods book"""
def open(self, file_name, **keywords):
"""open ods file"""
BookReader.open(self, file_name, **keywords)
self._load_from_file()
def open_stream(self, file_stream, **keywords):
"""open ods file stream"""
BookReader.open_stream(self, file_stream, **keywords)
self._load_from_memory()
def read_sheet_by_name(self, sheet_name):
"""read a named sheet"""
tables = self.native_book.spreadsheet.getElementsByType(Table)
rets = [table for table in tables
if table.getAttribute('name') == sheet_name]
if len(rets) == 0:
raise ValueError("%s cannot be found" % sheet_name)
else:
return self.read_sheet(rets[0])
def read_sheet_by_index(self, sheet_index):
"""read a sheet at a specified index"""
tables = self.native_book.spreadsheet.getElementsByType(Table)
length = len(tables)
if sheet_index < length:
return self.read_sheet(tables[sheet_index])
else:
raise IndexError("Index %d of out bound %d" % (
sheet_index, length))
def read_all(self):
"""read all sheets"""
result = OrderedDict()
for sheet in self.native_book.spreadsheet.getElementsByType(Table):
ods_sheet = ODSSheet(sheet, **self.keywords)
result[ods_sheet.name] = ods_sheet.to_array()
return result
def read_sheet(self, native_sheet):
"""read one native sheet"""
sheet = ODSSheet(native_sheet, **self.keywords)
return {sheet.name: sheet.to_array()}
def _load_from_memory(self):
self.native_book = load(self.file_stream)
def _load_from_file(self):
self.native_book = load(self.file_name)
pass
class ODSSheetWriter(SheetWriter):
"""
ODS sheet writer
"""
def set_sheet_name(self, name):
"""initialize the native table"""
self.native_sheet = Table(name=name)
def set_size(self, size):
"""not used in this class but used in ods3"""
pass
def write_cell(self, row, cell):
"""write a native cell"""
cell_to_be_written = TableCell()
cell_type = type(cell)
cell_odf_type = converter.ODS_WRITE_FORMAT_COVERSION.get(
cell_type, "string")
cell_to_be_written.setAttrNS(OFFICENS, "value-type", cell_odf_type)
cell_odf_value_token = converter.VALUE_TOKEN.get(
cell_odf_type, "value")
converter_func = converter.ODS_VALUE_CONVERTERS.get(
cell_odf_type, None)
if converter_func:
cell = converter_func(cell)
if cell_odf_type != 'string':
cell_to_be_written.setAttrNS(OFFICENS, cell_odf_value_token, cell)
cell_to_be_written.addElement(P(text=cell))
else:
lines = cell.split('\n')
for line in lines:
cell_to_be_written.addElement(P(text=line))
row.addElement(cell_to_be_written)
def write_row(self, array):
"""
write a row into the file
"""
row = TableRow()
self.native_sheet.addElement(row)
for cell in array:
self.write_cell(row, cell)
def close(self):
"""
This call writes file
"""
self.native_book.spreadsheet.addElement(self.native_sheet)
class ODSWriter(BookWriter):
"""
open document spreadsheet writer
"""
def __init__(self):
BookWriter.__init__(self)
self.native_book = OpenDocumentSpreadsheet()
def create_sheet(self, name):
"""
write a row into the file
"""
return ODSSheetWriter(self.native_book, None, name)
def close(self):
"""
This call writes file
"""
self.native_book.write(self.file_alike_object)
def is_integer_ok_for_xl_float(value):
"""check if a float had zero value in digits"""
return value == math.floor(value)
_ods_registry = {
"file_type": "ods",
"reader": ODSBook,
"writer": ODSWriter,
"stream_type": "binary",
"mime_type": "application/vnd.oasis.opendocument.spreadsheet",
"library": "pyexcel-ods"
}
exports = (_ods_registry,)

8
debian/rules vendored Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/make -f
# This file was automatically generated by stdeb 0.8.5 at
# Wed, 07 Sep 2016 17:04:48 +0200
%:
dh $@ --with python2

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (quilt)

1
debian/source/options vendored Normal file
View File

@ -0,0 +1 @@
extend-diff-ignore="\.egg-info$"

View File

@ -1,3 +0,0 @@
pip freeze
nosetests --with-cov --cover-package pyexcel_ods --cover-package tests --with-doctest --doctest-extension=.rst tests README.rst pyexcel_ods && flake8 . --exclude=.moban.d --builtins=unicode,xrange,long