textual: Querying TabPane by ID returns multiple nodes
When assigning an ID to a TabPane, it seems that there is always a corresponding ContentTab created with the same ID, and therefore failing query_one(id) calls.
This discussion thread is relevant, and I can use the TabPane#foo trick to workaround this issue. But this still seems to be a bug to me.
Repro:
from textual.app import App, ComposeResult
from textual.widgets import TabbedContent, TabPane, Button
class ExampleApp(App):
def compose(self) -> ComposeResult:
with TabbedContent():
yield TabPane("A", id="tab-a")
yield Button("Repro")
def on_button_pressed(self) -> None:
for node in self.query("#tab-a"):
self.log(f"### {node} ###")
self.query_one("#tab-a")
if __name__ == "__main__":
ExampleApp().run()
Clicking the button produces the following error:
TooManyMatches: Call to only_one resulted in more than one matched node
Relevant log lines in Textual console:
[01:05:37] INFO tabbed_content_bug.py:14
### ContentTab(id='tab-a') ###
[01:05:37] INFO tabbed_content_bug.py:14
### TabPane(id='tab-a') ###
Textual Diagnostics
Versions
| Name | Value |
|---|---|
| Textual | 0.41.0 |
| Rich | 13.5.2 |
Python
| Name | Value |
|---|---|
| Version | 3.11.2 |
| Implementation | CPython |
| Compiler | Clang 15.0.7 |
| Executable | /Users/lian/local/src/textual/main/.venv/bin/python |
Operating System
| Name | Value |
|---|---|
| System | Darwin |
| Release | 22.6.0 |
| Version | Darwin Kernel Version 22.6.0: Wed Jul 5 22:22:05 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T6000 |
Terminal
| Name | Value |
|---|---|
| Terminal Application | tmux (3.3a) |
| TERM | screen-256color |
| COLORTERM | truecolor |
| FORCE_COLOR | Not set |
| NO_COLOR | Not set |
Rich Console options
| Name | Value |
|---|---|
| size | width=80, height=23 |
| legacy_windows | False |
| min_width | 1 |
| max_width | 80 |
| is_terminal | False |
| encoding | utf-8 |
| max_height | 23 |
| justify | None |
| overflow | None |
| no_wrap | False |
| highlight | None |
| markup | None |
| height | None |
About this issue
- Original URL
- State: closed
- Created 7 months ago
- Comments: 19 (16 by maintainers)
Commits related to this issue
- :sparkles: Illustration for https://github.com/Textualize/textual/issues/3695 Example of why it would be a bad idea to "hide" the IDs for ContentTabs in a TabbedContent. — committed to davep/textual-sandbox by davep 7 months ago
- Experiment with namespacing the ContentTab IDs See #3695. — committed to davep/textual by davep 7 months ago
- :sparkles: Example for https://github.com/Textualize/textual/issues/3695 — committed to davep/textual-sandbox by davep 7 months ago
- Namespace the Tab IDs within a TabbedContent See #3695. — committed to davep/textual by davep 7 months ago
- Squashed commit of the following: commit 1e1b02398f356e710b5b44c6bee46c98ec2dc957 Author: Will McGugan <willmcgugan@gmail.com> Date: Thu Jan 4 17:09:43 2024 +0000 words commit 2801a41a8ff4d37... — committed to brokenshield/textual by brokenshield 6 months ago
Just realised there’s one huge gotcha here: the
@ondecorator andTabbedContent.TabActivated.tab(and more generally thetabproperty ofTabbedContent.TabActivated). While a developer might wish that aquery_oneof a givenTabPaneID result in just thatTabPaneand not the result that caused this re-issue, it would also seem reasonable that they’d expect to be able to write:and have it do the right thing. In retrospect it makes more sense that
TabbedContentdidn’t have aTabActivatedmessage but, instead, had aTabPaneActivatedmessage.Gonna need to think on this one.
TabPane”.TabbedContent, the user has no control on how theContentTabinstances are created.With these two 👆 clarifications, does my point make sense?
Hey @liancheng, thanks for the issue and for linking to the relevant discussion.
@willmcgugan, although this is “expected behaviour” in that we clearly implemented it this way, I think it makes no sense for us to cause this confusion to devs and to have queries break for no good reason.
As for a fix, something as simple as prefixing the internal IDs might cut it.