Skip to content

Commit f365f85

Browse files
authored
Add print tree params for attribute display (#407)
* feat: nested_key_dict to tree to support child_key=None * feat: tree to nested_key_dict to support child_key=None * feat: allow more customisation in print_tree
1 parent 8c593c9 commit f365f85

File tree

4 files changed

+90
-6
lines changed

4 files changed

+90
-6
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
9+
## [0.31.1] - 2025-09-25
10+
### Added:
11+
- Tree Print: Add customisation for attribute display and attribute separator.
12+
### Changed:
813
- General: Switch to use Python 3.10 conventions.
914
- Docs: Update docs on the Python version update.
1015

@@ -821,7 +826,8 @@ ignore null attribute columns.
821826
- Utility Iterator: Tree traversal methods.
822827
- Workflow To Do App: Tree use case with to-do list implementation.
823828

824-
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.31.0...HEAD
829+
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.31.1...HEAD
830+
[0.31.1]: https://github.com/kayjan/bigtree/compare/0.31.0...0.31.1
825831
[0.31.0]: https://github.com/kayjan/bigtree/compare/0.30.1...0.31.0
826832
[0.30.1]: https://github.com/kayjan/bigtree/compare/0.30.0...0.30.1
827833
[0.30.0]: https://github.com/kayjan/bigtree/compare/0.29.2...0.30.0

bigtree/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.31.0"
1+
__version__ = "0.31.1"
22

33
from bigtree.binarytree.construct import list_to_binarytree
44
from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag

bigtree/tree/export/stdout.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def print_tree(
2525
max_depth: int = 0,
2626
all_attrs: bool = False,
2727
attr_list: Iterable[str] | None = None,
28+
attr_format: str = "{k}={v}",
29+
attr_sep: str = ", ",
2830
attr_omit_null: bool = False,
2931
attr_bracket: Collection[str] = ("[", "]"),
3032
style: str | Iterable[str] | constants.BasePrintStyle = "const",
@@ -36,6 +38,7 @@ def print_tree(
3638
- Able to select which node to print from, resulting in a subtree, using `node_name_or_path`
3739
- Able to customise for maximum depth to print, using `max_depth`
3840
- Able to choose which attributes to show or show all attributes, using `all_attrs` and `attr_list`
41+
- For showing attributes, able to customise the format of attributes and separator of attributes
3942
- Able to omit showing of attributes if it is null, using `attr_omit_null`
4043
- Able to customise open and close brackets if attributes are shown, using `attr_bracket`
4144
- Able to customise style, to choose from str, list[str], or inherit from constants.BasePrintStyle, using `style`
@@ -93,6 +96,13 @@ def print_tree(
9396
│ └── e [age=35]
9497
└── c [age=60]
9598
99+
>>> print_tree(root, attr_list=["name", "age"], attr_format="{k}:{v}", attr_sep="; ")
100+
a [name:a; age:90]
101+
├── b [name:b; age:65]
102+
│ ├── d [name:d; age:40]
103+
│ └── e [name:e; age:35]
104+
└── c [name:c; age:60]
105+
96106
>>> print_tree(root, attr_list=["age"], attr_bracket=["*(", ")"])
97107
a *(age=90)
98108
├── b *(age=65)
@@ -175,6 +185,9 @@ def print_tree(
175185
max_depth: maximum depth of tree to print, based on `depth` attribute
176186
all_attrs: indicator to show all attributes, overrides `attr_list` and `attr_omit_null`
177187
attr_list: node attributes to print
188+
attr_format: if attributes are displayed, the format in which to display, uses k,v to correspond to
189+
attribute name and attribute value
190+
attr_list_sep: if attributes are displayed, the separator of attributes, defaults to comma
178191
attr_omit_null: indicator whether to omit showing of null attributes
179192
attr_bracket: open and close bracket for `all_attrs` or `attr_list`
180193
style: style of print
@@ -195,21 +208,25 @@ def print_tree(
195208
attr_bracket_open, attr_bracket_close = attr_bracket
196209
if all_attrs:
197210
attrs = _node.describe(exclude_attributes=["name"], exclude_prefix="_")
198-
attr_str_list = [f"{k}={v}" for k, v in attrs]
211+
attr_str_list = [attr_format.format(k=k, v=v) for k, v in attrs]
199212
else:
200213
if attr_omit_null:
201214
attr_str_list = [
202-
f"{attr_name}={_node.get_attr(attr_name)}"
215+
attr_format.replace("{k}", attr_name).replace(
216+
"{v}", str(_node.get_attr(attr_name))
217+
)
203218
for attr_name in attr_list
204219
if not common.isnull(_node.get_attr(attr_name))
205220
]
206221
else:
207222
attr_str_list = [
208-
f"{attr_name}={_node.get_attr(attr_name)}"
223+
attr_format.replace("{k}", attr_name).replace(
224+
"{v}", str(_node.get_attr(attr_name))
225+
)
209226
for attr_name in attr_list
210227
if hasattr(_node, attr_name)
211228
]
212-
attr_str = ", ".join(attr_str_list)
229+
attr_str = attr_sep.join(attr_str_list)
213230
if attr_str:
214231
attr_str = f" {attr_bracket_open}{attr_str}{attr_bracket_close}"
215232
name_str = _node.get_attr(alias) or _node.node_name

tests/tree/export/test_stdout.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,67 @@ def test_print_tree_attr_omit_null_true(tree_node_negative_null_attr):
222222
attr_omit_null=True,
223223
)
224224

225+
# attr_format
226+
@staticmethod
227+
def test_print_tree_attr_format(tree_node):
228+
expected_str = (
229+
"a [90]\n"
230+
"├── b [65]\n"
231+
"│ ├── d [40]\n"
232+
"│ └── e [35]\n"
233+
"│ ├── g [10]\n"
234+
"│ └── h [6]\n"
235+
"└── c [60]\n"
236+
" └── f [38]\n"
237+
)
238+
assert_print_statement(
239+
export.print_tree,
240+
expected_str,
241+
tree=tree_node,
242+
attr_list=["age"],
243+
attr_format="{v}",
244+
)
245+
246+
@staticmethod
247+
def test_print_tree_attr_format_all_attrs(tree_node):
248+
expected_str = (
249+
"a [90]\n"
250+
"├── b [65]\n"
251+
"│ ├── d [40]\n"
252+
"│ └── e [35]\n"
253+
"│ ├── g [10]\n"
254+
"│ └── h [6]\n"
255+
"└── c [60]\n"
256+
" └── f [38]\n"
257+
)
258+
assert_print_statement(
259+
export.print_tree,
260+
expected_str,
261+
tree=tree_node,
262+
all_attrs=True,
263+
attr_format="{v}",
264+
)
265+
266+
@staticmethod
267+
def test_print_tree_attr_sep(tree_node):
268+
expected_str = (
269+
"a [name=a age=90]\n"
270+
"├── b [name=b age=65]\n"
271+
"│ ├── d [name=d age=40]\n"
272+
"│ └── e [name=e age=35]\n"
273+
"│ ├── g [name=g age=10]\n"
274+
"│ └── h [name=h age=6]\n"
275+
"└── c [name=c age=60]\n"
276+
" └── f [name=f age=38]\n"
277+
)
278+
assert_print_statement(
279+
export.print_tree,
280+
expected_str,
281+
tree=tree_node,
282+
attr_list=["name", "age"],
283+
attr_sep=" ",
284+
)
285+
225286
# attr_bracket
226287
@staticmethod
227288
def test_print_tree_attr_bracket(tree_node):

0 commit comments

Comments
 (0)