1919 json = MagicMock ()
2020
2121try :
22- from textual .widgets import Static
22+ from textual .widgets import Static , Tree
2323 from textual .widgets ._tree import TreeNode
2424
2525except ImportError : # pragma: no cover
5050[cyan]query:age >= 30 OR node_name LIKE ".*e"[/] Advanced query"""
5151
5252
53- def _get_textual_node_path (textual_node : TreeNode , sep : str = "/" ) -> str :
53+ def _get_textual_node_path (textual_node : TreeNode ) -> list [ str ] :
5454 """Get node path of textual TreeNode, reads the node name recursively until root node.
5555
5656 Args:
@@ -65,7 +65,7 @@ def _get_textual_node_path(textual_node: TreeNode, sep: str = "/") -> str:
6565 while parent :
6666 path .append (str (parent .label ))
6767 parent = parent .parent
68- return sep . join ( path [::- 1 ])
68+ return path [::- 1 ]
6969
7070
7171def _get_corresponding_bt_node (bt_tree : tree .Tree , textual_node : TreeNode ) -> node .Node :
@@ -79,7 +79,9 @@ def _get_corresponding_bt_node(bt_tree: tree.Tree, textual_node: TreeNode) -> no
7979 bigtree tree node
8080 """
8181 node_path = _get_textual_node_path (textual_node )
82- return bt_tree .find_full_path (node_path ) # type: ignore[attr-defined, no-any-return]
82+ for next_path in node_path [1 :]:
83+ bt_tree = bt_tree [next_path ]
84+ return bt_tree .node
8385
8486
8587def _get_corresponding_textual_nodes (
@@ -122,9 +124,21 @@ def _get_attr_bt_node(
122124 return common .assemble_attributes (bt_node , ** kwargs )
123125
124126
127+ def _assemble_data (bt_node : node .Node ) -> dict [str , str ]:
128+ """Assemble data for textual node from bigtree node
129+
130+ Args:
131+ bt_node: bigtree node
132+
133+ Returns:
134+ data dictionary
135+ """
136+ return {"path_name" : bt_node .path_name }
137+
138+
125139def populate_textual_tree (
126140 bt_tree : tree .Tree ,
127- textual_tree : TreeNode ,
141+ textual_tree : Tree ,
128142 max_depth : int = 2 ,
129143) -> None :
130144 """Populate textual tree with bigtree tree.
@@ -135,21 +149,18 @@ def populate_textual_tree(
135149 max_depth: maximum depth of tree to expand
136150 """
137151
138- def assemble_data (bt_node : node .Node ) -> dict [str , str ]:
139- return {"path_name" : bt_node .path_name }
140-
141152 def add (bt_parent : node .Node , textual_parent : TreeNode , depth : int = 1 ) -> None :
142153 # Depth + 1 because we are calculating the depth of children
143154 expand = True if depth + 1 < max_depth else False
144155 for bt_child in bt_parent .children :
145156 textual_child = textual_parent .add (
146- bt_child .node_name , data = assemble_data (bt_child ), expand = expand
157+ bt_child .node_name , data = _assemble_data (bt_child ), expand = expand
147158 )
148159 add (bt_child , textual_child , depth + 1 )
149160
150161 textual_tree .clear ()
151162 textual_tree .root .label = bt_tree .node .name
152- textual_tree .root .data = assemble_data (bt_tree .node )
163+ textual_tree .root .data = _assemble_data (bt_tree .node )
153164 textual_tree .root .expand ()
154165 add (bt_tree .node , textual_tree .root )
155166
@@ -191,7 +202,7 @@ def expand_parents(textual_node: TreeNode) -> None:
191202
192203
193204def action_add_node (
194- bt_tree : tree .Tree , textual_node : TreeNode , value : str | None
205+ bt_tree : tree .Tree , textual_node : TreeNode | None , value : str | None
195206) -> None :
196207 """Add new child node to existing node, implements for bigtree tree and textual tree in-place.
197208
@@ -203,13 +214,13 @@ def action_add_node(
203214 if not value or not textual_node :
204215 return
205216 bt_node = _get_corresponding_bt_node (bt_tree , textual_node )
206- node .Node (value , parent = bt_node )
207- textual_node .add (value )
217+ bt_child = node .Node (value , parent = bt_node )
218+ textual_node .add (value , data = _assemble_data ( bt_child ) )
208219 textual_node .expand ()
209220
210221
211222def action_add_sibling (
212- bt_tree : tree .Tree , textual_node : TreeNode , value : str | None
223+ bt_tree : tree .Tree , textual_node : TreeNode | None , value : str | None
213224) -> None :
214225 """Add new sibling node to existing node, implements for bigtree tree and textual tree in-place.
215226
@@ -218,16 +229,16 @@ def action_add_sibling(
218229 textual_node: textual tree node
219230 value: name of node to add
220231 """
221- if not textual_node .parent :
222- raise ValueError ("Cannot add sibling for root node." )
223232 if not value or not textual_node :
224233 return
234+ if not textual_node .parent :
235+ raise ValueError ("Cannot add sibling for root node." )
225236 bt_node = _get_corresponding_bt_node (bt_tree , textual_node )
226- node .Node (value , parent = bt_node .parent )
227- textual_node .parent .add (value )
237+ bt_child = node .Node (value , parent = bt_node .parent )
238+ textual_node .parent .add (value , data = _assemble_data ( bt_child ) )
228239
229240
230- def action_delete_node (bt_tree : tree .Tree , textual_node : TreeNode ) -> None :
241+ def action_delete_node (bt_tree : tree .Tree , textual_node : TreeNode | None ) -> None :
231242 """Delete node, implements for bigtree tree and textual tree in-place.
232243
233244 Args:
@@ -256,6 +267,7 @@ def action_rename_node(
256267 bt_node = _get_corresponding_bt_node (bt_tree , textual_node )
257268 bt_node .rename (value )
258269 textual_node .set_label (value )
270+ textual_node .data = _assemble_data (bt_node )
259271
260272
261273def select_edit_attr (bt_tree : tree .Tree , textual_node : TreeNode ) -> str :
@@ -273,9 +285,9 @@ def select_edit_attr(bt_tree: tree.Tree, textual_node: TreeNode) -> str:
273285
274286
275287def action_edit_attr (
276- bt_tree : tree .Tree , textual_node : TreeNode , value : str | None
288+ bt_tree : tree .Tree , textual_node : TreeNode | None , value : str | None
277289) -> None :
278- """Delete node, implements for bigtree tree and textual tree in-place.
290+ """Delete node, implements for bigtree tree in-place. Textual tree data only maintains path_name
279291
280292 Args:
281293 bt_tree: bigtree tree
@@ -284,18 +296,21 @@ def action_edit_attr(
284296 """
285297 if not textual_node or not value :
286298 return
287- kv_pairs = [kv .strip ().split ("=" ) for kv in value .split ("," )]
288- kv_pairs_eval = [(k , ast .literal_eval (v )) for k , v in kv_pairs ]
289299 try :
300+ kv_pairs = [kv .strip ().split ("=" ) for kv in value .split ("," )]
301+ kv_pairs_eval = [(k , ast .literal_eval (v )) for k , v in kv_pairs ]
290302 new_attrs = dict (kv_pairs_eval )
291- except ValueError as err :
303+ except ( ValueError , SyntaxError ) as err :
292304 raise ValueError (f"Input malformed, check `{ value } `" ) from err
293305 bt_node = _get_corresponding_bt_node (bt_tree , textual_node )
294306 existing_attrs = _get_attr_bt_node (bt_tree , textual_node )
295307 attrs_to_remove = set (existing_attrs ) - set (new_attrs )
296308 for attr_to_remove in attrs_to_remove :
297309 del bt_node .__dict__ [attr_to_remove ]
298310 bt_node .set_attrs (new_attrs )
311+ # Sync textual_node to bt_node
312+ textual_node .label = bt_node .name
313+ textual_node .data = _assemble_data (bt_node )
299314
300315
301316def action_search (
@@ -319,7 +334,7 @@ def action_search(
319334 return _get_corresponding_textual_nodes (textual_node , bt_matches_path )
320335
321336
322- def action_save_as (bt_tree : tree .Tree , value : str | None ) -> None :
337+ def action_save_as (bt_tree : tree .Tree , value : str | None ) -> None : # pragma: no cover
323338 """Save tree as json file.
324339
325340 Args:
0 commit comments