""" 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