Merge pull request #2508 from davep/add-options

Add `add_options` to `OptionList`
This commit is contained in:
Dave Pearson
2023-05-08 10:51:15 +01:00
committed by GitHub
7 changed files with 244 additions and 11 deletions

View File

@@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Method `DataTable.move_cursor` https://github.com/Textualize/textual/issues/2472
### Added
- Added `OptionList.add_options` https://github.com/Textualize/textual/pull/2508
## [0.23.0] - 2023-05-03
### Fixed

View File

@@ -4,7 +4,6 @@ from rich.table import Table
from textual.app import App, ComposeResult
from textual.widgets import Footer, Header, OptionList
from textual.widgets.option_list import Option, Separator
COLONIES: tuple[tuple[str, str, str, str], ...] = (
("Aerilon", "Demeter", "1.2 Billion", "Gaoth"),

View File

@@ -7,7 +7,7 @@ forms of bounce-bar menu.
from __future__ import annotations
from typing import ClassVar, NamedTuple
from typing import ClassVar, Iterable, NamedTuple
from rich.console import RenderableType
from rich.repr import Result
@@ -508,6 +508,31 @@ class OptionList(ScrollView, can_focus=True):
# list, set the virtual size.
self.virtual_size = Size(self.scrollable_content_region.width, len(self._lines))
def add_options(self, items: Iterable[NewOptionListContent]) -> Self:
"""Add new options to the end of the option list.
Args:
items: The new items to add.
Returns:
The `OptionList` instance.
Raises:
DuplicateID: If there is an attempt to use a duplicate ID.
"""
# Only work if we have items to add; but don't make a fuss out of
# zero items to add, just carry on like nothing happened.
if items:
# Turn any incoming values into valid content for the list.
content = [self._make_content(item) for item in items]
self._contents.extend(content)
# Pull out the content that is genuine options and add them to the
# list of options.
self._options.extend([item for item in content if isinstance(item, Option)])
self._refresh_content_tracking(force=True)
self.refresh()
return self
def add_option(self, item: NewOptionListContent = None) -> Self:
"""Add a new option to the end of the option list.
@@ -520,15 +545,7 @@ class OptionList(ScrollView, can_focus=True):
Raises:
DuplicateID: If there is an attempt to use a duplicate ID.
"""
# Turn any incoming value into valid content for the list.
content = self._make_content(item)
self._contents.append(content)
# If the content is a genuine option, add it to the list of options.
if isinstance(content, Option):
self._options.append(content)
self._refresh_content_tracking(force=True)
self.refresh()
return self
return self.add_options([item])
def _remove_option(self, index: int) -> None:
"""Remove an option from the option list.

View File

@@ -106,6 +106,14 @@ async def test_add_later() -> None:
assert option_list.option_count == 6
option_list.add_option(Option("even more"))
assert option_list.option_count == 7
option_list.add_options(
[Option("more still"), "Yet more options", "so many options!"]
)
assert option_list.option_count == 10
option_list.add_option(None)
assert option_list.option_count == 10
option_list.add_options([])
assert option_list.option_count == 10
async def test_create_with_duplicate_id() -> None:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,45 @@
from __future__ import annotations
from rich.text import Text
from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.widgets import OptionList
from textual.widgets.option_list import Option
class OptionListApp(App[None]):
def compose( self ) -> ComposeResult:
with Horizontal():
yield OptionList(
"One",
Option("Two"),
None,
Text.from_markup("[red]Three[/]")
)
yield OptionList(id="later-individual")
yield OptionList(id="later-at-once")
def on_mount(self) -> None:
options: list[None | str | Text | Option] = [
"One",
Option("Two"),
None,
Text.from_markup("[red]Three[/]"),
]
option_list = self.query_one("#later-individual", OptionList)
for option in options:
option_list.add_option(option)
option_list.highlighted = 0
option_list = self.query_one("#later-at-once", OptionList)
option_list.add_options([
"One",
Option("Two"),
None,
Text.from_markup("[red]Three[/]"),
])
option_list.highlighted = 0
if __name__ == "__main__":
OptionListApp().run()

View File

@@ -203,6 +203,8 @@ def test_option_list(snap_compare):
assert snap_compare(WIDGET_EXAMPLES_DIR / "option_list_options.py")
assert snap_compare(WIDGET_EXAMPLES_DIR / "option_list_tables.py")
def test_option_list_build(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "option_list.py")
def test_progress_bar_indeterminate(snap_compare):
assert snap_compare(WIDGET_EXAMPLES_DIR / "progress_bar_isolated_.py", press=["f"])