Replace DataTable row_count with property, test improvements

This commit is contained in:
Darren Burns
2023-01-24 11:33:35 +00:00
parent d1413ee352
commit 12d429dbd0
3 changed files with 69 additions and 77 deletions

View File

@@ -217,7 +217,6 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
self.columns: list[Column] = [] self.columns: list[Column] = []
self.rows: dict[RowKey, Row] = {} self.rows: dict[RowKey, Row] = {}
self.data: dict[RowKey, list[CellType]] = {} self.data: dict[RowKey, list[CellType]] = {}
self.row_count = 0
# Keep tracking of key -> index for rows/cols. # Keep tracking of key -> index for rows/cols.
# For a given key, what is the current location of the corresponding row/col? # For a given key, what is the current location of the corresponding row/col?
@@ -271,6 +270,10 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
def cursor_column(self) -> int: def cursor_column(self) -> int:
return self.cursor_cell.column return self.cursor_cell.column
@property
def row_count(self) -> int:
return len(self.rows)
def get_cell_value(self, coordinate: Coordinate) -> CellType: def get_cell_value(self, coordinate: Coordinate) -> CellType:
"""Get the value from the cell at the given coordinate. """Get the value from the cell at the given coordinate.
@@ -485,7 +488,6 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
Args: Args:
columns: Also clear the columns. Defaults to False. columns: Also clear the columns. Defaults to False.
""" """
self.row_count = 0
self._clear_caches() self._clear_caches()
self._y_offsets.clear() self._y_offsets.clear()
self.data.clear() self.data.clear()
@@ -568,7 +570,6 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
for line_no in range(height): for line_no in range(height):
self._y_offsets.append((row_key, line_no)) self._y_offsets.append((row_key, line_no))
self.row_count += 1
self._line_no += height self._line_no += height
self._new_rows.add(row_index) self._new_rows.add(row_index)

View File

@@ -1,10 +1,11 @@
import pytest import pytest
from rich.text import Text
from textual.app import App from textual.app import App
from textual.coordinate import Coordinate from textual.coordinate import Coordinate
from textual.message import Message from textual.message import Message
from textual.widgets import DataTable from textual.widgets import DataTable
from textual.widgets._data_table import StringKey, CellDoesNotExist from textual.widgets._data_table import StringKey, CellDoesNotExist, RowKey, Row
ROWS = [["0/0", "0/1"], ["1/0", "1/1"], ["2/0", "2/1"]] ROWS = [["0/0", "0/1"], ["1/0", "1/1"], ["2/0", "2/1"]]
@@ -126,6 +127,44 @@ async def test_datatable_message_emission():
assert messages == expected_messages assert messages == expected_messages
async def test_add_rows():
app = DataTableApp()
async with app.run_test():
table = app.query_one(DataTable)
row_keys = table.add_rows(ROWS)
# We're given a key for each row
assert len(row_keys) == len(ROWS)
assert len(row_keys) == len(table.data)
assert table.row_count == len(ROWS)
# Each key can be used to fetch a row from the DataTable
assert all(key in table.data for key in row_keys)
# Ensure the keys are returned *in order*, and there's one for each row
for key, row in zip(row_keys, range(len(ROWS))):
assert table.rows[key].index == row
async def test_add_data_user_defined_keys():
app = DataTableApp()
async with app.run_test():
table = app.query_one(DataTable)
algernon_key = table.add_row(*ROWS[0], key="algernon")
table.add_row(*ROWS[1], key="charlie")
auto_key = table.add_row(*ROWS[2])
assert algernon_key == "algernon"
# We get a RowKey object back, but we can use our own string *or* this object
# to find the row we're looking for, they're considered equivalent for lookups.
assert isinstance(algernon_key, RowKey)
assert table.data[algernon_key] == ROWS[0]
assert table.data["algernon"] == ROWS[0]
assert table.data["charlie"] == ROWS[1]
assert table.data[auto_key] == ROWS[2]
first_row = Row(algernon_key, index=0, height=1, y=0)
assert table.rows[algernon_key] == first_row
assert table.rows["algernon"] == first_row
async def test_clear(): async def test_clear():
app = DataTableApp() app = DataTableApp()
async with app.run_test(): async with app.run_test():
@@ -147,6 +186,7 @@ async def test_clear():
# Ensure that the table has been cleared # Ensure that the table has been cleared
assert table.data == {} assert table.data == {}
assert table.rows == {} assert table.rows == {}
assert table.row_count == 0
assert len(table.columns) == 1 assert len(table.columns) == 1
# Clearing the columns too # Clearing the columns too
@@ -154,13 +194,31 @@ async def test_clear():
assert len(table.columns) == 0 assert len(table.columns) == 0
def test_add_rows_generates_keys(): async def test_column_labels() -> None:
table = DataTable() app = DataTableApp()
keys = table.add_rows(ROWS) async with app.run_test():
table = app.query_one(DataTable)
table.add_columns("1", "2", "3")
assert [col.label for col in table.columns] == [Text("1"), Text("2"), Text("3")]
# Ensure the keys are returned in order, and there's one for each row
for key, row in zip(keys, range(len(ROWS))): async def test_row_widths() -> None:
assert table.rows[key].index == row app = DataTableApp()
async with app.run_test() as pilot:
table = app.query_one(DataTable)
table.add_columns("foo", "bar")
assert table.columns[0].width == 3
assert table.columns[1].width == 3
table.add_row("Hello", "World!")
await pilot.pause()
assert table.columns[0].content_width == 5
assert table.columns[1].content_width == 6
table.add_row("Hello World!!!", "fo")
await pilot.pause()
assert table.columns[0].content_width == 14
assert table.columns[1].content_width == 6
def test_get_cell_value_returns_value_at_cell(): def test_get_cell_value_returns_value_at_cell():

View File

@@ -1,67 +0,0 @@
import asyncio
from rich.text import Text
from textual.app import App, ComposeResult
from textual.widgets import DataTable
class TableApp(App):
def compose(self) -> ComposeResult:
yield DataTable()
async def test_table_clear() -> None:
"""Check DataTable.clear"""
app = TableApp()
async with app.run_test() as pilot:
table = app.query_one(DataTable)
table.add_columns("foo", "bar")
assert table.row_count == 0
row_key = table.add_row("Hello", "World!")
assert [col.label for col in table.columns] == [Text("foo"), Text("bar")]
assert table.data == {row_key: ["Hello", "World!"]}
assert table.row_count == 1
table.clear()
assert [col.label for col in table.columns] == [Text("foo"), Text("bar")]
assert table.data == {}
assert table.row_count == 0
async def test_table_clear_with_columns() -> None:
"""Check DataTable.clear(columns=True)"""
app = TableApp()
async with app.run_test() as pilot:
table = app.query_one(DataTable)
table.add_columns("foo", "bar")
assert table.row_count == 0
row_key = table.add_row("Hello", "World!")
assert [col.label for col in table.columns] == [Text("foo"), Text("bar")]
assert table.data == {row_key: ["Hello", "World!"]}
assert table.row_count == 1
table.clear(columns=True)
assert [col.label for col in table.columns] == []
assert table.data == {}
assert table.row_count == 0
async def test_table_add_row() -> None:
app = TableApp()
async with app.run_test():
table = app.query_one(DataTable)
table.add_columns("foo", "bar")
assert table.columns[0].width == 3
assert table.columns[1].width == 3
table.add_row("Hello", "World!")
await asyncio.sleep(0)
assert table.columns[0].content_width == 5
assert table.columns[1].content_width == 6
table.add_row("Hello World!!!", "fo")
await asyncio.sleep(0)
assert table.columns[0].content_width == 14
assert table.columns[1].content_width == 6