Skip to content

Commit df2d852

Browse files
authored
Merge pull request Textualize#3944 from davep/tree-root-expanded-state
Retain `Tree.root`'s expanded state when performing a `Tree.clear`
2 parents 354c423 + 5f5758c commit df2d852

File tree

5 files changed

+197
-1
lines changed

5 files changed

+197
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- `Widget.move_child` would break if `before`/`after` is set to the index of the widget in `child` https://github.com/Textualize/textual/issues/1743
1313
- Fixed auto width text not processing markup https://github.com/Textualize/textual/issues/3918
14+
- Fixed `Tree.clear` not retaining the root's expanded state https://github.com/Textualize/textual/issues/3557
1415

1516
### Changed
1617

src/textual/widgets/_tree.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -717,13 +717,14 @@ def clear(self) -> Self:
717717
self._current_id = 0
718718
root_label = self.root._label
719719
root_data = self.root.data
720+
root_expanded = self.root.is_expanded
720721
self.root = TreeNode(
721722
self,
722723
None,
723724
self._new_id(),
724725
root_label,
725726
root_data,
726-
expanded=True,
727+
expanded=root_expanded,
727728
)
728729
self._updates += 1
729730
self.refresh()

tests/snapshot_tests/__snapshots__/test_snapshots.ambr

+157
Original file line numberDiff line numberDiff line change
@@ -37109,6 +37109,163 @@
3710937109

3711037110
'''
3711137111
# ---
37112+
# name: test_tree_clearing_and_expansion
37113+
'''
37114+
<svg class="rich-terminal" viewBox="0 0 994 635.5999999999999" xmlns="http://www.w3.org/2000/svg">
37115+
<!-- Generated with Rich https://www.textualize.io -->
37116+
<style>
37117+
37118+
@font-face {
37119+
font-family: "Fira Code";
37120+
src: local("FiraCode-Regular"),
37121+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
37122+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
37123+
font-style: normal;
37124+
font-weight: 400;
37125+
}
37126+
@font-face {
37127+
font-family: "Fira Code";
37128+
src: local("FiraCode-Bold"),
37129+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
37130+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
37131+
font-style: bold;
37132+
font-weight: 700;
37133+
}
37134+
37135+
.terminal-3765519511-matrix {
37136+
font-family: Fira Code, monospace;
37137+
font-size: 20px;
37138+
line-height: 24.4px;
37139+
font-variant-east-asian: full-width;
37140+
}
37141+
37142+
.terminal-3765519511-title {
37143+
font-size: 18px;
37144+
font-weight: bold;
37145+
font-family: arial;
37146+
}
37147+
37148+
.terminal-3765519511-r1 { fill: #e2e3e3 }
37149+
.terminal-3765519511-r2 { fill: #211505;font-weight: bold }
37150+
.terminal-3765519511-r3 { fill: #1a1000;font-weight: bold }
37151+
.terminal-3765519511-r4 { fill: #c5c8c6 }
37152+
</style>
37153+
37154+
<defs>
37155+
<clipPath id="terminal-3765519511-clip-terminal">
37156+
<rect x="0" y="0" width="975.0" height="584.5999999999999" />
37157+
</clipPath>
37158+
<clipPath id="terminal-3765519511-line-0">
37159+
<rect x="0" y="1.5" width="976" height="24.65"/>
37160+
</clipPath>
37161+
<clipPath id="terminal-3765519511-line-1">
37162+
<rect x="0" y="25.9" width="976" height="24.65"/>
37163+
</clipPath>
37164+
<clipPath id="terminal-3765519511-line-2">
37165+
<rect x="0" y="50.3" width="976" height="24.65"/>
37166+
</clipPath>
37167+
<clipPath id="terminal-3765519511-line-3">
37168+
<rect x="0" y="74.7" width="976" height="24.65"/>
37169+
</clipPath>
37170+
<clipPath id="terminal-3765519511-line-4">
37171+
<rect x="0" y="99.1" width="976" height="24.65"/>
37172+
</clipPath>
37173+
<clipPath id="terminal-3765519511-line-5">
37174+
<rect x="0" y="123.5" width="976" height="24.65"/>
37175+
</clipPath>
37176+
<clipPath id="terminal-3765519511-line-6">
37177+
<rect x="0" y="147.9" width="976" height="24.65"/>
37178+
</clipPath>
37179+
<clipPath id="terminal-3765519511-line-7">
37180+
<rect x="0" y="172.3" width="976" height="24.65"/>
37181+
</clipPath>
37182+
<clipPath id="terminal-3765519511-line-8">
37183+
<rect x="0" y="196.7" width="976" height="24.65"/>
37184+
</clipPath>
37185+
<clipPath id="terminal-3765519511-line-9">
37186+
<rect x="0" y="221.1" width="976" height="24.65"/>
37187+
</clipPath>
37188+
<clipPath id="terminal-3765519511-line-10">
37189+
<rect x="0" y="245.5" width="976" height="24.65"/>
37190+
</clipPath>
37191+
<clipPath id="terminal-3765519511-line-11">
37192+
<rect x="0" y="269.9" width="976" height="24.65"/>
37193+
</clipPath>
37194+
<clipPath id="terminal-3765519511-line-12">
37195+
<rect x="0" y="294.3" width="976" height="24.65"/>
37196+
</clipPath>
37197+
<clipPath id="terminal-3765519511-line-13">
37198+
<rect x="0" y="318.7" width="976" height="24.65"/>
37199+
</clipPath>
37200+
<clipPath id="terminal-3765519511-line-14">
37201+
<rect x="0" y="343.1" width="976" height="24.65"/>
37202+
</clipPath>
37203+
<clipPath id="terminal-3765519511-line-15">
37204+
<rect x="0" y="367.5" width="976" height="24.65"/>
37205+
</clipPath>
37206+
<clipPath id="terminal-3765519511-line-16">
37207+
<rect x="0" y="391.9" width="976" height="24.65"/>
37208+
</clipPath>
37209+
<clipPath id="terminal-3765519511-line-17">
37210+
<rect x="0" y="416.3" width="976" height="24.65"/>
37211+
</clipPath>
37212+
<clipPath id="terminal-3765519511-line-18">
37213+
<rect x="0" y="440.7" width="976" height="24.65"/>
37214+
</clipPath>
37215+
<clipPath id="terminal-3765519511-line-19">
37216+
<rect x="0" y="465.1" width="976" height="24.65"/>
37217+
</clipPath>
37218+
<clipPath id="terminal-3765519511-line-20">
37219+
<rect x="0" y="489.5" width="976" height="24.65"/>
37220+
</clipPath>
37221+
<clipPath id="terminal-3765519511-line-21">
37222+
<rect x="0" y="513.9" width="976" height="24.65"/>
37223+
</clipPath>
37224+
<clipPath id="terminal-3765519511-line-22">
37225+
<rect x="0" y="538.3" width="976" height="24.65"/>
37226+
</clipPath>
37227+
</defs>
37228+
37229+
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="992" height="633.6" rx="8"/><text class="terminal-3765519511-title" fill="#c5c8c6" text-anchor="middle" x="496" y="27">TreeClearingSnapshotApp</text>
37230+
<g transform="translate(26,22)">
37231+
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
37232+
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
37233+
<circle cx="44" cy="0" r="7" fill="#28c840"/>
37234+
</g>
37235+
37236+
<g transform="translate(9, 41)" clip-path="url(#terminal-3765519511-clip-terminal)">
37237+
<rect fill="#24292f" x="0" y="1.5" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#fea62b" x="24.4" y="1.5" width="48.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="73.2" y="1.5" width="414.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="1.5" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#cf7e00" x="512.4" y="1.5" width="61" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="573.4" y="1.5" width="402.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="25.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="25.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="50.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="50.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="74.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="74.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="99.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="99.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="123.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="123.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="147.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="147.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="172.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="172.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="196.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="196.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="221.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="221.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="245.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="245.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="269.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="269.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="294.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="294.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="318.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="318.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="343.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="343.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="367.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="367.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="391.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="391.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="416.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="416.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="440.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="440.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="465.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="465.1" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="489.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="489.5" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="513.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="513.9" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="538.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="538.3" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="0" y="562.7" width="488" height="24.65" shape-rendering="crispEdges"/><rect fill="#24292f" x="488" y="562.7" width="488" height="24.65" shape-rendering="crispEdges"/>
37238+
<g class="terminal-3765519511-matrix">
37239+
<text class="terminal-3765519511-r1" x="0" y="20" textLength="24.4" clip-path="url(#terminal-3765519511-line-0)">▼&#160;</text><text class="terminal-3765519511-r2" x="24.4" y="20" textLength="48.8" clip-path="url(#terminal-3765519511-line-0)">Left</text><text class="terminal-3765519511-r1" x="488" y="20" textLength="24.4" clip-path="url(#terminal-3765519511-line-0)">▶&#160;</text><text class="terminal-3765519511-r3" x="512.4" y="20" textLength="61" clip-path="url(#terminal-3765519511-line-0)">Right</text><text class="terminal-3765519511-r4" x="976" y="20" textLength="12.2" clip-path="url(#terminal-3765519511-line-0)">
37240+
</text><text class="terminal-3765519511-r4" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-3765519511-line-1)">
37241+
</text><text class="terminal-3765519511-r4" x="976" y="68.8" textLength="12.2" clip-path="url(#terminal-3765519511-line-2)">
37242+
</text><text class="terminal-3765519511-r4" x="976" y="93.2" textLength="12.2" clip-path="url(#terminal-3765519511-line-3)">
37243+
</text><text class="terminal-3765519511-r4" x="976" y="117.6" textLength="12.2" clip-path="url(#terminal-3765519511-line-4)">
37244+
</text><text class="terminal-3765519511-r4" x="976" y="142" textLength="12.2" clip-path="url(#terminal-3765519511-line-5)">
37245+
</text><text class="terminal-3765519511-r4" x="976" y="166.4" textLength="12.2" clip-path="url(#terminal-3765519511-line-6)">
37246+
</text><text class="terminal-3765519511-r4" x="976" y="190.8" textLength="12.2" clip-path="url(#terminal-3765519511-line-7)">
37247+
</text><text class="terminal-3765519511-r4" x="976" y="215.2" textLength="12.2" clip-path="url(#terminal-3765519511-line-8)">
37248+
</text><text class="terminal-3765519511-r4" x="976" y="239.6" textLength="12.2" clip-path="url(#terminal-3765519511-line-9)">
37249+
</text><text class="terminal-3765519511-r4" x="976" y="264" textLength="12.2" clip-path="url(#terminal-3765519511-line-10)">
37250+
</text><text class="terminal-3765519511-r4" x="976" y="288.4" textLength="12.2" clip-path="url(#terminal-3765519511-line-11)">
37251+
</text><text class="terminal-3765519511-r4" x="976" y="312.8" textLength="12.2" clip-path="url(#terminal-3765519511-line-12)">
37252+
</text><text class="terminal-3765519511-r4" x="976" y="337.2" textLength="12.2" clip-path="url(#terminal-3765519511-line-13)">
37253+
</text><text class="terminal-3765519511-r4" x="976" y="361.6" textLength="12.2" clip-path="url(#terminal-3765519511-line-14)">
37254+
</text><text class="terminal-3765519511-r4" x="976" y="386" textLength="12.2" clip-path="url(#terminal-3765519511-line-15)">
37255+
</text><text class="terminal-3765519511-r4" x="976" y="410.4" textLength="12.2" clip-path="url(#terminal-3765519511-line-16)">
37256+
</text><text class="terminal-3765519511-r4" x="976" y="434.8" textLength="12.2" clip-path="url(#terminal-3765519511-line-17)">
37257+
</text><text class="terminal-3765519511-r4" x="976" y="459.2" textLength="12.2" clip-path="url(#terminal-3765519511-line-18)">
37258+
</text><text class="terminal-3765519511-r4" x="976" y="483.6" textLength="12.2" clip-path="url(#terminal-3765519511-line-19)">
37259+
</text><text class="terminal-3765519511-r4" x="976" y="508" textLength="12.2" clip-path="url(#terminal-3765519511-line-20)">
37260+
</text><text class="terminal-3765519511-r4" x="976" y="532.4" textLength="12.2" clip-path="url(#terminal-3765519511-line-21)">
37261+
</text><text class="terminal-3765519511-r4" x="976" y="556.8" textLength="12.2" clip-path="url(#terminal-3765519511-line-22)">
37262+
</text>
37263+
</g>
37264+
</g>
37265+
</svg>
37266+
37267+
'''
37268+
# ---
3711237269
# name: test_tree_example
3711337270
'''
3711437271
<svg class="rich-terminal" viewBox="0 0 994 635.5999999999999" xmlns="http://www.w3.org/2000/svg">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from textual.app import App, ComposeResult
2+
from textual.widgets import Tree
3+
4+
class TreeClearingSnapshotApp(App[None]):
5+
6+
CSS = """
7+
Screen {
8+
layout: horizontal;
9+
}
10+
"""
11+
12+
@staticmethod
13+
def _populate(tree: Tree) -> Tree:
14+
for n in range(5):
15+
branch = tree.root.add(str(n))
16+
for m in range(5):
17+
branch.add_leaf(f"{n}-{m}")
18+
return tree
19+
20+
def compose(self) -> ComposeResult:
21+
yield self._populate(Tree("Left", id="left"))
22+
yield self._populate(Tree("Right", id="right"))
23+
24+
def on_mount(self) -> None:
25+
self.query_one("#left", Tree).root.expand()
26+
self.query_one("#left", Tree).clear()
27+
self.query_one("#right", Tree).clear()
28+
29+
if __name__ == "__main__":
30+
TreeClearingSnapshotApp().run()

tests/snapshot_tests/test_snapshots.py

+7
Original file line numberDiff line numberDiff line change
@@ -967,3 +967,10 @@ def test_zero_scrollbar_size(snap_compare):
967967
"""Regression test for missing content with 0 sized scrollbars"""
968968
# https://github.com/Textualize/textual/issues/3886
969969
assert snap_compare(SNAPSHOT_APPS_DIR / "zero_scrollbar_size.py")
970+
971+
972+
def test_tree_clearing_and_expansion(snap_compare):
973+
"""Test the Tree.root.is_expanded state after a Tree.clear"""
974+
# https://github.com/Textualize/textual/issues/3557
975+
assert snap_compare(SNAPSHOT_APPS_DIR / "tree_clearing.py")
976+

0 commit comments

Comments
 (0)