Improve setting Selection by value
- Dominant language
- Python
- Stars
- 5.4k
- Forks
- 827
- Avg merge
- 9h 45m
- Merged PRs (30d)
- 58
Description
### What is the problem or limitation you are having?
If you have a selection that uses rich value (i.e., list of dictionaries) or a ListSource, the `value` setter requires the use of a Row object.
As an example - an extract from the `selection` example:
```python
DATA_OPTIONS = [
{"name": "Carbon", "number": 6, "weight": 12.011},
{"name": "Ytterbium", "number": 70, "weight": 173.04},
{"name": "Thulium", "number": 69, "weight": 168.93},
]
self.source_selection = toga.Selection(
accessor="name",
items=DATA_OPTIONS,
)
```
In this setup, it is not possible to use `"Carbon"` or `6` to set the value of the selection; you have to use:
```python
self.source_selection.value = self.source_selection.items.find({"name": "Carbon"})
```
or
```python
self.source_selection.value = self.source_selection.items.find({"number": 6})
```
While this is logically consistent, it isn't a very intuitive API. It also isn't possible to set the value in the constructor, as the items won't exist until after the selection has been created.
It would make more sense to be able to reference actual data.
### Describe the solution you'd like
It should be possible to set the selection by accessor value:
```Python
self.source_selection = toga.Selection(
accessor="name",
items=DATA_OPTIONS,
value="Carbon"
)
# or later
self.source_selection.value = "Carbon"
```
Or by any other value-based search:
```Python
self.source_selection = toga.Selection(
accessor="name",
items=DATA_OPTIONS,
value={"number": 6}
)
# or later
self.source_selection.value = {"number": 6}
```
Setting by explicit row should remain an option; but only if the value provided to the setter is a literal Row object.
### Describe alternatives you've considered
Do nothing. The current API *works*... just not well.
I don't see any other viable API options.
### Additional context
Originally reported via #3976.
The implementation of the `value` setter on Selection already has `find()`-based handling if the data source has a single column and no explicit accessor; this change would extend that `find()` based handling to catch the cases that won't work for an `index()` lookup (i.e., anything other than a Row). These cases will already raise an error, so there's no backwards compatibility concern here.
Contributor guide
Research direction
Start at the Selection value setter and compare its existing find()-based handling with the selection example using DATA_OPTIONS and an accessor. Extend the behavior so accessor values and value-based searches resolve to the matching item while literal Row objects remain supported; verify constructor and later assignment cases, including the existing error paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- desktop
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100