From a1e63a1c023909731ad0f5f2337d7e75e000b3f8 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 5 Jan 2023 09:21:52 +0000 Subject: [PATCH 1/5] Process the label on construction of a TreeNode Currently there's an asymmetry in how the label is handled for a TreeNode. If a str label is passed to the constructor it stays as a str type. On the other hand, if it's set via set_label, it gets processed into a Rich Text type. This commit removes that asymmetry. --- src/textual/widgets/_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index e23385502..d457d8533 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -71,7 +71,7 @@ class TreeNode(Generic[TreeDataType]): self._tree = tree self._parent = parent self._id = id - self._label = label + self._label = tree.process_label(label) self.data = data self._expanded = expanded self._children: list[TreeNode] = [] From b8a329638e15f469452fb11a9d382e6794875c90 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 5 Jan 2023 09:37:08 +0000 Subject: [PATCH 2/5] Add public access to a TreeNode's label This adds public support to reading a TreeNode's label, and also setting it too. See #1396. --- CHANGELOG.md | 10 ++++++++-- src/textual/widgets/_tree.py | 11 +++++++++++ tests/test_tree.py | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/test_tree.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ee7b9a67..d6485bd50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.10.0] - Unreleased + +### Added + +- Added public `TreeNode` label access via `TreeNode.label` https://github.com/Textualize/textual/issues/1396 + ## [0.9.1] - 2022-12-30 ### Added @@ -23,8 +29,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Widget.render_line now returns a Strip - Fix for slow updates on Windows -- Bumped Rich dependency - +- Bumped Rich dependency + ## [0.8.2] - 2022-12-28 ### Fixed diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index d457d8533..f88dcf60c 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -163,6 +163,17 @@ class TreeNode(Generic[TreeDataType]): self._updates += 1 self._tree._invalidate() + @property + def label(self) -> TextType: + """TextType: The label for the node.""" + return self._label + + @label.setter + def label(self, new_label: TextType) -> TextType: + """TextType: The label for the node.""" + self.set_label(new_label) + return self.label + def set_label(self, label: TextType) -> None: """Set a new label for the node. diff --git a/tests/test_tree.py b/tests/test_tree.py new file mode 100644 index 000000000..55af8088e --- /dev/null +++ b/tests/test_tree.py @@ -0,0 +1,17 @@ +from textual.widgets import Tree, TreeNode +from rich.text import Text + +def test_tree_node_label() -> None: + """It should be possible to modify a TreeNode's label.""" + node = TreeNode(Tree[None]("Xenomorph Lifecycle"), None, 0, "Facehugger") + assert node.label == Text("Facehugger") + node.label = "Chestbuster" + assert node.label == Text("Chestbuster") + +def test_tree_node_label_via_tree() -> None: + """It should be possible to modify a TreeNode's label when created via a Tree.""" + tree = Tree[None]("Xenomorph Lifecycle") + node = tree.root.add("Facehugger") + assert node.label == Text("Facehugger") + node.label = "Chestbuster" + assert node.label == Text("Chestbuster") From d39c59c4147c386efd53e5fad608d5cdec59eea5 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 5 Jan 2023 10:01:52 +0000 Subject: [PATCH 3/5] Move the TreeNode label tests into a better-named file There's going to be a whole bunch of tests relating to the Tree and TreeNode coming, let's make sure this ends up being fairly granular. (side thought: it might be a good time soon to revisit all the tests for Textual and try and wrangle them into some tidy structure) --- tests/{test_tree.py => tree/test_tree_node_label.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_tree.py => tree/test_tree_node_label.py} (100%) diff --git a/tests/test_tree.py b/tests/tree/test_tree_node_label.py similarity index 100% rename from tests/test_tree.py rename to tests/tree/test_tree_node_label.py From 18eae615cc233d2db8ca9fa8ad82dc0906134bbf Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 5 Jan 2023 14:26:45 +0000 Subject: [PATCH 4/5] Remove unnecessary return from label.setter Python is expressive, but it ain't that expressive. --- src/textual/widgets/_tree.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index f88dcf60c..c3bfd65ee 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -169,10 +169,8 @@ class TreeNode(Generic[TreeDataType]): return self._label @label.setter - def label(self, new_label: TextType) -> TextType: - """TextType: The label for the node.""" + def label(self, new_label: TextType) -> None: self.set_label(new_label) - return self.label def set_label(self, label: TextType) -> None: """Set a new label for the node. From ad70de5e87855a3a49f25589188b36ddc1ee5c15 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 5 Jan 2023 21:06:30 +0000 Subject: [PATCH 5/5] added question --- FAQ.md | 12 ++++++++++++ questions/compose-result.question.md | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 questions/compose-result.question.md diff --git a/FAQ.md b/FAQ.md index 570d28464..1372d3263 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,6 +1,7 @@ # Frequently Asked Questions - [Does Textual support images?](#does-textual-support-images) +- [How can I fix ImportError cannot import name ComposeResult from textual.app ?](#how-can-i-fix-importerror-cannot-import-name-composeresult-from-textualapp-) - [How do I center a widget in a screen?](#how-do-i-center-a-widget-in-a-screen) - [How do I pass arguments to an app?](#how-do-i-pass-arguments-to-an-app) @@ -11,6 +12,17 @@ Textual doesn't have built in support for images yet, but it is on the [Roadmap] See also the [rich-pixels](https://github.com/darrenburns/rich-pixels) project for a Rich renderable for images that works with Textual. + +## How can I fix ImportError cannot import name ComposeResult from textual.app ? + +You likely have an older version of Textual. You can install the latest version by adding the `-U` switch which will force pip to upgrade. + +The following should do it: + +``` +pip install "textual[dev]" -U +``` + ## How do I center a widget in a screen? diff --git a/questions/compose-result.question.md b/questions/compose-result.question.md new file mode 100644 index 000000000..d148f256a --- /dev/null +++ b/questions/compose-result.question.md @@ -0,0 +1,14 @@ +--- +title: "How can I fix ImportError cannot import name ComposeResult from textual.app ?" +alt_titles: + - "Can't import ComposeResult" + - "Error about missing ComposeResult from textual.app" +--- + +You likely have an older version of Textual. You can install the latest version by adding the `-U` switch which will force pip to upgrade. + +The following should do it: + +``` +pip install "textual[dev]" -U +```