From c90904a7223321ec97cc2c05d13c3b46802e69ae Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 2 May 2026 08:58:57 +0800 Subject: [PATCH 01/10] bump: v1.4.1 --- CHANGELOG.md | 5 ++++- bigtree/__init__.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a9aa643..932f1da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [1.4.1] - 2026-05-02 ### Changed: - Tree Search: Modify type hint to include returning None - Misc: Clean up and remove redundant lines. @@ -912,7 +914,8 @@ ignore null attribute columns. - Utility Iterator: Tree traversal methods. - Workflow To Do App: Tree use case with to-do list implementation. -[Unreleased]: https://github.com/kayjan/bigtree/compare/1.4.0...HEAD +[Unreleased]: https://github.com/kayjan/bigtree/compare/1.4.1...HEAD +[1.4.1]: https://github.com/kayjan/bigtree/compare/1.4.0...1.4.1 [1.4.0]: https://github.com/kayjan/bigtree/compare/1.3.1...1.4.0 [1.3.1]: https://github.com/kayjan/bigtree/compare/1.3.0...1.3.1 [1.3.0]: https://github.com/kayjan/bigtree/compare/1.2.0...1.3.0 diff --git a/bigtree/__init__.py b/bigtree/__init__.py index 4ceec3c6..a143f2dd 100644 --- a/bigtree/__init__.py +++ b/bigtree/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.4.0" +__version__ = "1.4.1" from bigtree._globals import Globals from bigtree.binarytree.binarytree import BinaryTree From cf1ae041f24e744ca2887522ad4b28136c3e74af Mon Sep 17 00:00:00 2001 From: Kay Date: Wed, 6 May 2026 02:14:21 +0800 Subject: [PATCH 02/10] docs: enhance mypy - warn if no return --- bigtree/node/basenode.py | 2 ++ bigtree/tree/helper.py | 3 ++- bigtree/tree/search.py | 10 +++------- pyproject.toml | 1 - 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bigtree/node/basenode.py b/bigtree/node/basenode.py index 84a7eda0..37bde59c 100644 --- a/bigtree/node/basenode.py +++ b/bigtree/node/basenode.py @@ -458,6 +458,7 @@ def left_sibling(self: T) -> T | None: child_idx = children.index(self) if child_idx: return self.parent.children[child_idx - 1] + return None @property def right_sibling(self: T) -> T | None: @@ -471,6 +472,7 @@ def right_sibling(self: T) -> T | None: child_idx = children.index(self) if child_idx + 1 < len(children): return self.parent.children[child_idx + 1] + return None @property def node_path(self: T) -> Iterable[T]: diff --git a/bigtree/tree/helper.py b/bigtree/tree/helper.py index 314ed4b8..d216663e 100644 --- a/bigtree/tree/helper.py +++ b/bigtree/tree/helper.py @@ -441,7 +441,7 @@ def get_tree_diff( aggregate: bool = False, attr_list: Iterable[str] | None = None, fallback_sep: str = "/", -) -> node.Node: +) -> node.Node | None: """Get difference of `tree` to `other_tree`, changes are relative to `tree`. Compares the difference in tree structure (default), but can also compare tree attributes using `attr_list`. @@ -692,3 +692,4 @@ def get_tree_diff( _node = search.find_full_path(tree_diff, path) _node.name += " (~)" return tree_diff + return None diff --git a/bigtree/tree/search.py b/bigtree/tree/search.py index e85b2fce..b93e5199 100644 --- a/bigtree/tree/search.py +++ b/bigtree/tree/search.py @@ -117,8 +117,7 @@ def find(tree: T, condition: Callable[[T], bool], max_depth: int = 0) -> T | Non Search result """ result = findall(tree, condition, max_depth, max_count=1) - if result: - return result[0] + return result[0] if result else None def find_name(tree: NodeT, name: str, max_depth: int = 0) -> NodeT | None: @@ -206,9 +205,7 @@ def find_relative_path(tree: NodeT, path_name: str) -> NodeT | None: Search result """ result = find_relative_paths(tree, path_name, max_count=1) - - if result: - return result[0] + return result[0] if result else None def find_relative_paths( @@ -532,8 +529,7 @@ def find_child( Search result """ result = find_children(tree, condition, max_count=1) - if result: - return result[0] + return result[0] if result else None def find_child_by_name(tree: NodeT | DAGNodeT, name: str) -> NodeT | DAGNodeT | None: diff --git a/pyproject.toml b/pyproject.toml index 992a7481..d05c1d7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,7 +169,6 @@ profile = "black" ignore_missing_imports = true strict = true strict_optional = false -warn_no_return = false disallow_untyped_calls = false [tool.ruff] From 1f0da7c6fe5161e16d149ce92d93be6a4129b566 Mon Sep 17 00:00:00 2001 From: Kay Date: Wed, 6 May 2026 02:18:18 +0800 Subject: [PATCH 03/10] docs: update CHANGELOG --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932f1da8..092da0f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed: +- Tree Helper: Tree diff modify type hint to include returning None. +- Misc: Mypy type checks to remove ignoring warn_no_return. ## [1.4.1] - 2026-05-02 ### Changed: -- Tree Search: Modify type hint to include returning None +- Tree Search: Modify type hint to include returning None. - Misc: Clean up and remove redundant lines. ## [1.4.0] - 2026-03-24 From b3172d629c465a4acaab1bb6fe5af35466f0ef52 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 9 May 2026 15:13:22 +0800 Subject: [PATCH 04/10] feat: add default to plugins, add get_common_ancestors to BaseNode --- bigtree/_plugins.py | 5 ++++- bigtree/node/basenode.py | 27 +++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/bigtree/_plugins.py b/bigtree/_plugins.py index 4890e311..6f10fe28 100644 --- a/bigtree/_plugins.py +++ b/bigtree/_plugins.py @@ -16,6 +16,7 @@ def register_binarytree_plugins() -> None: # Iterator methods "inorder_iter": iterators.inorder_iter, }, + method="default", ) plugin_docs = "\n".join( @@ -52,6 +53,7 @@ def register_dag_plugins() -> None: # Iterator methods "iterate": iterators.dag_iterator, }, + method="default", ) plugin_docs = "\n".join( @@ -143,7 +145,8 @@ def register_tree_plugins() -> None: "find_children": search.find_children, "find_child": search.find_child, "find_child_by_name": search.find_child_by_name, - } + }, + method="default", ) Tree.register_plugins( { diff --git a/bigtree/node/basenode.py b/bigtree/node/basenode.py index 37bde59c..f9b11c3b 100644 --- a/bigtree/node/basenode.py +++ b/bigtree/node/basenode.py @@ -114,13 +114,14 @@ class BaseNode: 1. ``describe()``: Get node information sorted by attributes, return list of tuples 2. ``get_attr(attr_name: str)``: Get value of node attribute 3. ``set_attrs(attrs: dict)``: Set node attribute name(s) and value(s) - 4. ``go_to(node: Self)``: Get a path from own node to another node from same tree - 5. ``append(node: Self)``: Add child to node - 6. ``extend(nodes: list[Self])``: Add multiple children to node - 7. ``copy()``: Deep copy self - 8. ``sort()``: Sort child nodes - 9. ``plot()``: Plot tree in line form - 10. ``query(query: str)``: Filter tree using Tree Query Language + 4. ``get_common_ancestors(node: Self)``: Get common ancestors with another node from same tree + 5. ``go_to(node: Self)``: Get a path from own node to another node from same tree + 6. ``append(node: Self)``: Add child to node + 7. ``extend(nodes: list[Self])``: Add multiple children to node + 8. ``copy()``: Deep copy self + 9. ``sort()``: Sort child nodes + 10. ``plot()``: Plot tree in line form + 11. ``query(query: str)``: Filter tree using Tree Query Language ---- @@ -652,8 +653,18 @@ def set_attrs(self, attrs: Mapping[str, Any]) -> None: """ self.__dict__.update(attrs) + def get_common_ancestors(self: T, node: T) -> Iterable[T]: + """Get common ancestors of current node and specified node from same tree. + + Args: + node: node to get common ancestors + """ + from bigtree.tree.parsing import get_common_ancestors + + return get_common_ancestors([self, node]) + def go_to(self: T, node: T) -> Iterable[T]: - """Get path from current node to specified node from same tree, uses `get_path` function. + """Get path from current node to specified node from same tree. Args: node: node to travel to from current node, inclusive of start and end node From 2d5029622520fd1ca7d7db659b7a35e047bb06f5 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 9 May 2026 15:14:20 +0800 Subject: [PATCH 05/10] feat: add default to plugins, add get_common_ancestors to BaseNode --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 429b815f..e5b680e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- BaseNode: Method `gca` for getting common ancestors. ## [1.4.1] - 2026-05-02 ### Changed: -- Tree Helper: Tree diff modify type hint to include returning None. +- Tree Diff: Modify type hint to include returning None. - Misc: Mypy type checks to remove ignoring warn_no_return. ## [1.4.1] - 2026-05-02 From 46cb0b256a16a061e28235289fcbf014bff0a853 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 9 May 2026 15:15:13 +0800 Subject: [PATCH 06/10] docs: enumerate demonstration --- CHANGELOG.md | 1 + docs/gettingstarted/demo/binarytree.md | 8 ++--- docs/gettingstarted/demo/dag.md | 12 ++++---- docs/gettingstarted/demo/tree.md | 42 +++++++++++++------------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5b680e7..bbacfcb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - BaseNode: Method `gca` for getting common ancestors. +- Docs: Enumerate the demonstration page. ## [1.4.1] - 2026-05-02 ### Changed: diff --git a/docs/gettingstarted/demo/binarytree.md b/docs/gettingstarted/demo/binarytree.md index f871cc12..901be159 100644 --- a/docs/gettingstarted/demo/binarytree.md +++ b/docs/gettingstarted/demo/binarytree.md @@ -12,9 +12,9 @@ Compared to nodes in tree, nodes in Binary Tree are only allowed maximum of 2 ch Since BinaryNode extends from Node, construct, traverse, search, export methods from Node are applicable to Binary Tree as well. -## Construct Binary Tree +## 1. Construct Binary Tree -### 1. From BinaryNode +### 1.1 From BinaryNode BinaryNode can be linked to each other with `parent`, `children`, `left`, and `right` setter methods, or using bitshift operator with the convention `parent_node >> child_node` or `child_node << parent_node`. @@ -37,7 +37,7 @@ graph.write_png("assets/demo/binarytree.png") ![Sample Binary Tree Output](https://github.com/kayjan/bigtree/raw/master/assets/demo/binarytree.png "Sample Binary Tree Output") -### 2. From list +### 1.2 From list Construct nodes only, list has similar format as `heapq` list. @@ -56,7 +56,7 @@ tree.hshow() # └─ 7 ``` -## Traverse Binary Tree +## 2. Traverse Binary Tree In addition to the traversal methods in the usual tree, binary tree includes in-order traversal method. diff --git a/docs/gettingstarted/demo/dag.md b/docs/gettingstarted/demo/dag.md index ed50cfa6..c921fc65 100644 --- a/docs/gettingstarted/demo/dag.md +++ b/docs/gettingstarted/demo/dag.md @@ -10,9 +10,9 @@ to implement dag-level methods (for construct/export etc.) for a more intuitive Compared to nodes in tree, nodes in DAG are able to have multiple parents. -## Construct DAG +## 1. Construct DAG -### 1. From DAGNode +### 1.1 From DAGNode DAGNodes can be linked to each other in the following ways: @@ -39,7 +39,7 @@ graph.write_png("assets/demo/dag.png") ![Sample DAG Output](https://github.com/kayjan/bigtree/raw/master/assets/demo/dag.png "Sample DAG Output") -### 2. From list +### 1.2 From list Construct nodes only, list contains parent-child tuples. @@ -53,7 +53,7 @@ print([(parent.node_name, child.node_name) for parent, child in dag.iterate()]) # [('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')] ``` -### 3. From nested dictionary +### 1.3 From nested dictionary Construct nodes with attributes, `key`: child name, `value`: dict of parent name, child node attributes. @@ -73,7 +73,7 @@ print([(parent.node_name, child.node_name) for parent, child in dag.iterate()]) # [('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')] ``` -### 4. From pandas DataFrame +### 1.4 From pandas DataFrame Construct nodes with attributes, *pandas DataFrame* contains child column, parent column, and attribute columns. @@ -99,7 +99,7 @@ print([(parent.node_name, child.node_name) for parent, child in dag.iterate()]) # [('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')] ``` -## DAG Attributes and Operations +## 2. DAG Attributes and Operations Note that using `DAGNode` as superclass inherits the default class attributes (properties) and operations (methods). diff --git a/docs/gettingstarted/demo/tree.md b/docs/gettingstarted/demo/tree.md index b61c6edd..5482830a 100644 --- a/docs/gettingstarted/demo/tree.md +++ b/docs/gettingstarted/demo/tree.md @@ -10,12 +10,12 @@ implement tree-level methods for a more intuitive API. Here are some codes to get started. -## Construct Tree +## 1. Construct Tree Nodes can have attributes if they are initialized from `Node`, *dictionary*, *pandas DataFrame*, or *polars DataFrame*. Read more [here](/../../bigtree/tree/tree/#tree-construct-methods). -### 1. From Node +### 1.1 From Node Nodes can be linked to each other in the following ways: @@ -104,7 +104,7 @@ Nodes can be linked to each other in the following ways: ![Sample Tree Output](https://github.com/kayjan/bigtree/raw/master/assets/demo/tree.png "Sample Tree Output") -### 2. From str +### 1.2 From str Construct nodes only. Newick string notation supports parsing attributes. @@ -153,7 +153,7 @@ Construct nodes only. Newick string notation supports parsing attributes. # └── f ``` -### 3. From list +### 1.3 From list Construct nodes only. List can contain either full paths or tuples of parent-child names. @@ -183,7 +183,7 @@ Construct nodes only. List can contain either full paths or tuples # └── c ``` -### 4. From nested dictionary +### 1.4 From nested dictionary Construct nodes with attributes. Dictionary can be in a flat structure where `key` is path and `value` is dictionary of node attribute names and values, or in a recursive structure where `key` is node attribute @@ -277,7 +277,7 @@ names and `value` is node attribute values, and list of children (recursive). ``` -### 5. From pandas/polars DataFrame +### 1.5 From pandas/polars DataFrame Construct nodes with attributes. *DataFrame* can contain either path column or parent-child columns. Other columns can be used to specify attributes. @@ -378,7 +378,7 @@ Construct nodes with attributes. *DataFrame* can contain either path colum # └── c [age=60] ``` -### 6. From rich Trees +### 1.6 From rich Trees Convert rich.tree.Tree to bigtree Trees. @@ -408,9 +408,9 @@ Convert rich.tree.Tree to bigtree Trees. If tree is already created, nodes can still be added using path string, dictionary, and pandas/polars DataFrame!
Attributes can be added to existing nodes using a dictionary or pandas/polars DataFrame. -## View Tree +## 2. View Tree -### 1. Print Tree +### 2.1 Print Tree After tree is constructed, it can be viewed by printing to console using `show`, `hshow`, or `vshow` method directly, for compact, horizontal, and vertical orientation respectively. @@ -578,7 +578,7 @@ Other customisations for printing are also available, such as: # └── c ``` -### 2. Display on Jupyter Notebook +### 2.2 Display in Jupyter Notebook Tree can be displayed interactively on jupyter notebook using `ishow`. @@ -606,7 +606,7 @@ tree.ishow(all_attrs=True, height=400) # (1)! -### 3. Plot Tree +### 2.3 Plot Tree Tree can also be plotted using `plot` method directly with the help of `matplotlib` library. @@ -635,7 +635,7 @@ fig.savefig("assets/demo/tree_plot.png") # Save figure ![Tree Plot Image Output](https://github.com/kayjan/bigtree/raw/master/assets/demo/tree_plot.png "Tree Plot Image Output") -## Tree Attributes and Operations +## 3. Tree Attributes and Operations Note that using `BaseNode` or `Node` as superclass inherits the default class attributes (properties) and operations (methods). @@ -702,7 +702,7 @@ Below is the table of operations available to `BaseNode` and `Node` classes. | Plot tree | `root.plot("-ok")` | plt.Figure() | | Query tree | `root.query('name == "b"')` | [Node(/a/b, )] | -## Traverse Tree +## 4. Traverse Tree Tree can be traversed using the following traversal methods. @@ -742,7 +742,7 @@ a # [['a'], ['c', 'b'], ['d', 'e']] ``` -## Modify Tree +## 5. Modify Tree Nodes can be shifted (with or without replacement) or copied (without replacement) from one path to another, this changes the tree in-place. @@ -887,7 +887,7 @@ root_other.show() 4. The first copy and replace of `Documents/Pictures/photo2.jpg` with `photo1.jpg` 5. The second copy and replace of `Documents/file2.doc` with `file1.doc` -## Tree Search +## 6. Tree Search One or multiple nodes can be searched based on name, path, attribute value, or user-defined condition. It is also possible to search for one or more child node(s) based on attributes, this search will be faster as @@ -985,11 +985,11 @@ Read more [here](/../../bigtree/tree/tree/#tree-query-and-search-methods). # Node(/a/c/c, age=40) ``` -## Helper Utility +## 7. Helper Utility Read more [here](/../../bigtree/tree/tree/#tree-helper-methods). -### 1. Clone tree +### 7.1 Clone tree Trees can be cloned to another Node type. If the same type is desired, use `tree.copy()` instead. @@ -1003,7 +1003,7 @@ clone_tree(root, Node) # clone from `BaseNode` to `Node` type # Node(/a, ) ``` -### 2. Get subtree +### 7.2 Get subtree Subtree refers to a smaller tree with a different tree root. @@ -1026,7 +1026,7 @@ root_subtree.show() # └── e ``` -### 3. Prune tree +### 7.3 Prune tree Pruned tree refers to a smaller tree with the same tree root. Trees can be pruned by one or more of the following filters: @@ -1090,7 +1090,7 @@ Pruned tree refers to a smaller tree with the same tree root. Trees can be prune # └── c ``` -### 4. Get tree differences +### 7.4 Get tree differences View the differences in structure and/or attributes between two trees. The changes reflected are relative to the first tree. By default, only the differences are shown. It is possible to view the full original tree with the differences. @@ -1282,7 +1282,7 @@ For aggregating the differences at the parent-level instead of having `(+)` and # └── d (~) [tags=('original d', 'new d')] ``` -## Export Tree +## 8. Export Tree Tree can be exported to other data types: From ce76c868c7a11bdea2a231cfe631371246e59221 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 9 May 2026 15:16:00 +0800 Subject: [PATCH 07/10] feat: test get_common_ancestors in BaseNode --- tests/tree/test_parsing.py | 67 +++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/tests/tree/test_parsing.py b/tests/tree/test_parsing.py index 0f7f19a4..65e9a9fd 100644 --- a/tests/tree/test_parsing.py +++ b/tests/tree/test_parsing.py @@ -103,7 +103,54 @@ def test_get_path(self): actual_path == expected_path ), f"Wrong path for {node_pair}, expected {expected_path}, received {actual_path}" + def test_get_common_ancestors(self): + # Using get_common_ancestors from BaseNode + assert_tree_structure_basenode_root(self.a) + assert_tree_structure_basenode_root_attr(self.a) + assert_tree_structure_basenode_self(self) + assert_tree_structure_node_root(self.a) + assert_tree_structure_node_self(self) + + expected_paths = [ + ["a"], + ["a"], + ["a"], + ["a"], + ["a"], + ["a"], + ["a"], + ["b", "a"], + ["b", "a"], + ["b", "a"], + ["b", "a"], + ["a"], + ["a"], + ["b", "a"], + ["b", "a"], + ["b", "a"], + ["a"], + ["a"], + ["e", "b", "a"], + ["e", "b", "a"], + ["a"], + ["a"], + ["e", "b", "a"], + ["a"], + ["a"], + ["a"], + ["a"], + ["c", "a"], + ] + for node_pair, expected in zip( + combinations(list(iterators.preorder_iter(self.a)), 2), expected_paths + ): + actual = [_node.node_name for _node in node_pair[0].gca(node_pair[1])] + assert ( + actual == expected + ), f"Wrong ancestors for {node_pair}, expected {expected}, received {actual}" + def test_go_to(self): + # Using go_to from BaseNode assert_tree_structure_basenode_root(self.a) assert_tree_structure_basenode_root_attr(self.a) assert_tree_structure_basenode_self(self) @@ -140,25 +187,21 @@ def test_go_to(self): ["h", "e", "b", "a", "c", "f"], ["c", "f"], ] - for node_pair, expected_path in zip( + for node_pair, expected in zip( combinations(list(iterators.preorder_iter(self.a)), 2), expected_paths ): - actual_path = [ - _node.node_name for _node in node_pair[0].go_to(node_pair[1]) - ] + actual = [_node.node_name for _node in node_pair[0].go_to(node_pair[1])] assert ( - actual_path == expected_path - ), f"Wrong path for {node_pair}, expected {expected_path}, received {actual_path}" + actual == expected + ), f"Wrong path for {node_pair}, expected {expected}, received {actual}" def test_get_path_same_node(self): for _node in iterators.preorder_iter(self.a): - actual_path = [ - _node1.node_name for _node1 in parsing.get_path(_node, _node) - ] - expected_path = [_node.node_name] + actual = [_node1.node_name for _node1 in parsing.get_path(_node, _node)] + expected = [_node.node_name] assert ( - actual_path == expected_path - ), f"Wrong path for {_node}, expected {expected_path}, received {actual_path}" + actual == expected + ), f"Wrong path for {_node}, expected {expected}, received {actual}" def test_get_path_type_error(self): source = node.Node("a") From 063f476ede145d17af17672c470c016baae40227 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 9 May 2026 16:39:19 +0800 Subject: [PATCH 08/10] feat: test get_common_ancestors in BaseNode --- docs/gettingstarted/demo/tree.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/gettingstarted/demo/tree.md b/docs/gettingstarted/demo/tree.md index 5482830a..a70e4374 100644 --- a/docs/gettingstarted/demo/tree.md +++ b/docs/gettingstarted/demo/tree.md @@ -693,7 +693,8 @@ Below is the table of operations available to `BaseNode` and `Node` classes. |------------------------------------|------------------------------------------------------------------|--------------------------------------------| | Visualize tree (only for `Node`) | `root.show()` / `root.hshow()` / `root.vshow()` | None | | Get node information | `root.describe(exclude_prefix="_")` | [('name', 'a')] | -| Find path from one node to another | `root.go_to(node_e)` | [Node(/a, ), Node(/a/b, ), Node(/a/b/e, )] | +| Find common ancestors | `root.get_common_ancestors(node_e)` | [Node(/a/b, ), Node(/a/b/e, )] | +| Find path from one node to another | `node_b.go_to(node_e)` | [Node(/a, ), Node(/a/b, ), Node(/a/b/e, )] | | Add one or more children to node | `root.append(Node("j"))` / `root.extend([Node("k"), Node("l")])` | Node(/a, ) | | Set attribute(s) | `root.set_attrs({"description": "root-tag"})` | None | | Get attribute | `root.get_attr("description")` | 'root-tag' | From 77aff392cf290de4786cea14f8142b61efac2f4f Mon Sep 17 00:00:00 2001 From: Kay Date: Sun, 10 May 2026 01:03:37 +0800 Subject: [PATCH 09/10] feat: update demonstration to include query examples --- CHANGELOG.md | 5 +++-- docs/gettingstarted/demo/tree.md | 33 +++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbacfcb8..c1c5db95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -- BaseNode: Method `gca` for getting common ancestors. -- Docs: Enumerate the demonstration page. +- BaseNode: Method `get_common_ancestors` for getting common ancestors, this was already available in parsing module. +- Docs: Enumerate the demonstration page, fix url links. +- Docs: Update demonstration to include query examples. ## [1.4.1] - 2026-05-02 ### Changed: diff --git a/docs/gettingstarted/demo/tree.md b/docs/gettingstarted/demo/tree.md index a70e4374..03553ccc 100644 --- a/docs/gettingstarted/demo/tree.md +++ b/docs/gettingstarted/demo/tree.md @@ -13,7 +13,7 @@ Here are some codes to get started. ## 1. Construct Tree Nodes can have attributes if they are initialized from `Node`, *dictionary*, *pandas DataFrame*, or *polars DataFrame*. -Read more [here](/../../bigtree/tree/tree/#tree-construct-methods). +Read more [here](https://bigtree.readthedocs.io/stable/bigtree/tree/construct/#tree-construct-methods). ### 1.1 From Node @@ -888,13 +888,15 @@ root_other.show() 4. The first copy and replace of `Documents/Pictures/photo2.jpg` with `photo1.jpg` 5. The second copy and replace of `Documents/file2.doc` with `file1.doc` -## 6. Tree Search +## 6. Tree Search and Query One or multiple nodes can be searched based on name, path, attribute value, or user-defined condition. It is also possible to search for one or more child node(s) based on attributes, this search will be faster as it does not require traversing the whole tree to find the node(s). -Read more [here](/../../bigtree/tree/tree/#tree-query-and-search-methods). +Tree can be queried using Tree Query Language. + +Read more [here](https://bigtree.readthedocs.io/stable/bigtree/tree/tree/#tree-query-and-search-methods). === "Find single node" ```python hl_lines="13 16 19 22 25 28" @@ -986,9 +988,30 @@ Read more [here](/../../bigtree/tree/tree/#tree-query-and-search-methods). # Node(/a/c/c, age=40) ``` +=== "Tree Query" + ```python hl_lines="13 16" + from bigtree import Node, Tree + root = Node("a", age=90) + b = Node("b", age=65, parent=root) + c = Node("c", age=60, parent=root) + d = Node("d", age=40, parent=c) + tree = Tree(root) + tree.show(attr_list=["age"]) + # a [age=90] + # ├── b [age=65] + # └── c [age=60] + # └── d [age=40] + + tree.query('name == "b" OR age <= 40') + # [Node(/a/b, age=65), Node(/a/c/d, age=40)] + + tree.query("is_leaf") + # [Node(/a/b, age=65), Node(/a/c/d, age=40)] + ``` + ## 7. Helper Utility -Read more [here](/../../bigtree/tree/tree/#tree-helper-methods). +Read more [here](https://bigtree.readthedocs.io/stable/bigtree/tree/tree/#tree-helper-methods). ### 7.1 Clone tree @@ -1296,7 +1319,7 @@ Tree can be exported to other data types: 7. Mermaid Flowchart (can display on .md) 8. Pyvis Network (can display interactive .html) -Read more [here](/../../bigtree/tree/tree/#tree-export-methods). +Read more [here](https://bigtree.readthedocs.io/stable/bigtree/tree/tree/#tree-export-methods). ```python from bigtree import Node, Tree From 0a0b3044f29f728e7b41d5708cd304c164e91c16 Mon Sep 17 00:00:00 2001 From: Kay Date: Sun, 10 May 2026 01:06:48 +0800 Subject: [PATCH 10/10] test: fix --- tests/tree/test_parsing.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/tree/test_parsing.py b/tests/tree/test_parsing.py index 65e9a9fd..dc67ac45 100644 --- a/tests/tree/test_parsing.py +++ b/tests/tree/test_parsing.py @@ -144,7 +144,10 @@ def test_get_common_ancestors(self): for node_pair, expected in zip( combinations(list(iterators.preorder_iter(self.a)), 2), expected_paths ): - actual = [_node.node_name for _node in node_pair[0].gca(node_pair[1])] + actual = [ + _node.node_name + for _node in node_pair[0].get_common_ancestors(node_pair[1]) + ] assert ( actual == expected ), f"Wrong ancestors for {node_pair}, expected {expected}, received {actual}"