debian-python-pyexcel-io/pyexcel_io/sheet.py

176 lines
4.9 KiB
Python

"""
pyexcel_io.sheet
~~~~~~~~~~~~~~~~~~~
The io interface to file extensions
:copyright: (c) 2014-2022 by Onni Software Ltd.
:license: New BSD License, see LICENSE for more details
"""
import pyexcel_io.constants as constants
from pyexcel_io.utils import _index_filter
from pyexcel_io._compact import irange
from pyexcel_io.plugin_api import NamedContent # noqa: F401
class SheetReader(object):
"""
Generic sheet reader
"""
def __init__(
self,
sheet,
start_row=0,
row_limit=-1,
start_column=0,
column_limit=-1,
skip_row_func=None,
skip_column_func=None,
skip_empty_rows=False,
row_renderer=None,
keep_trailing_empty_cells=False,
**deprecated_use_of_keywords_here
):
self._native_sheet = sheet
self._keywords = {}
self._keywords.update(deprecated_use_of_keywords_here)
self._start_row = start_row
self._row_limit = row_limit
self._start_column = start_column
self._column_limit = column_limit
self._skip_row = _index_filter
self._skip_column = _index_filter
self._skip_empty_rows = skip_empty_rows
self._row_renderer = row_renderer
self.keep_trailing_empty_cells = keep_trailing_empty_cells
if skip_row_func:
self._skip_row = skip_row_func
if skip_column_func:
self._skip_column = skip_column_func
def to_array(self):
"""2 dimentional representation of the content"""
for row_index, row in enumerate(self.row_iterator()):
row_position = self._skip_row(
row_index, self._start_row, self._row_limit
)
if row_position == constants.SKIP_DATA:
continue
elif row_position == constants.STOP_ITERATION:
break
return_row = []
tmp_row = []
for column_index, cell_value in enumerate(
self.column_iterator(row)
):
column_position = self._skip_column(
column_index, self._start_column, self._column_limit
)
if column_position == constants.SKIP_DATA:
continue
elif column_position == constants.STOP_ITERATION:
break
if self.keep_trailing_empty_cells:
return_row.append(cell_value)
else:
tmp_row.append(cell_value)
if cell_value is not None and cell_value != "":
return_row += tmp_row
tmp_row = []
if self._skip_empty_rows and len(return_row) < 1:
# we by-pass next yeild here
# because it is an empty row
continue
if self._row_renderer:
return_row = self._row_renderer(return_row)
yield return_row
def row_iterator(self):
"""
iterate each row
override this function in the sitation where
number_of_rows() is difficult or costly to implement
"""
return irange(self.number_of_rows())
def column_iterator(self, row):
"""
iterate each column of a given row
override this function in the sitation where
number_of_columns() is difficult or costly to implement
"""
for column in irange(self.number_of_columns()):
yield self.cell_value(row, column)
def number_of_rows(self):
"""
implement this method for easy extension
"""
raise Exception("Please implement number_of_rows()")
def number_of_columns(self):
"""
implement this method for easy extension
"""
raise Exception("Please implement number_of_columns()")
def cell_value(self, row, column):
"""
implement this method for easy extension
"""
raise Exception("Please implement cell_value()")
def close(self):
pass
class SheetWriter(object):
"""
Generic sheet writer
"""
def __init__(self, native_book, native_sheet, name, **keywords):
if name:
sheet_name = name
else:
sheet_name = constants.DEFAULT_SHEET_NAME
self._native_book = native_book
self._native_sheet = native_sheet
self._keywords = keywords
self.set_sheet_name(sheet_name)
def set_sheet_name(self, name):
"""
Set sheet name
"""
pass
def write_row(self, array):
"""
write a row into the file
"""
raise NotImplementedError("Please implement write_row()")
def write_array(self, table):
"""
For standalone usage, write an array
"""
for row in table:
self.write_row(row)
def close(self):
"""
This call actually save the file
"""
pass