Datatable remove row (#2253)

* Checking in remove_row progress

* Ensuring structures updated correctly when row deleted

* Clamping index

* Failed attempt

* Removing rows

* Update a type hint in DataTable

* Remove some code that wasnt required

* Use index syntax instead of get

* Add DataTable remove row test

* Snapshot tests for removing rows

* Add a docstring for DataTable.remove_row method

* Update changelog regarding DataTable.remove_row

* Add check_idle call to remove_row
This commit is contained in:
darrenburns
2023-04-11 18:48:58 +01:00
committed by GitHub
parent 13939499d9
commit 6352ceb61b
7 changed files with 273 additions and 2 deletions

View File

@@ -5,11 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Added
- Added `DataTable.remove_row` method https://github.com/Textualize/textual/pull/2253
- `Widget.scroll_to_center` now scrolls the widget to the center of the screen https://github.com/Textualize/textual/pull/2255
## [0.19.1] - 2023-04-10

View File

@@ -29,6 +29,9 @@ class TwoWayDict(Generic[Key, Value]):
self._forward.__delitem__(key)
self._reverse.__delitem__(value)
def __iter__(self):
return iter(self._forward)
def get(self, key: Key) -> Value:
"""Given a key, efficiently lookup and return the associated value.

View File

@@ -308,7 +308,9 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
cursor_coordinate: Reactive[Coordinate] = Reactive(
Coordinate(0, 0), repaint=False, always_update=True
)
hover_coordinate: Reactive[Coordinate] = Reactive(Coordinate(0, 0), repaint=False)
hover_coordinate: Reactive[Coordinate] = Reactive(
Coordinate(0, 0), repaint=False, always_update=True
)
class CellHighlighted(Message, bubble=True):
"""Posted when the cursor moves to highlight a new cell.
@@ -1186,6 +1188,10 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
self._label_column = Column(self._label_column_key, Text(), auto_width=True)
self._labelled_row_exists = False
self.refresh()
self.scroll_x = 0
self.scroll_y = 0
self.scroll_target_x = 0
self.scroll_target_y = 0
return self
def add_column(
@@ -1322,6 +1328,41 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
row_keys.append(row_key)
return row_keys
def remove_row(self, row_key: RowKey | str) -> None:
"""Remove a row (identified by a key) from the DataTable.
Args:
row_key: The key identifying the row to remove.
Raises:
RowDoesNotExist: If the row key does not exist.
"""
if row_key not in self._row_locations:
raise RowDoesNotExist(f"Row key {row_key!r} is not valid.")
self._require_update_dimensions = True
self.check_idle()
index_to_delete = self._row_locations.get(row_key)
new_row_locations = TwoWayDict({})
for row_location_key in self._row_locations:
row_index = self._row_locations.get(row_location_key)
if row_index > index_to_delete:
new_row_locations[row_location_key] = row_index - 1
elif row_index < index_to_delete:
new_row_locations[row_location_key] = row_index
self._row_locations = new_row_locations
del self.rows[row_key]
del self._data[row_key]
self.cursor_coordinate = self.cursor_coordinate
self.hover_coordinate = self.hover_coordinate
self._update_count += 1
self.refresh(layout=True)
def on_idle(self) -> None:
"""Runs when the message pump is empty.

View File

@@ -12593,6 +12593,164 @@
'''
# ---
# name: test_datatable_remove_row
'''
<svg class="rich-terminal" viewBox="0 0 994 635.5999999999999" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Regular"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Bold"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
font-style: bold;
font-weight: 700;
}
.terminal-2304919999-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
.terminal-2304919999-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
.terminal-2304919999-r1 { fill: #dde6ed;font-weight: bold }
.terminal-2304919999-r2 { fill: #dde6ed }
.terminal-2304919999-r3 { fill: #c5c8c6 }
.terminal-2304919999-r4 { fill: #211505 }
.terminal-2304919999-r5 { fill: #e1e1e1 }
</style>
<defs>
<clipPath id="terminal-2304919999-clip-terminal">
<rect x="0" y="0" width="975.0" height="584.5999999999999" />
</clipPath>
<clipPath id="terminal-2304919999-line-0">
<rect x="0" y="1.5" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-1">
<rect x="0" y="25.9" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-2">
<rect x="0" y="50.3" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-3">
<rect x="0" y="74.7" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-4">
<rect x="0" y="99.1" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-5">
<rect x="0" y="123.5" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-6">
<rect x="0" y="147.9" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-7">
<rect x="0" y="172.3" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-8">
<rect x="0" y="196.7" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-9">
<rect x="0" y="221.1" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-10">
<rect x="0" y="245.5" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-11">
<rect x="0" y="269.9" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-12">
<rect x="0" y="294.3" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-13">
<rect x="0" y="318.7" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-14">
<rect x="0" y="343.1" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-15">
<rect x="0" y="367.5" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-16">
<rect x="0" y="391.9" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-17">
<rect x="0" y="416.3" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-18">
<rect x="0" y="440.7" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-19">
<rect x="0" y="465.1" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-20">
<rect x="0" y="489.5" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-21">
<rect x="0" y="513.9" width="976" height="24.65"/>
</clipPath>
<clipPath id="terminal-2304919999-line-22">
<rect x="0" y="538.3" width="976" height="24.65"/>
</clipPath>
</defs>
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="992" height="633.6" rx="8"/><text class="terminal-2304919999-title" fill="#c5c8c6" text-anchor="middle" x="496" y="27">TableApp</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
<circle cx="44" cy="0" r="7" fill="#28c840"/>
</g>
<g transform="translate(9, 41)" clip-path="url(#terminal-2304919999-clip-terminal)">
<rect fill="#004578" x="0" y="1.5" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#004578" x="73.2" y="1.5" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#004578" x="341.6" y="1.5" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#004578" x="524.6" y="1.5" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#073b61" x="610" y="1.5" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#fea62b" x="0" y="25.9" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="25.9" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="25.9" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="25.9" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="25.9" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="50.3" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="50.3" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="50.3" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="50.3" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="50.3" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="74.7" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="74.7" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="74.7" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="74.7" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="74.7" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="99.1" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="99.1" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="99.1" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="99.1" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="99.1" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="123.5" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="123.5" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="123.5" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="123.5" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="123.5" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="147.9" width="73.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="73.2" y="147.9" width="268.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="147.9" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="524.6" y="147.9" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="147.9" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="172.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="196.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="221.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="245.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="269.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="294.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="318.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="343.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="367.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="391.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="416.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="440.7" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="465.1" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="489.5" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="513.9" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="538.3" width="976" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="562.7" width="976" height="24.65" shape-rendering="crispEdges"/>
<g class="terminal-2304919999-matrix">
<text class="terminal-2304919999-r1" x="0" y="20" textLength="73.2" clip-path="url(#terminal-2304919999-line-0)">&#160;lane&#160;</text><text class="terminal-2304919999-r1" x="73.2" y="20" textLength="268.4" clip-path="url(#terminal-2304919999-line-0)">&#160;swimmer&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r1" x="341.6" y="20" textLength="183" clip-path="url(#terminal-2304919999-line-0)">&#160;country&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r1" x="524.6" y="20" textLength="85.4" clip-path="url(#terminal-2304919999-line-0)">&#160;time&#160;&#160;</text><text class="terminal-2304919999-r3" x="976" y="20" textLength="12.2" clip-path="url(#terminal-2304919999-line-0)">
</text><text class="terminal-2304919999-r4" x="0" y="44.4" textLength="73.2" clip-path="url(#terminal-2304919999-line-1)">&#160;5&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="44.4" textLength="268.4" clip-path="url(#terminal-2304919999-line-1)">&#160;Chad&#160;le&#160;Clos&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="44.4" textLength="183" clip-path="url(#terminal-2304919999-line-1)">&#160;South&#160;Africa&#160;&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="44.4" textLength="85.4" clip-path="url(#terminal-2304919999-line-1)">&#160;51.14&#160;</text><text class="terminal-2304919999-r3" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-2304919999-line-1)">
</text><text class="terminal-2304919999-r5" x="0" y="68.8" textLength="73.2" clip-path="url(#terminal-2304919999-line-2)">&#160;4&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="68.8" textLength="268.4" clip-path="url(#terminal-2304919999-line-2)">&#160;Joseph&#160;Schooling&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="68.8" textLength="183" clip-path="url(#terminal-2304919999-line-2)">&#160;Singapore&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="68.8" textLength="85.4" clip-path="url(#terminal-2304919999-line-2)">&#160;50.39&#160;</text><text class="terminal-2304919999-r3" x="976" y="68.8" textLength="12.2" clip-path="url(#terminal-2304919999-line-2)">
</text><text class="terminal-2304919999-r5" x="0" y="93.2" textLength="73.2" clip-path="url(#terminal-2304919999-line-3)">&#160;6&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="93.2" textLength="268.4" clip-path="url(#terminal-2304919999-line-3)">&#160;László&#160;Cseh&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="93.2" textLength="183" clip-path="url(#terminal-2304919999-line-3)">&#160;Hungary&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="93.2" textLength="85.4" clip-path="url(#terminal-2304919999-line-3)">&#160;51.14&#160;</text><text class="terminal-2304919999-r3" x="976" y="93.2" textLength="12.2" clip-path="url(#terminal-2304919999-line-3)">
</text><text class="terminal-2304919999-r5" x="0" y="117.6" textLength="73.2" clip-path="url(#terminal-2304919999-line-4)">&#160;3&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="117.6" textLength="268.4" clip-path="url(#terminal-2304919999-line-4)">&#160;Li&#160;Zhuhao&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="117.6" textLength="183" clip-path="url(#terminal-2304919999-line-4)">&#160;China&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="117.6" textLength="85.4" clip-path="url(#terminal-2304919999-line-4)">&#160;51.26&#160;</text><text class="terminal-2304919999-r3" x="976" y="117.6" textLength="12.2" clip-path="url(#terminal-2304919999-line-4)">
</text><text class="terminal-2304919999-r5" x="0" y="142" textLength="73.2" clip-path="url(#terminal-2304919999-line-5)">&#160;7&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="142" textLength="268.4" clip-path="url(#terminal-2304919999-line-5)">&#160;Tom&#160;Shields&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="142" textLength="183" clip-path="url(#terminal-2304919999-line-5)">&#160;United&#160;States&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="142" textLength="85.4" clip-path="url(#terminal-2304919999-line-5)">&#160;51.73&#160;</text><text class="terminal-2304919999-r3" x="976" y="142" textLength="12.2" clip-path="url(#terminal-2304919999-line-5)">
</text><text class="terminal-2304919999-r5" x="0" y="166.4" textLength="73.2" clip-path="url(#terminal-2304919999-line-6)">&#160;10&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="73.2" y="166.4" textLength="268.4" clip-path="url(#terminal-2304919999-line-6)">&#160;Darren&#160;Burns&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="341.6" y="166.4" textLength="183" clip-path="url(#terminal-2304919999-line-6)">&#160;Scotland&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-2304919999-r5" x="524.6" y="166.4" textLength="85.4" clip-path="url(#terminal-2304919999-line-6)">&#160;51.84&#160;</text><text class="terminal-2304919999-r3" x="976" y="166.4" textLength="12.2" clip-path="url(#terminal-2304919999-line-6)">
</text><text class="terminal-2304919999-r3" x="976" y="190.8" textLength="12.2" clip-path="url(#terminal-2304919999-line-7)">
</text><text class="terminal-2304919999-r3" x="976" y="215.2" textLength="12.2" clip-path="url(#terminal-2304919999-line-8)">
</text><text class="terminal-2304919999-r3" x="976" y="239.6" textLength="12.2" clip-path="url(#terminal-2304919999-line-9)">
</text><text class="terminal-2304919999-r3" x="976" y="264" textLength="12.2" clip-path="url(#terminal-2304919999-line-10)">
</text><text class="terminal-2304919999-r3" x="976" y="288.4" textLength="12.2" clip-path="url(#terminal-2304919999-line-11)">
</text><text class="terminal-2304919999-r3" x="976" y="312.8" textLength="12.2" clip-path="url(#terminal-2304919999-line-12)">
</text><text class="terminal-2304919999-r3" x="976" y="337.2" textLength="12.2" clip-path="url(#terminal-2304919999-line-13)">
</text><text class="terminal-2304919999-r3" x="976" y="361.6" textLength="12.2" clip-path="url(#terminal-2304919999-line-14)">
</text><text class="terminal-2304919999-r3" x="976" y="386" textLength="12.2" clip-path="url(#terminal-2304919999-line-15)">
</text><text class="terminal-2304919999-r3" x="976" y="410.4" textLength="12.2" clip-path="url(#terminal-2304919999-line-16)">
</text><text class="terminal-2304919999-r3" x="976" y="434.8" textLength="12.2" clip-path="url(#terminal-2304919999-line-17)">
</text><text class="terminal-2304919999-r3" x="976" y="459.2" textLength="12.2" clip-path="url(#terminal-2304919999-line-18)">
</text><text class="terminal-2304919999-r3" x="976" y="483.6" textLength="12.2" clip-path="url(#terminal-2304919999-line-19)">
</text><text class="terminal-2304919999-r3" x="976" y="508" textLength="12.2" clip-path="url(#terminal-2304919999-line-20)">
</text><text class="terminal-2304919999-r3" x="976" y="532.4" textLength="12.2" clip-path="url(#terminal-2304919999-line-21)">
</text><text class="terminal-2304919999-r3" x="976" y="556.8" textLength="12.2" clip-path="url(#terminal-2304919999-line-22)">
</text>
</g>
</g>
</svg>
'''
# ---
# name: test_datatable_render
'''
<svg class="rich-terminal" viewBox="0 0 994 635.5999999999999" xmlns="http://www.w3.org/2000/svg">

View File

@@ -0,0 +1,51 @@
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.widgets import DataTable
ROWS = [
("lane", "swimmer", "country", "time"),
(5, "Chad le Clos", "South Africa", 51.14),
(4, "Joseph Schooling", "Singapore", 50.39),
(2, "Michael Phelps", "United States", 51.14),
(6, "László Cseh", "Hungary", 51.14),
(3, "Li Zhuhao", "China", 51.26),
(8, "Mehdy Metella", "France", 51.58),
(7, "Tom Shields", "United States", 51.73),
(10, "Darren Burns", "Scotland", 51.84),
(1, "Aleksandr Sadovnikov", "Russia", 51.84),
]
class TableApp(App):
"""Snapshot app for testing removal of rows.
Removes several rows, so we can check that the display of the
DataTable updates as expected."""
BINDINGS = [
Binding("r", "remove_row", "Remove Row"),
]
def compose(self) -> ComposeResult:
yield DataTable()
def on_mount(self) -> None:
table = self.query_one(DataTable)
table.focus()
rows = iter(ROWS)
column_labels = next(rows)
for column in column_labels:
table.add_column(column, key=column)
for row in rows:
table.add_row(*row, key=str(row[0]))
def action_remove_row(self):
table = self.query_one(DataTable)
table.remove_row("2")
table.remove_row("8")
table.remove_row("1")
app = TableApp()
if __name__ == "__main__":
app.run()

View File

@@ -116,6 +116,11 @@ def test_datatable_sort_multikey(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "data_table_sort.py", press=press)
def test_datatable_remove_row(snap_compare):
press = ["r"]
assert snap_compare(SNAPSHOT_APPS_DIR / "data_table_remove_row.py", press=press)
def test_datatable_labels_and_fixed_data(snap_compare):
# Ensure that we render correctly when there are fixed rows/cols and labels.
assert snap_compare(SNAPSHOT_APPS_DIR / "data_table_row_labels.py")

View File

@@ -289,6 +289,19 @@ async def test_add_columns_user_defined_keys():
assert key == key
async def test_remove_row():
app = DataTableApp()
async with app.run_test():
table = app.query_one(DataTable)
table.add_columns("A", "B")
for row in ROWS:
table.add_row(row, key=row[0])
assert len(table.rows) == 3
table.remove_row(ROWS[0][0])
assert len(table.rows) == 2
async def test_clear():
app = DataTableApp()
async with app.run_test():