Skip to content

Commit

Permalink
feat: convert containers for tabular data to HTML (#243)
Browse files Browse the repository at this point in the history
Closes #140.

### Summary of Changes

Add method `to_html` to `Table`, `Column`, and `Row` that returns an
HTML representation of the respective container.
  • Loading branch information
lars-reimann committed Apr 22, 2023
1 parent 66a8f18 commit 683c279
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/safeds/data/tabular/containers/_column.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,30 @@ def plot_histogram(self) -> Image:
buffer.seek(0)
return Image(buffer, ImageFormat.PNG)

# ------------------------------------------------------------------------------------------------------------------
# Conversion
# ------------------------------------------------------------------------------------------------------------------

def to_html(self) -> str:
"""
Return an HTML representation of the column.
Returns
-------
output : str
The generated HTML.
Examples
--------
>>> from safeds.data.tabular.containers import Column
>>> column = Column("test", [1, 2, 3])
>>> html = column.to_html()
"""
frame = self._data.to_frame()
frame.columns = [self.name]

return frame.to_html(max_rows=self._data.size, max_cols=1)

# ------------------------------------------------------------------------------------------------------------------
# IPython integration
# ------------------------------------------------------------------------------------------------------------------
Expand Down
17 changes: 17 additions & 0 deletions src/safeds/data/tabular/containers/_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,23 @@ def to_dict(self) -> dict[str, Any]:
"""
return {column_name: self.get_value(column_name) for column_name in self.column_names}

def to_html(self) -> str:
"""
Return an HTML representation of the row.
Returns
-------
output : str
The generated HTML.
Examples
--------
>>> from safeds.data.tabular.containers import Row
>>> row = Row({"a": 1, "b": 2})
>>> html = row.to_html()
"""
return self._data.to_html(max_rows=1, max_cols=self._data.shape[1])

# ------------------------------------------------------------------------------------------------------------------
# IPython integration
# ------------------------------------------------------------------------------------------------------------------
Expand Down
17 changes: 17 additions & 0 deletions src/safeds/data/tabular/containers/_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,23 @@ def to_dict(self) -> dict[str, list[Any]]:
"""
return {column_name: list(self.get_column(column_name)) for column_name in self.column_names}

def to_html(self) -> str:
"""
Return an HTML representation of the table.
Returns
-------
output : str
The generated HTML.
Examples
--------
>>> from safeds.data.tabular.containers import Table
>>> table = Table.from_dict({"a": [1, 2, 3], "b": [4, 5, 6]})
>>> html = table.to_html()
"""
return self._data.to_html(max_rows=self._data.shape[0], max_cols=self._data.shape[1])

def to_columns(self) -> list[Column]:
"""
Return a list of the columns.
Expand Down
46 changes: 46 additions & 0 deletions tests/safeds/data/tabular/containers/test_column.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,52 @@
from safeds.data.tabular.containers import Column


class TestToHtml:
@pytest.mark.parametrize(
"column",
[
Column("a", []),
Column("a", [1, 2, 3]),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_table_element(self, column: Column) -> None:
pattern = r"<table.*?>.*?</table>"
assert re.search(pattern, column.to_html(), flags=re.S) is not None

@pytest.mark.parametrize(
"column",
[
Column("a", []),
Column("a", [1, 2, 3]),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_th_element_for_column_name(self, column: Column) -> None:
assert f"<th>{column.name}</th>" in column.to_html()

@pytest.mark.parametrize(
"column",
[
Column("a", []),
Column("a", [1, 2, 3]),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_td_element_for_each_value(self, column: Column) -> None:
for value in column:
assert f"<td>{value}</td>" in column.to_html()


class TestReprHtml:
@pytest.mark.parametrize(
"column",
Expand Down
47 changes: 47 additions & 0 deletions tests/safeds/data/tabular/containers/test_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,53 @@ def test_should_return_dict_for_table(self, row: Row, expected: dict[str, Any])
assert row.to_dict() == expected


class TestToHtml:
@pytest.mark.parametrize(
"row",
[
Row(),
Row({"a": 1, "b": 2}),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_table_element(self, row: Row) -> None:
pattern = r"<table.*?>.*?</table>"
assert re.search(pattern, row.to_html(), flags=re.S) is not None

@pytest.mark.parametrize(
"row",
[
Row(),
Row({"a": 1, "b": 2}),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_th_element_for_each_column_name(self, row: Row) -> None:
for column_name in row.column_names:
assert f"<th>{column_name}</th>" in row.to_html()

@pytest.mark.parametrize(
"row",
[
Row(),
Row({"a": 1, "b": 2}),
],
ids=[
"empty",
"non-empty",
],
)
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.to_html()


class TestReprHtml:
@pytest.mark.parametrize(
"row",
Expand Down
48 changes: 48 additions & 0 deletions tests/safeds/data/tabular/containers/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,54 @@ def test_should_return_dict_for_table(self, table: Table, expected: dict[str, li
assert table.to_dict() == expected


class TestToHtml:
@pytest.mark.parametrize(
"table",
[
Table.from_dict({}),
Table.from_dict({"a": [1, 2], "b": [3, 4]}),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_table_element(self, table: Table) -> None:
pattern = r"<table.*?>.*?</table>"
assert re.search(pattern, table.to_html(), flags=re.S) is not None

@pytest.mark.parametrize(
"table",
[
Table.from_dict({}),
Table.from_dict({"a": [1, 2], "b": [3, 4]}),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_th_element_for_each_column_name(self, table: Table) -> None:
for column_name in table.column_names:
assert f"<th>{column_name}</th>" in table.to_html()

@pytest.mark.parametrize(
"table",
[
Table.from_dict({}),
Table.from_dict({"a": [1, 2], "b": [3, 4]}),
],
ids=[
"empty",
"non-empty",
],
)
def test_should_contain_td_element_for_each_value(self, table: Table) -> None:
for column in table.to_columns():
for value in column:
assert f"<td>{value}</td>" in table.to_html()


class TestReprHtml:
@pytest.mark.parametrize(
"table",
Expand Down

0 comments on commit 683c279

Please sign in to comment.