from collections import defaultdict
from typing import Any
from openpyxl.worksheet.worksheet import Worksheet
from tabulate import tabulate
from exceltablekit.alphabet import Alphabet
from exceltablekit.errors import InvalidColumnValueError, InvalidRowValueError
from exceltablekit.table.cell import Cell
from exceltablekit.utils import Validation
[docs]
class Table:
_worksheet: Worksheet
_total_row_headers: int
_first_column: str
_first_row: int
_last_column: str
_last_row: int
_num_first_column: int
_num_last_column: int
_body: list[Cell]
_headers: list[Cell]
def __init__(
self,
worksheet: Worksheet,
first_column: str,
first_row: int,
last_column: str,
last_row: int,
) -> None:
try:
Validation.column(first_column)
Validation.column(last_column)
Validation.row(first_row)
Validation.row(last_row)
except (InvalidColumnValueError, InvalidRowValueError):
raise
self._worksheet = worksheet
self._total_row_headers = 0
self._body = []
self._headers = []
self._first_column = first_column
self._first_row = first_row
self._last_column = last_column
self._last_row = last_row
self._num_first_column = Alphabet.get_number_column_by_string(first_column)
self._num_last_column = Alphabet.get_number_column_by_string(last_column)
for col in range(self._num_first_column, self._num_last_column + 1):
for row in range(first_row, last_row + 1):
self._body.append(
Cell(column=Alphabet.get_string_column_by_number(col), row=row)
)
def _set_style(self, property: str, value: Any, content: list[Cell]) -> None:
"""Defines the style for all table body cells.
Parameters:
----------
property : str
Property to define.
value : any
Value of the property to set.
content : list[Cell]
Header o body.
"""
for cell in content:
cell.set_property(self._worksheet, property, value)
[docs]
def set_style_body(self, property: str, value: Any) -> None:
"""Defines the style for all table body cells.
Parameters:
----------
property : str
Property to define.
value : any
Value of the property to set.
"""
self._set_style(property=property, value=value, content=self._body)
[docs]
def get_cells_by_row(self, num_row: int) -> list[Cell]:
"""Returns all cells within a row for a given row number.
Parameters:
----------
num_row : int
The row index or identifier.
"""
cells: list[Cell] = []
if num_row > self._last_row:
raise ValueError("Row number out of bounds.")
for cell in self._body:
if cell.get_row() == num_row:
cells.append(cell)
return cells
[docs]
def get_body(self) -> list[Cell]:
"""Returns the list of cells contained within a table."""
return self._body
[docs]
def get_first_column(self) -> str:
"""Returns the first column letter of the table."""
return self._first_column
[docs]
def get_first_row(self) -> int:
"""Returns the first row number of the table."""
return self._first_row
[docs]
def display_cells(self) -> None:
"""Displays all cells (column and row coordinates) within the table to the console."""
content = self._headers + self._body
text_content = [cell.get_cell() for cell in content]
rows_dict: dict[int, list[str]] = defaultdict(list)
for cell_str in text_content:
row_num = int("".join(ch for ch in cell_str if ch.isdigit()))
rows_dict[row_num].append(cell_str)
table = [rows_dict[key] for key in sorted(rows_dict.keys())]
print(tabulate(table, tablefmt="simple_grid"))