beeware / beeware/toga

Improve setting Selection by value

Open
#3,986 4 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.