Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Select.from_values class method for initializing with iterator #3743

Merged
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8f7fdb0
prototype to use class method to initialize Select object using an it…
azinneck0485 Nov 21, 2023
5793ef1
add docstring and optional arguments to Select.from_values()
azinneck0485 Nov 23, 2023
450553f
add test widget for Select.from_values() and update documentation to …
azinneck0485 Nov 23, 2023
bafaf97
add snapshot tests to Select.from_values() class method and update sn…
azinneck0485 Nov 23, 2023
4fe0ecf
update changelog
azinneck0485 Nov 23, 2023
c9cb679
changes to Select.from_value doc and variables names per PR review co…
azinneck0485 Nov 25, 2023
029d96f
Merge remote-tracking branch 'upstream/main' into Issue3691_AltSelect…
azinneck0485 Nov 25, 2023
fc874aa
fix merge mistakes
azinneck0485 Nov 25, 2023
5cccc2d
fix more merge mistakes
azinneck0485 Nov 25, 2023
2a403c3
fix more merge mistakes (typos)
azinneck0485 Nov 25, 2023
7d869bd
change Select.from_value() input parameters to match changes made fro…
azinneck0485 Nov 25, 2023
e6264b1
re-update snapshots for Select.from_values()
azinneck0485 Nov 25, 2023
c14aa59
add new tests for Select.from() based on related tests added by merge
azinneck0485 Nov 25, 2023
0ee6aff
update changelog
azinneck0485 Nov 25, 2023
5c0ea97
update another snapshot
azinneck0485 Nov 25, 2023
2a6db4b
update Select documentation per code review
azinneck0485 Nov 28, 2023
23bb964
update doc string and variable names in _select.py per code review
azinneck0485 Nov 28, 2023
d305aec
Merge branch 'main' into Issue3691_AltSelectInit
rodrigogiraoserrao Nov 30, 2023
ed3f106
Fix docstrings.
rodrigogiraoserrao Nov 30, 2023
ae1a43a
add return type hint for from_values class method
azinneck0485 Nov 30, 2023
6516920
remove unneeded snapshot tests for Select.from_values and update snap…
azinneck0485 Nov 30, 2023
903920d
Merge remote-tracking branch 'origin/Issue3691_AltSelectInit' into Is…
azinneck0485 Nov 30, 2023
91efd51
update snapshots again after merge
azinneck0485 Dec 1, 2023
4a21734
change type hint for Select.from_values based on review comments
azinneck0485 Dec 1, 2023
3c484a8
docstring and type hint changes to Select.from_values per code review…
azinneck0485 Dec 5, 2023
b9f063b
Add period.
rodrigogiraoserrao Dec 5, 2023
986f14e
Merge branch 'main' into Issue3691_AltSelectInit
rodrigogiraoserrao Dec 5, 2023
81727f9
Merge branch 'main' into Issue3691_AltSelectInit
rodrigogiraoserrao Dec 5, 2023
5a75777
Update snapshot.
rodrigogiraoserrao Dec 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Added support for Ctrl+Fn and Ctrl+Shift+Fn keys in urxvt https://github.com/Textualize/textual/pull/3737
- Friendly error messages when trying to mount non-widgets https://github.com/Textualize/textual/pull/3780
- Added `Select.from_values` class method that can be used to initialize a Select control with an iterator of values https://github.com/Textualize/textual/pull/3743

## [0.43.2] - 2023-11-29

Expand Down
26 changes: 26 additions & 0 deletions docs/examples/widgets/select_from_values_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from textual import on
from textual.app import App, ComposeResult
from textual.widgets import Header, Select

LINES = """I must not fear.
Fear is the mind-killer.
Fear is the little-death that brings total obliteration.
I will face my fear.
I will permit it to pass over me and through me.""".splitlines()


class SelectApp(App):
CSS_PATH = "select.tcss"

def compose(self) -> ComposeResult:
yield Header()
yield Select.from_values(LINES)

@on(Select.Changed)
def select_changed(self, event: Select.Changed) -> None:
self.title = str(event.value)


if __name__ == "__main__":
app = SelectApp()
app.run()
30 changes: 29 additions & 1 deletion docs/widgets/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ my_select: Select[int] = Select(options)

If you aren't familiar with typing or don't want to worry about it right now, feel free to ignore it.

## Example
## Examples

### Basic Example

The following example presents a `Select` with a number of options.

Expand All @@ -57,6 +59,32 @@ The following example presents a `Select` with a number of options.
--8<-- "docs/examples/widgets/select.tcss"
```

### Example using Class Method

The following example presents a `Select` created using the `from_values` class method.

=== "Output"

```{.textual path="docs/examples/widgets/select_from_values_widget.py"}
```

=== "Output (expanded)"

```{.textual path="docs/examples/widgets/select_from_values_widget.py" press="tab,enter,down,down"}
```


=== "select_from_values_widget.py"

```python
--8<-- "docs/examples/widgets/select_from_values_widget.py"
```

=== "select.tcss"

```sass
--8<-- "docs/examples/widgets/select.tcss"
```

## Blank state

Expand Down
55 changes: 53 additions & 2 deletions src/textual/widgets/_select.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import sys
azinneck0485 marked this conversation as resolved.
Show resolved Hide resolved
from dataclasses import dataclass
from typing import TYPE_CHECKING, Generic, Iterable, TypeVar, Union

Expand All @@ -19,6 +20,11 @@

from ..app import ComposeResult

if sys.version_info.minor >= 11:
from typing import Self
else:
from typing_extensions import Self


azinneck0485 marked this conversation as resolved.
Show resolved Hide resolved
class NoSelection:
"""Used by the `Select` widget to flag the unselected state. See [`Select.BLANK`][textual.widgets.Select.BLANK]."""
Expand Down Expand Up @@ -284,15 +290,15 @@ def __init__(
Args:
options: Options to select from. If no options are provided then
`allow_blank` must be set to `True`.
prompt: Text to show in the control when no option is select.
prompt: Text to show in the control when no option is selected.
allow_blank: Enables or disables the ability to have the widget in a state
with no selection made, in which case its value is set to the constant
[`Select.BLANK`][textual.widgets.Select.BLANK].
value: Initial value selected. Should be one of the values in `options`.
If no initial value is set and `allow_blank` is `False`, the widget
will auto-select the first available option.
name: The name of the select control.
id: The ID of the control the DOM.
id: The ID of the control in the DOM.
classes: The CSS classes of the control.
disabled: Whether the control is disabled or not.

Expand All @@ -305,6 +311,51 @@ def __init__(
self._value = value
self._setup_variables_for_options(options)

@classmethod
def from_values(
cls,
values: Iterable[SelectType],
*,
prompt: str = "Select",
allow_blank: bool = True,
value: SelectType | NoSelection = BLANK,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
disabled: bool = False,
) -> Self:
azinneck0485 marked this conversation as resolved.
Show resolved Hide resolved
"""Initialize the Select control with values specified by an arbitrary iterable

The options shown in the control are computed by calling the built-in `str`
on each value.

Args:
values: Values used to generate options to select from.
prompt: Text to show in the control when no option is selected.
allow_blank: Enables or disables the ability to have the widget in a state
with no selection made, in which case its value is set to the constant
[`Select.BLANK`][textual.widgets.Select.BLANK].
value: Initial value selected. Should be one of the values in `values`.
If no initial value is set and `allow_blank` is `False`, the widget
will auto-select the first available value.
name: The name of the select control.
id: The ID of the control in the DOM.
classes: The CSS classes of the control.
disabled: Whether the control is disabled or not.
"""
azinneck0485 marked this conversation as resolved.
Show resolved Hide resolved
options_iterator = [(str(value), value) for value in values]

return cls(
options_iterator,
prompt=prompt,
allow_blank=allow_blank,
value=value,
name=name,
id=id,
classes=classes,
disabled=disabled,
)

def _setup_variables_for_options(
self,
options: Iterable[tuple[RenderableType, SelectType]],
Expand Down
Loading