Skip to content

Commit

Permalink
feat: finalize Row class
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-reimann committed Jan 13, 2025
1 parent 212c0ae commit a801436
Show file tree
Hide file tree
Showing 20 changed files with 340 additions and 388 deletions.
26 changes: 1 addition & 25 deletions src/safeds/data/tabular/containers/_lazy_vectorized_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from ._row import Row

if TYPE_CHECKING:
from safeds.data.tabular.typing import ColumnType, Schema

from ._table import Table


Expand All @@ -21,7 +19,7 @@ class _LazyVectorizedRow(Row):
up operations on the row.
Moreover, accessing a column only builds an expression that will be evaluated when needed. This is useful when later
operations remove more rows or columns, so we don't do unnecessary work upfront.
operations remove rows or columns, so we don't do unnecessary work upfront.
"""

# ------------------------------------------------------------------------------------------------------------------
Expand All @@ -44,22 +42,6 @@ def __hash__(self) -> int:
def __sizeof__(self) -> int:
return self._table.__sizeof__()

# ------------------------------------------------------------------------------------------------------------------
# Properties
# ------------------------------------------------------------------------------------------------------------------

@property
def column_names(self) -> list[str]:
return self._table.column_names

@property
def column_count(self) -> int:
return self._table.column_count

@property
def schema(self) -> Schema:
return self._table.schema

# ------------------------------------------------------------------------------------------------------------------
# Column operations
# ------------------------------------------------------------------------------------------------------------------
Expand All @@ -70,9 +52,3 @@ def get_cell(self, name: str) -> _LazyCell:
_check_columns_exist(self._table, name)

return _LazyCell(pl.col(name))

def get_column_type(self, name: str) -> ColumnType:
return self._table.get_column_type(name)

def has_column(self, name: str) -> bool:
return self._table.has_column(name)
74 changes: 3 additions & 71 deletions src/safeds/data/tabular/containers/_row.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from collections.abc import Iterator, Mapping
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from safeds.data.tabular.typing import ColumnType, Schema

from ._cell import Cell


class Row(ABC, Mapping[str, Any]):
class Row(ABC):
"""
A one-dimensional collection of named, heterogeneous values.
This class cannot be instantiated directly. It is only used for arguments of callbacks.
You only need to interact with this class in callbacks passed to higher-order functions.
"""

# ------------------------------------------------------------------------------------------------------------------
# Dunder methods
# ------------------------------------------------------------------------------------------------------------------

def __contains__(self, name: Any) -> bool:
return self.has_column(name)

@abstractmethod
def __eq__(self, other: object) -> bool: ...

Expand All @@ -33,34 +27,9 @@ def __getitem__(self, name: str) -> Cell:
@abstractmethod
def __hash__(self) -> int: ...

def __iter__(self) -> Iterator[Any]:
return iter(self.column_names)

def __len__(self) -> int:
return self.column_count

@abstractmethod
def __sizeof__(self) -> int: ...

# ------------------------------------------------------------------------------------------------------------------
# Properties
# ------------------------------------------------------------------------------------------------------------------

@property
@abstractmethod
def column_names(self) -> list[str]:
"""The names of the columns in the row."""

@property
@abstractmethod
def column_count(self) -> int:
"""The number of columns in the row."""

@property
@abstractmethod
def schema(self) -> Schema:
"""The schema of the row."""

# ------------------------------------------------------------------------------------------------------------------
# Column operations
# ------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -108,40 +77,3 @@ def get_cell(self, name: str) -> Cell:
| 2 | 4 |
+------+------+
"""

@abstractmethod
def get_column_type(self, name: str) -> ColumnType:
"""
Get the type of the specified column.
Parameters
----------
name:
The name of the column.
Returns
-------
type:
The type of the column.
Raises
------
ColumnNotFoundError
If the column name does not exist.
"""

@abstractmethod
def has_column(self, name: str) -> bool:
"""
Check if the row has a column with the specified name.
Parameters
----------
name:
The name of the column.
Returns
-------
has_column:
Whether the row has a column with the specified name.
"""
65 changes: 46 additions & 19 deletions tests/helpers/_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from polars.testing import assert_frame_equal

from safeds.data.labeled.containers import TabularDataset
from safeds.data.tabular.containers import Cell, Column, Table
from safeds.data.tabular.containers import Cell, Column, Row, Table


def assert_tables_are_equal(
Expand Down Expand Up @@ -62,44 +62,71 @@ def assert_that_tabular_datasets_are_equal(table1: TabularDataset, table2: Tabul


def assert_cell_operation_works(
input_value: Any,
value: Any,
transformer: Callable[[Cell], Cell],
expected_value: Any,
expected: Any,
) -> None:
"""
Assert that a cell operation works as expected.
Parameters
----------
input_value:
value:
The value in the input cell.
transformer:
The transformer to apply to the cells.
expected_value:
expected:
The expected value of the transformed cell.
"""
column = Column("A", [input_value])
column = Column("A", [value])
transformed_column = column.transform(transformer)
assert transformed_column == Column("A", [expected_value]), f"Expected: {expected_value}\nGot: {transformed_column}"
actual = transformed_column[0]
assert actual == expected


def assert_row_operation_works(
input_value: Any,
transformer: Callable[[Table], Table],
expected_value: Any,
table: Table,
computer: Callable[[Row], Cell],
expected: list[Any],
) -> None:
"""
Assert that a row operation works as expected.
Parameters
----------
input_value:
The value in the input row.
transformer:
The transformer to apply to the rows.
expected_value:
The expected value of the transformed row.
table:
The input table.
computer:
The function that computes the new column.
expected:
The expected values of the computed column.
"""
column_name = _find_free_column_name(table, "computed")

new_table = table.add_computed_column(column_name, computer)
actual = list(new_table.get_column(column_name))
assert actual == expected


def _find_free_column_name(table: Table, prefix: str) -> str:
"""
table = Table(input_value)
transformed_table = transformer(table)
assert transformed_table == Table(expected_value), f"Expected: {expected_value}\nGot: {transformed_table}"
Find a free column name in the table.
Parameters
----------
table:
The table to search for a free column name.
prefix:
The prefix to use for the column name.
Returns
-------
free_name:
A free column name.
"""
column_name = prefix

while column_name in table.column_names:
column_name += "_"

return column_name
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# serializer version: 1
# name: TestContract.test_should_return_same_hash_in_different_processes[empty]
1789859531466043636
# ---
# name: TestContract.test_should_return_same_hash_in_different_processes[no rows]
585695607399955642
# ---
# name: TestContract.test_should_return_same_hash_in_different_processes[with data]
909875695937937648
# ---
20 changes: 0 additions & 20 deletions tests/safeds/data/tabular/containers/_row/test_column_count.py

This file was deleted.

25 changes: 0 additions & 25 deletions tests/safeds/data/tabular/containers/_row/test_column_names.py

This file was deleted.

24 changes: 0 additions & 24 deletions tests/safeds/data/tabular/containers/_row/test_contains.py

This file was deleted.

Loading

0 comments on commit a801436

Please sign in to comment.