New style reader writer (#39)

* 🎉 new style ods reader written

* This is an auto-commit, updating project meta data, such as changelog.rst, contributors.rst

*  new style ods writer

Co-authored-by: chfw <chfw@users.noreply.github.com>
This commit is contained in:
jaska 2020-10-03 14:27:56 +01:00 committed by GitHub
parent 07ee703b59
commit 24813b2d34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 81 additions and 89 deletions

View File

@ -1,6 +1,6 @@
[settings] [settings]
line_length=79 line_length=79
known_first_party=lml, pyexcel, odfpy known_first_party=lml, pyexcel_io, odf
known_third_party=nose known_third_party=nose
indent=' ' indent=' '
multi_line_output=3 multi_line_output=3

View File

@ -1,6 +1,13 @@
Change log Change log
================================================================================ ================================================================================
0.6.0 - 2020
--------------------------------------------------------------------------------
**added**
#. new style reader and writer plugins. works with pyexcel-io v0.6.0
0.5.6 - 19.03.2019 0.5.6 - 19.03.2019
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -1,6 +1,12 @@
name: pyexcel-ods name: pyexcel-ods
organisation: pyexcel organisation: pyexcel
releases: releases:
- changes:
- action: added
details:
- 'new style reader and writer plugins. works with pyexcel-io v0.6.0'
date: 2020
version: 0.6.0
- changes: - changes:
- action: added - action: added
details: details:

View File

@ -25,7 +25,7 @@ project = 'pyexcel-ods'
copyright = '2015-2020 Onni Software Ltd.' copyright = '2015-2020 Onni Software Ltd.'
author = 'chfw' author = 'chfw'
# The short X.Y version # The short X.Y version
version = '0.5.6' version = '0.6.0'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = '0.5.6' release = '0.5.6'

View File

@ -1,8 +1,8 @@
overrides: "pyexcel.yaml" overrides: "pyexcel.yaml"
name: "pyexcel-ods" name: "pyexcel-ods"
nick_name: ods nick_name: ods
version: 0.5.6 version: 0.6.0
current_version: 0.5.6 current_version: 0.6.0
release: 0.5.6 release: 0.5.6
copyright_year: 2015-2020 copyright_year: 2015-2020
file_type: ods file_type: ods

View File

@ -2,7 +2,7 @@
pyexcel_ods pyexcel_ods
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
The lower level ods file format handler using odfpy The lower level ods file format handler using odfpy
:copyright: (c) 2015-2017 by Onni Software Ltd & its contributors :copyright: (c) 2015-2020 by Onni Software Ltd & its contributors
:license: New BSD License :license: New BSD License
""" """
@ -13,15 +13,23 @@ from pyexcel_io.io import store_data as write_data
# this line has to be place above all else # this line has to be place above all else
# because of dynamic import # because of dynamic import
from pyexcel_io.plugins import IOPluginInfoChain from pyexcel_io.plugins import IOPluginInfoChain, IOPluginInfoChainV2
__FILE_TYPE__ = "ods" __FILE_TYPE__ = "ods"
IOPluginInfoChain(__name__).add_a_reader( IOPluginInfoChain(__name__)
IOPluginInfoChainV2(__name__).add_a_reader(
relative_plugin_class_path="odsr.ODSBook", relative_plugin_class_path="odsr.ODSBook",
locations=["file", "memory"],
file_types=[__FILE_TYPE__],
stream_type="binary",
).add_a_reader(
relative_plugin_class_path="odsr.ODSBookInContent",
locations=["content"],
file_types=[__FILE_TYPE__], file_types=[__FILE_TYPE__],
stream_type="binary", stream_type="binary",
).add_a_writer( ).add_a_writer(
relative_plugin_class_path="odsw.ODSWriter", relative_plugin_class_path="odsw.ODSWriter",
locations=["file", "memory"],
file_types=[__FILE_TYPE__], file_types=[__FILE_TYPE__],
stream_type="binary", stream_type="binary",
) )

View File

@ -4,7 +4,7 @@
ods reader ods reader
:copyright: (c) 2014-2017 by Onni Software Ltd. :copyright: (c) 2014-2020 by Onni Software Ltd.
:license: New BSD License, see LICENSE for more details :license: New BSD License, see LICENSE for more details
""" """
# Copyright 2011 Marco Conti # Copyright 2011 Marco Conti
@ -20,6 +20,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from io import BytesIO
import pyexcel_io.service as service import pyexcel_io.service as service
from odf.text import P from odf.text import P
@ -28,17 +29,17 @@ from odf.table import Table, TableRow, TableCell
# Thanks to grt for the fixes # Thanks to grt for the fixes
from odf.teletype import extractText from odf.teletype import extractText
from odf.namespaces import OFFICENS from odf.namespaces import OFFICENS
from pyexcel_io.book import BookReader
from odf.opendocument import load from odf.opendocument import load
from pyexcel_io.sheet import SheetReader from pyexcel_io.plugin_api.abstract_sheet import ISheet
from pyexcel_io._compact import OrderedDict from pyexcel_io.plugin_api.abstract_reader import IReader
class ODSSheet(SheetReader): class ODSSheet(ISheet):
"""native ods sheet""" """native ods sheet"""
def __init__(self, sheet, auto_detect_int=True, **keywords): def __init__(self, sheet, auto_detect_int=True, **keywords):
SheetReader.__init__(self, sheet, **keywords) self._native_sheet = sheet
self._keywords = keywords
self.__auto_detect_int = auto_detect_int self.__auto_detect_int = auto_detect_int
@property @property
@ -99,62 +100,38 @@ class ODSSheet(SheetReader):
return "\n".join(text_content) return "\n".join(text_content)
class ODSBook(BookReader): class ODSBook(IReader):
"""read ods book""" """read ods book"""
def open(self, file_name, **keywords): def __init__(self, file_alike_object, _, **keywords):
"""open ods file""" self._native_book = load(file_alike_object)
BookReader.open(self, file_name, **keywords) self._keywords = keywords
self._load_from_file() self.content_array = [
NameObject(table.getAttribute("name"), table)
def open_stream(self, file_stream, **keywords): for table in self._native_book.spreadsheet.getElementsByType(Table)
"""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): def read_sheet(self, sheet_index):
"""read a sheet at a specified index""" """read a sheet at a specified index"""
tables = self._native_book.spreadsheet.getElementsByType(Table) table = self.content_array[sheet_index].sheet
length = len(tables) sheet = ODSSheet(table, **self._keywords)
if sheet_index < length: return sheet
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 close(self): def close(self):
self._native_book = None self._native_book = None
def _load_from_memory(self):
self._native_book = load(self._file_stream)
def _load_from_file(self): class ODSBookInContent(ODSBook):
self._native_book = load(self._file_name) """
Open xlsx as read only mode
"""
def __init__(self, file_content, file_type, **keywords):
io = BytesIO(file_content)
super().__init__(io, file_type, **keywords)
class NameObject(object):
def __init__(self, name, sheet):
self.name = name
self.sheet = sheet

View File

@ -4,7 +4,7 @@
ods writer ods writer
:copyright: (c) 2014-2017 by Onni Software Ltd. :copyright: (c) 2014-2020 by Onni Software Ltd.
:license: New BSD License, see LICENSE for more details :license: New BSD License, see LICENSE for more details
""" """
import sys import sys
@ -13,27 +13,23 @@ import pyexcel_io.service as converter
from odf.text import P from odf.text import P
from odf.table import Table, TableRow, TableCell from odf.table import Table, TableRow, TableCell
from odf.namespaces import OFFICENS from odf.namespaces import OFFICENS
from pyexcel_io.book import BookWriter
from odf.opendocument import OpenDocumentSpreadsheet from odf.opendocument import OpenDocumentSpreadsheet
from pyexcel_io.sheet import SheetWriter from pyexcel_io.plugin_api.abstract_sheet import ISheetWriter
from pyexcel_io.plugin_api.abstract_writer import IWriter
PY2 = sys.version_info[0] == 2 PY2 = sys.version_info[0] == 2
PY27_BELOW = PY2 and sys.version_info[1] < 7 PY27_BELOW = PY2 and sys.version_info[1] < 7
class ODSSheetWriter(SheetWriter): class ODSSheetWriter(ISheetWriter):
""" """
ODS sheet writer ODS sheet writer
""" """
def set_sheet_name(self, name): def __init__(self, ods_book, ods_sheet, sheet_name, **keywords):
"""initialize the native table""" self._native_book = ods_book
self._native_sheet = Table(name=name) self._native_sheet = Table(name=sheet_name)
def set_size(self, size):
"""not used in this class but used in ods3"""
pass
def write_cell(self, row, cell): def write_cell(self, row, cell):
"""write a native cell""" """write a native cell"""
@ -77,14 +73,14 @@ class ODSSheetWriter(SheetWriter):
self._native_book.spreadsheet.addElement(self._native_sheet) self._native_book.spreadsheet.addElement(self._native_sheet)
class ODSWriter(BookWriter): class ODSWriter(IWriter):
""" """
open document spreadsheet writer open document spreadsheet writer
""" """
def __init__(self): def __init__(self, file_alike_object, file_type, **keywords):
BookWriter.__init__(self) self._file_alike_object = file_alike_object
self._native_book = OpenDocumentSpreadsheet() self._native_book = OpenDocumentSpreadsheet()
def create_sheet(self, name): def create_sheet(self, name):

View File

@ -29,7 +29,7 @@ except (ValueError, UnicodeError, locale.Error):
NAME = "pyexcel-ods" NAME = "pyexcel-ods"
AUTHOR = "chfw" AUTHOR = "chfw"
VERSION = "0.5.6" VERSION = "0.6.0"
EMAIL = "info@pyexcel.org" EMAIL = "info@pyexcel.org"
LICENSE = "New BSD" LICENSE = "New BSD"
DESCRIPTION = ( DESCRIPTION = (

View File

@ -7,8 +7,9 @@ from pyexcel_ods.odsw import ODSWriter
class TestODSReader(ODSCellTypes): class TestODSReader(ODSCellTypes):
def setUp(self): def setUp(self):
r = ODSBook() r = ODSBook(
r.open(os.path.join("tests", "fixtures", "ods_formats.ods")) os.path.join("tests", "fixtures", "ods_formats.ods"), "ods"
)
self.data = r.read_all() self.data = r.read_all()
for key in self.data.keys(): for key in self.data.keys():
self.data[key] = list(self.data[key]) self.data[key] = list(self.data[key])
@ -17,16 +18,15 @@ class TestODSReader(ODSCellTypes):
class TestODSWriter(ODSCellTypes): class TestODSWriter(ODSCellTypes):
def setUp(self): def setUp(self):
r = ODSBook() r = ODSBook(
r.open(os.path.join("tests", "fixtures", "ods_formats.ods")) os.path.join("tests", "fixtures", "ods_formats.ods"), "ods"
)
self.data1 = r.read_all() self.data1 = r.read_all()
self.testfile = "odswriter.ods" self.testfile = "odswriter.ods"
w = ODSWriter() w = ODSWriter(self.testfile, "ods")
w.open(self.testfile)
w.write(self.data1) w.write(self.data1)
w.close() w.close()
r2 = ODSBook() r2 = ODSBook(self.testfile, "ods")
r2.open(self.testfile)
self.data = r2.read_all() self.data = r2.read_all()
for key in self.data.keys(): for key in self.data.keys():
self.data[key] = list(self.data[key]) self.data[key] = list(self.data[key])

View File

@ -13,12 +13,10 @@ class TestNativeODSWriter:
"Sheet3": [[u"X", u"Y", u"Z"], [1, 4, 7], [2, 5, 8], [3, 6, 9]], "Sheet3": [[u"X", u"Y", u"Z"], [1, 4, 7], [2, 5, 8], [3, 6, 9]],
} }
self.testfile = "writer.ods" self.testfile = "writer.ods"
writer = Writer() writer = Writer(self.testfile, "ods")
writer.open(self.testfile)
writer.write(self.content) writer.write(self.content)
writer.close() writer.close()
reader = Reader() reader = Reader(self.testfile, "ods")
reader.open(self.testfile)
content = reader.read_all() content = reader.read_all()
for key in content.keys(): for key in content.keys():
content[key] = list(content[key]) content[key] = list(content[key])