| 26 | |
| 27 | |
| 28 | class TabularData(MutableSequence[Sequence["CellT"]]): |
| 29 | def __init__(self, columns: Sequence[str], fill_value: Optional[str] = ""): |
| 30 | self._columns: dict[str, Column] = {name: Column() for name in columns} |
| 31 | self._keys: list[str] = list(columns) |
| 32 | self._fill_value = fill_value |
| 33 | self._protected: set[str] = set() |
| 34 | |
| 35 | @property |
| 36 | def columns(self) -> list[Column]: |
| 37 | return list(map(self.column, self.keys())) |
| 38 | |
| 39 | def is_protected(self, col_name) -> bool: |
| 40 | return col_name in self._protected |
| 41 | |
| 42 | def protect(self, *col_names: str): |
| 43 | self._protected.update(col_names) |
| 44 | |
| 45 | def unprotect(self, *col_names: str): |
| 46 | self._protected = self._protected.difference(col_names) |
| 47 | |
| 48 | def column(self, name: str) -> Column: |
| 49 | return self._columns[name] |
| 50 | |
| 51 | def items(self) -> ItemsView[str, Column]: |
| 52 | projection = {k: self.column(k) for k in self.keys()} |
| 53 | return projection.items() |
| 54 | |
| 55 | def keys(self) -> list[str]: |
| 56 | return self._keys |
| 57 | |
| 58 | def _iter_col_row(self, row: Sequence["CellT"]) -> Iterator[tuple["CellT", Column]]: |
| 59 | for val, col in zip_longest(row, self.columns): |
| 60 | if col is None: |
| 61 | break |
| 62 | yield with_value(val, self._fill_value), col |
| 63 | |
| 64 | def append(self, value: Sequence["CellT"]) -> None: |
| 65 | for val, col in self._iter_col_row(value): |
| 66 | col.append(val) |
| 67 | |
| 68 | def extend(self, values: Iterable[Sequence["CellT"]]) -> None: |
| 69 | for row in values: |
| 70 | self.append(row) |
| 71 | |
| 72 | def insert(self, index: int, value: Sequence["CellT"]) -> None: |
| 73 | for val, col in self._iter_col_row(value): |
| 74 | col.insert(index, val) |
| 75 | |
| 76 | def __iter__(self) -> Iterator[list["CellT"]]: |
| 77 | return map(list, zip(*self.columns)) |
| 78 | |
| 79 | def __getattr__(self, item: str) -> Column: |
| 80 | with reraise(KeyError, AttributeError): |
| 81 | return self.column(item) |
| 82 | |
| 83 | def __getitem__(self, item: Union[int, slice]): |
| 84 | func = itemgetter(item) |
| 85 | it = map(func, self.columns) |
no outgoing calls