mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
DataTable sort by function (or other callable) (#3090)
* DataTable sort by function (or other callable) The `DataTable` widget now takes the `by` argument instead of `columns`, allowing the table to also be sorted using a custom function (or other callable). This is a breaking change since it requires all calls to the `sort` method to include an iterable of key(s) (or a singular function/callable). Covers #2261 using [suggested function signature](https://github.com/Textualize/textual/pull/2512#issuecomment-1580277771) from @darrenburns on PR #2512. * argument change and functionaloty update Changed back to orinal `columns` argument and added a new `key` argument which takes a function (or other callable). This allows the PR to NOT BE a breaking change. * better example for docs - Updated the example file for the docs to better show the functionality of the change (especially when using `columns` and `key` together). - Added one new tests to cover a similar situation to the example changes * removed unecessary code from example - the sort by clicked column function was bloat in my opinion * requested changes * simplify method and terminology * combine key_wrapper and default sort * Removing some tests from DataTable.sort as duplicates. Ensure there is test coverage of the case where a key, but no columns, is passed to DataTable.sort. * Remove unused import * Fix merge issues in CHANGELOG, update DataTable sort-by-key changelog PR link --------- Co-authored-by: Darren Burns <darrenburns@users.noreply.github.com> Co-authored-by: Darren Burns <darrenb900@gmail.com>
This commit is contained in:
92
docs/examples/widgets/data_table_sort.py
Normal file
92
docs/examples/widgets/data_table_sort.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from rich.text import Text
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import DataTable, Footer
|
||||
|
||||
ROWS = [
|
||||
("lane", "swimmer", "country", "time 1", "time 2"),
|
||||
(4, "Joseph Schooling", Text("Singapore", style="italic"), 50.39, 51.84),
|
||||
(2, "Michael Phelps", Text("United States", style="italic"), 50.39, 51.84),
|
||||
(5, "Chad le Clos", Text("South Africa", style="italic"), 51.14, 51.73),
|
||||
(6, "László Cseh", Text("Hungary", style="italic"), 51.14, 51.58),
|
||||
(3, "Li Zhuhao", Text("China", style="italic"), 51.26, 51.26),
|
||||
(8, "Mehdy Metella", Text("France", style="italic"), 51.58, 52.15),
|
||||
(7, "Tom Shields", Text("United States", style="italic"), 51.73, 51.12),
|
||||
(1, "Aleksandr Sadovnikov", Text("Russia", style="italic"), 51.84, 50.85),
|
||||
(10, "Darren Burns", Text("Scotland", style="italic"), 51.84, 51.55),
|
||||
]
|
||||
|
||||
|
||||
class TableApp(App):
|
||||
BINDINGS = [
|
||||
("a", "sort_by_average_time", "Sort By Average Time"),
|
||||
("n", "sort_by_last_name", "Sort By Last Name"),
|
||||
("c", "sort_by_country", "Sort By Country"),
|
||||
("d", "sort_by_columns", "Sort By Columns (Only)"),
|
||||
]
|
||||
|
||||
current_sorts: set = set()
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield DataTable()
|
||||
yield Footer()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
table = self.query_one(DataTable)
|
||||
for col in ROWS[0]:
|
||||
table.add_column(col, key=col)
|
||||
table.add_rows(ROWS[1:])
|
||||
|
||||
def sort_reverse(self, sort_type: str):
|
||||
"""Determine if `sort_type` is ascending or descending."""
|
||||
reverse = sort_type in self.current_sorts
|
||||
if reverse:
|
||||
self.current_sorts.remove(sort_type)
|
||||
else:
|
||||
self.current_sorts.add(sort_type)
|
||||
return reverse
|
||||
|
||||
def action_sort_by_average_time(self) -> None:
|
||||
"""Sort DataTable by average of times (via a function) and
|
||||
passing of column data through positional arguments."""
|
||||
|
||||
def sort_by_average_time_then_last_name(row_data):
|
||||
name, *scores = row_data
|
||||
return (sum(scores) / len(scores), name.split()[-1])
|
||||
|
||||
table = self.query_one(DataTable)
|
||||
table.sort(
|
||||
"swimmer",
|
||||
"time 1",
|
||||
"time 2",
|
||||
key=sort_by_average_time_then_last_name,
|
||||
reverse=self.sort_reverse("time"),
|
||||
)
|
||||
|
||||
def action_sort_by_last_name(self) -> None:
|
||||
"""Sort DataTable by last name of swimmer (via a lambda)."""
|
||||
table = self.query_one(DataTable)
|
||||
table.sort(
|
||||
"swimmer",
|
||||
key=lambda swimmer: swimmer.split()[-1],
|
||||
reverse=self.sort_reverse("swimmer"),
|
||||
)
|
||||
|
||||
def action_sort_by_country(self) -> None:
|
||||
"""Sort DataTable by country which is a `Rich.Text` object."""
|
||||
table = self.query_one(DataTable)
|
||||
table.sort(
|
||||
"country",
|
||||
key=lambda country: country.plain,
|
||||
reverse=self.sort_reverse("country"),
|
||||
)
|
||||
|
||||
def action_sort_by_columns(self) -> None:
|
||||
"""Sort DataTable without a key."""
|
||||
table = self.query_one(DataTable)
|
||||
table.sort("swimmer", "lane", reverse=self.sort_reverse("columns"))
|
||||
|
||||
|
||||
app = TableApp()
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
Reference in New Issue
Block a user