Skip to content

Commit f012007

Browse files
authored
Merge pull request #226 from kayjan/fix-zero-null-check
fix: null checks to ignore zero values
2 parents 34b6cb9 + 2fd08b6 commit f012007

File tree

6 files changed

+147
-4
lines changed

6 files changed

+147
-4
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ 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.17.2] - 2024-04-24
810
### Changed:
911
- DAG Constructor: `list_to_dag` and `dict_to_dag` does not rely on `dataframe_to_dag` as pandas dataframe operation
1012
is phased out.
1113
### Fixed:
1214
- DAG Constructor: Handle cases where reserved keywords are part of attribute upon creation and throw error accordingly.
15+
- [#224] Tree/DAG Constructor: Null checks to not interpret 0 as null, this affects `dataframe_to_tree_by_relation`,
16+
`add_dataframe_to_tree_by_path`, `add_dataframe_to_tree_by_name`, `dataframe_to_tree`, and `dataframe_to_dag`.
17+
This will also affect showing/printing of trees when `attr_omit_null` is set to True.
1318

1419
## [0.17.1] - 2024-04-23
1520
### Fixed
@@ -550,7 +555,8 @@ ignore null attribute columns.
550555
- Utility Iterator: Tree traversal methods.
551556
- Workflow To Do App: Tree use case with to-do list implementation.
552557

553-
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.17.1...HEAD
558+
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.17.2...HEAD
559+
[0.17.2]: https://github.com/kayjan/bigtree/compare/0.17.1...0.17.2
554560
[0.17.1]: https://github.com/kayjan/bigtree/compare/0.17.0...0.17.1
555561
[0.17.0]: https://github.com/kayjan/bigtree/compare/0.16.4...0.17.0
556562
[0.16.4]: https://github.com/kayjan/bigtree/compare/0.16.3...0.16.4

bigtree/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.17.1"
1+
__version__ = "0.17.2"
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/utils/assertions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def isnull(value: Any) -> bool:
206206
"""
207207
import math
208208

209-
if not value or (isinstance(value, float) and math.isnan(value)):
209+
if value is None or (isinstance(value, float) and math.isnan(value)):
210210
return True
211211
return False
212212

tests/dag/test_construct.py

+36
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,42 @@ def test_dataframe_to_dag_reverse():
180180
assert_dag_structure_root(dag)
181181
assert_dag_structure_root_attr(dag)
182182

183+
@staticmethod
184+
def test_dataframe_to_dag_zero_attribute():
185+
from bigtree.utils.iterators import dag_iterator
186+
187+
data = pd.DataFrame(
188+
[
189+
["a", None, 0],
190+
["b", None, None],
191+
["c", "a", -1],
192+
["c", "b", -1],
193+
["d", "a", 40],
194+
["d", "c", 40],
195+
["e", "d", 35],
196+
["f", "c", 38],
197+
["f", "d", 38],
198+
["g", "c", 10],
199+
["h", "g", 6],
200+
],
201+
columns=["child", "parent", "value"],
202+
)
203+
dag = dataframe_to_dag(data)
204+
assert_dag_structure_root(dag)
205+
for parent, _ in dag_iterator(dag):
206+
match parent.name:
207+
case "a":
208+
assert hasattr(
209+
parent, "value"
210+
), "Check a attribute, expected value attribute"
211+
assert parent.value == 0, "Check a value, expected 0"
212+
case "b":
213+
assert not hasattr(
214+
parent, "value"
215+
), "Check b attribute, expected no value attribute"
216+
case "c":
217+
assert parent.value == -1, "Check c value, expected -1"
218+
183219
def test_dataframe_to_dag_empty_row_error(self):
184220
with pytest.raises(ValueError) as exc_info:
185221
dataframe_to_dag(pd.DataFrame(columns=["child", "parent", "age"]))

tests/tree/test_construct.py

+101
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,32 @@ def test_add_dataframe_to_tree_by_path_col_name(self):
616616
assert_tree_structure_node_root(self.root)
617617

618618
def test_add_dataframe_to_tree_by_path_col_name_reverse(self):
619+
data = pd.DataFrame(
620+
[
621+
["a", 0],
622+
["a/b", None],
623+
["a/c", -1],
624+
["a/b/d", 40],
625+
["a/b/e", 35],
626+
["a/c/f", 38],
627+
["a/b/e/g", 10],
628+
["a/b/e/h", 6],
629+
],
630+
columns=["PATH", "value"],
631+
)
632+
add_dataframe_to_tree_by_path(self.root, data)
633+
assert_tree_structure_basenode_root(self.root)
634+
assert_tree_structure_node_root(self.root)
635+
assert hasattr(
636+
self.root, "value"
637+
), "Check root attribute, expected value attribute"
638+
assert self.root.value == 0, "Check root value, expected 0"
639+
assert not hasattr(
640+
self.root["b"], "value"
641+
), "Check b attribute, expected no value attribute"
642+
assert self.root["c"].value == -1, "Check c value, expected -1"
643+
644+
def test_add_dataframe_to_tree_by_path_zero_attribute(self):
619645
add_dataframe_to_tree_by_path(
620646
self.root,
621647
self.data[["age", "PATH"]],
@@ -1025,6 +1051,32 @@ def test_add_dataframe_to_tree_by_name_col_name_reverse(self):
10251051
assert_tree_structure_basenode_root_attr(self.root)
10261052
assert_tree_structure_node_root(self.root)
10271053

1054+
def test_add_dataframe_to_tree_by_name_zero_attribute(self):
1055+
data = pd.DataFrame(
1056+
[
1057+
["a", 0],
1058+
["b", None],
1059+
["c", -1],
1060+
["d", 40],
1061+
["e", 35],
1062+
["f", 38],
1063+
["g", 10],
1064+
["h", 6],
1065+
],
1066+
columns=["NAME", "value"],
1067+
)
1068+
add_dataframe_to_tree_by_name(self.root, data)
1069+
assert_tree_structure_basenode_root(self.root)
1070+
assert_tree_structure_node_root(self.root)
1071+
assert hasattr(
1072+
self.root, "value"
1073+
), "Check root attribute, expected value attribute"
1074+
assert self.root.value == 0, "Check root value, expected 0"
1075+
assert not hasattr(
1076+
self.root["b"], "value"
1077+
), "Check b attribute, expected no value attribute"
1078+
assert self.root["c"].value == -1, "Check c value, expected -1"
1079+
10281080
def test_add_dataframe_to_tree_by_name_empty_error(self):
10291081
with pytest.raises(ValueError) as exc_info:
10301082
add_dataframe_to_tree_by_name(self.root, pd.DataFrame())
@@ -2075,6 +2127,30 @@ def test_dataframe_to_tree_no_attribute():
20752127
root = dataframe_to_tree(path_data)
20762128
assert_tree_structure_basenode_root(root)
20772129

2130+
@staticmethod
2131+
def test_dataframe_to_tree_zero_attribute():
2132+
path_data = pd.DataFrame(
2133+
[
2134+
["a", 0],
2135+
["a/b", None],
2136+
["a/c", -1],
2137+
["a/b/d", 1],
2138+
["a/b/e", 1],
2139+
["a/c/f", 1],
2140+
["a/b/e/g", 1],
2141+
["a/b/e/h", 1],
2142+
],
2143+
columns=["PATH", "value"],
2144+
)
2145+
root = dataframe_to_tree(path_data)
2146+
assert_tree_structure_basenode_root(root)
2147+
assert hasattr(root, "value"), "Check root attribute, expected value attribute"
2148+
assert root.value == 0, "Check root value, expected 0"
2149+
assert not hasattr(
2150+
root["b"], "value"
2151+
), "Check b attribute, expected no value attribute"
2152+
assert root["c"].value == -1, "Check c value, expected -1"
2153+
20782154
@staticmethod
20792155
def test_dataframe_to_tree_empty_row_error():
20802156
path_data = pd.DataFrame(columns=["PATH", "age"])
@@ -2427,6 +2503,31 @@ def test_dataframe_to_tree_by_relation_col_name_reverse(self):
24272503
assert_tree_structure_basenode_root_attr(root)
24282504
assert_tree_structure_node_root(root)
24292505

2506+
@staticmethod
2507+
def test_dataframe_to_tree_by_relation_zero_attribute():
2508+
relation_data = pd.DataFrame(
2509+
[
2510+
["a", None, 0],
2511+
["b", "a", None],
2512+
["c", "a", -1],
2513+
["d", "b", 40],
2514+
["e", "b", 35],
2515+
["f", "c", 38],
2516+
["g", "e", 10],
2517+
["h", "e", 6],
2518+
],
2519+
columns=["child", "parent", "value"],
2520+
)
2521+
root = dataframe_to_tree_by_relation(relation_data)
2522+
assert_tree_structure_basenode_root(root)
2523+
assert_tree_structure_node_root(root)
2524+
assert hasattr(root, "value"), "Check root attribute, expected value attribute"
2525+
assert root.value == 0, "Check root value, expected 0"
2526+
assert not hasattr(
2527+
root["b"], "value"
2528+
), "Check b attribute, expected no value attribute"
2529+
assert root["c"].value == -1, "Check c value, expected -1"
2530+
24302531
@staticmethod
24312532
def test_dataframe_to_tree_by_relation_empty_row_error():
24322533
relation_data = pd.DataFrame(columns=["child", "parent"])

tests/tree/test_export.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def test_print_tree_attr_omit_null_true(tree_node_negative_null_attr):
119119
"│ └── e\n"
120120
"│ ├── g [age=10]\n"
121121
"│ └── h\n"
122-
"└── c\n"
122+
"└── c [age=0]\n"
123123
" └── f\n"
124124
)
125125
assert_print_statement(

0 commit comments

Comments
 (0)