Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add copy method for tables #405

Merged
merged 24 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3abeadc
added clone
PhilipGutberlet Jun 30, 2023
2182d29
added clone
PhilipGutberlet Jun 30, 2023
98f315f
Merge remote-tracking branch 'origin/275-add-copy-method-for-tables' …
patrikguempel Jun 30, 2023
7c27ecb
style: apply automated linter fixes
megalinter-bot Jun 30, 2023
6b8167a
added missing ids in parameterize tests
PhilipGutberlet Jun 30, 2023
2a1d579
Merge remote-tracking branch 'origin/275-add-copy-method-for-tables' …
PhilipGutberlet Jun 30, 2023
9884a40
style: apply automated linter fixes
megalinter-bot Jun 30, 2023
c480667
Update src/safeds/data/tabular/containers/_table.py
PhilipGutberlet Jun 30, 2023
dbae130
Update src/safeds/data/tabular/containers/_table.py
PhilipGutberlet Jun 30, 2023
bba4798
Update src/safeds/data/tabular/containers/_row.py
PhilipGutberlet Jun 30, 2023
beea7bf
Update src/safeds/data/tabular/containers/_tagged_table.py
PhilipGutberlet Jun 30, 2023
492fe1f
Update src/safeds/data/tabular/containers/_tagged_table.py
PhilipGutberlet Jun 30, 2023
d1d170d
Merge branch 'main' into 275-add-copy-method-for-tables
PhilipGutberlet Jun 30, 2023
d7ead95
Update tests/safeds/ml/classical/regression/test_regressor.py
PhilipGutberlet Jun 30, 2023
d228d31
Update tests/safeds/ml/classical/regression/test_regressor.py
PhilipGutberlet Jun 30, 2023
aa6f413
Update tests/safeds/data/tabular/transformation/test_standard_scaler.py
PhilipGutberlet Jun 30, 2023
eff4b03
Update tests/safeds/data/tabular/transformation/test_range_scaler.py
PhilipGutberlet Jun 30, 2023
6f75c81
Update tests/safeds/data/tabular/transformation/test_standard_scaler.py
PhilipGutberlet Jun 30, 2023
07bf672
Update tests/safeds/data/tabular/transformation/test_range_scaler.py
PhilipGutberlet Jun 30, 2023
afcf656
Update tests/safeds/data/tabular/transformation/test_imputer.py
PhilipGutberlet Jun 30, 2023
3aa10c3
Update tests/safeds/data/tabular/transformation/test_range_scaler.py
PhilipGutberlet Jun 30, 2023
942a25d
Update tests/safeds/data/tabular/transformation/test_label_encoder.py
PhilipGutberlet Jun 30, 2023
4eb0a7c
Update tests/safeds/data/tabular/transformation/test_label_encoder.py
PhilipGutberlet Jun 30, 2023
c2d6d93
Merge branch 'main' into 275-add-copy-method-for-tables
PhilipGutberlet Jun 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/safeds/data/tabular/containers/_column.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import copy
import io
from collections.abc import Sequence
from numbers import Number
Expand Down Expand Up @@ -1031,3 +1032,19 @@ def _count_missing_values(self) -> int:
2
"""
return self._data.isna().sum()

# ------------------------------------------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------------------------------------------

def _copy(self) -> Column:
"""
Return a copy of this column.

Returns
-------
column : Column
The copy of this column.

"""
return copy.deepcopy(self)
18 changes: 17 additions & 1 deletion src/safeds/data/tabular/containers/_row.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import copy
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any

Expand Down Expand Up @@ -263,7 +264,7 @@ def __repr__(self) -> str:
>>> repr(row)
"Row({'a': 1})"
"""
return f"Row({str(self)})"
return f"Row({self!s})"

def __str__(self) -> str:
"""
Expand Down Expand Up @@ -493,3 +494,18 @@ def _repr_html_(self) -> str:
The generated HTML.
"""
return self._data.to_html(max_rows=1, max_cols=self._data.shape[1], notebook=True)

# ------------------------------------------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------------------------------------------

def _copy(self) -> Row:
"""
Return a copy of this row.

Returns
-------
copy : Row
The copy of this row.
"""
return copy.deepcopy(self)
21 changes: 18 additions & 3 deletions src/safeds/data/tabular/containers/_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ def add_row(self, row: Row) -> Table:
1 3 4
"""
int_columns = []
result = self.remove_columns([]) # clone
result = self._copy()
if result.number_of_rows == 0:
int_columns = list(filter(lambda name: isinstance(row[name], int | np.int64), row.column_names))
if result.number_of_columns == 0:
Expand Down Expand Up @@ -974,7 +974,7 @@ def add_rows(self, rows: list[Row] | Table) -> Table:
if isinstance(rows, Table):
rows = rows.to_rows()
int_columns = []
result = self.remove_columns([]) # clone
result = self._copy()
for row in rows:
if result.number_of_rows == 0:
int_columns = list(filter(lambda name: isinstance(row[name], int | np.int64), row.column_names))
Expand Down Expand Up @@ -1094,7 +1094,7 @@ def keep_only_columns(self, column_names: list[str]) -> Table:
if len(invalid_columns) != 0:
raise UnknownColumnNameError(invalid_columns)

clone = copy.deepcopy(self)
clone = self._copy()
clone = clone.remove_columns(list(set(self.column_names) - set(column_names)))
return clone

Expand Down Expand Up @@ -2223,3 +2223,18 @@ def __dataframe__(self, nan_as_null: bool = False, allow_copy: bool = True): #
data_copy = self._data.copy()
data_copy.columns = self.column_names
return data_copy.__dataframe__(nan_as_null, allow_copy)

# ------------------------------------------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------------------------------------------

def _copy(self) -> Table:
"""
Return a copy of this table.

Returns
-------
table : Table
The copy of this table.
"""
return copy.deepcopy(self)
16 changes: 16 additions & 0 deletions src/safeds/data/tabular/containers/_tagged_table.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import copy
from typing import TYPE_CHECKING

from safeds.data.tabular.containers import Column, Table
Expand Down Expand Up @@ -169,3 +170,18 @@ def features(self) -> Table:
@property
def target(self) -> Column:
return self._target

# ------------------------------------------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------------------------------------------

def _copy(self) -> TaggedTable:
"""
Return a copy of this tagged table.

Returns
-------
table : TaggedTable
The copy of this tagged table.
"""
return copy.deepcopy(self)
13 changes: 13 additions & 0 deletions tests/safeds/data/tabular/containers/_column/test_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pytest
from safeds.data.tabular.containers import Column


@pytest.mark.parametrize(
"column",
[Column("a"), Column("a", ["a", 3, 0.1])],
ids=["empty", "normal"],
)
def test_should_copy_table(column: Column) -> None:
copied = column._copy()
assert copied == column
assert copied is not column
13 changes: 13 additions & 0 deletions tests/safeds/data/tabular/containers/_table/test_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pytest
from safeds.data.tabular.containers import Table


@pytest.mark.parametrize(
"table",
[Table(), Table({"a": [], "b": []}), Table({"a": ["a", 3, 0.1], "b": [True, False, None]})],
ids=["empty", "empty-rows", "normal"],
)
def test_should_copy_table(table: Table) -> None:
copied = table._copy()
assert copied == table
assert copied is not table
12 changes: 12 additions & 0 deletions tests/safeds/data/tabular/containers/test_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,15 @@ def test_should_contain_th_element_for_each_column_name(self, row: Row) -> None:
def test_should_contain_td_element_for_each_value(self, row: Row) -> None:
for value in row.values():
assert f"<td>{value}</td>" in row._repr_html_()


class TestCopy:
@pytest.mark.parametrize(
"row",
[Row(), Row({"a": [3, 0.1]})],
ids=["empty", "normal"],
)
def test_should_copy_table(self, row: Row) -> None:
copied = row._copy()
assert copied == row
assert copied is not row
15 changes: 15 additions & 0 deletions tests/safeds/data/tabular/containers/test_tagged_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,18 @@ def test_should_return_features(self, tagged_table: TaggedTable) -> None:
class TestTarget:
def test_should_return_target(self, tagged_table: TaggedTable) -> None:
assert tagged_table.target == Column("T", [0, 1])


class TestCopy:
@pytest.mark.parametrize(
"tagged_table",
[
TaggedTable({"a": [], "b": []}, target_name="b", feature_names=["a"]),
TaggedTable({"a": ["a", 3, 0.1], "b": [True, False, None]}, target_name="b", feature_names=["a"]),
],
ids=["empty-rows", "normal"],
)
def test_should_copy_tagged_table(self, tagged_table: TaggedTable) -> None:
copied = tagged_table._copy()
assert copied == tagged_table
assert copied is not tagged_table