Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ 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]

## [0.17.2] - 2024-04-24
### Changed:
- DAG Constructor: `list_to_dag` and `dict_to_dag` does not rely on `dataframe_to_dag` as pandas dataframe operation
is phased out.
### Fixed:
- DAG Constructor: Handle cases where reserved keywords are part of attribute upon creation and throw error accordingly.
- [#224] Tree/DAG Constructor: Null checks to not interpret 0 as null, this affects `dataframe_to_tree_by_relation`,
`add_dataframe_to_tree_by_path`, `add_dataframe_to_tree_by_name`, `dataframe_to_tree`, and `dataframe_to_dag`.
This will also affect showing/printing of trees when `attr_omit_null` is set to True.

## [0.17.1] - 2024-04-23
### Fixed
Expand Down Expand Up @@ -550,7 +555,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/0.17.1...HEAD
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.17.2...HEAD
[0.17.2]: https://github.com/kayjan/bigtree/compare/0.17.1...0.17.2
[0.17.1]: https://github.com/kayjan/bigtree/compare/0.17.0...0.17.1
[0.17.0]: https://github.com/kayjan/bigtree/compare/0.16.4...0.17.0
[0.16.4]: https://github.com/kayjan/bigtree/compare/0.16.3...0.16.4
Expand Down
2 changes: 1 addition & 1 deletion bigtree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.17.1"
__version__ = "0.17.2"

from bigtree.binarytree.construct import list_to_binarytree
from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag
Expand Down
2 changes: 1 addition & 1 deletion bigtree/utils/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def isnull(value: Any) -> bool:
"""
import math

if not value or (isinstance(value, float) and math.isnan(value)):
if value is None or (isinstance(value, float) and math.isnan(value)):
return True
return False

Expand Down
36 changes: 36 additions & 0 deletions tests/dag/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,42 @@ def test_dataframe_to_dag_reverse():
assert_dag_structure_root(dag)
assert_dag_structure_root_attr(dag)

@staticmethod
def test_dataframe_to_dag_zero_attribute():
from bigtree.utils.iterators import dag_iterator

data = pd.DataFrame(
[
["a", None, 0],
["b", None, None],
["c", "a", -1],
["c", "b", -1],
["d", "a", 40],
["d", "c", 40],
["e", "d", 35],
["f", "c", 38],
["f", "d", 38],
["g", "c", 10],
["h", "g", 6],
],
columns=["child", "parent", "value"],
)
dag = dataframe_to_dag(data)
assert_dag_structure_root(dag)
for parent, _ in dag_iterator(dag):
match parent.name:
case "a":
assert hasattr(
parent, "value"
), "Check a attribute, expected value attribute"
assert parent.value == 0, "Check a value, expected 0"
case "b":
assert not hasattr(
parent, "value"
), "Check b attribute, expected no value attribute"
case "c":
assert parent.value == -1, "Check c value, expected -1"

def test_dataframe_to_dag_empty_row_error(self):
with pytest.raises(ValueError) as exc_info:
dataframe_to_dag(pd.DataFrame(columns=["child", "parent", "age"]))
Expand Down
101 changes: 101 additions & 0 deletions tests/tree/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,32 @@ def test_add_dataframe_to_tree_by_path_col_name(self):
assert_tree_structure_node_root(self.root)

def test_add_dataframe_to_tree_by_path_col_name_reverse(self):
data = pd.DataFrame(
[
["a", 0],
["a/b", None],
["a/c", -1],
["a/b/d", 40],
["a/b/e", 35],
["a/c/f", 38],
["a/b/e/g", 10],
["a/b/e/h", 6],
],
columns=["PATH", "value"],
)
add_dataframe_to_tree_by_path(self.root, data)
assert_tree_structure_basenode_root(self.root)
assert_tree_structure_node_root(self.root)
assert hasattr(
self.root, "value"
), "Check root attribute, expected value attribute"
assert self.root.value == 0, "Check root value, expected 0"
assert not hasattr(
self.root["b"], "value"
), "Check b attribute, expected no value attribute"
assert self.root["c"].value == -1, "Check c value, expected -1"

def test_add_dataframe_to_tree_by_path_zero_attribute(self):
add_dataframe_to_tree_by_path(
self.root,
self.data[["age", "PATH"]],
Expand Down Expand Up @@ -1025,6 +1051,32 @@ def test_add_dataframe_to_tree_by_name_col_name_reverse(self):
assert_tree_structure_basenode_root_attr(self.root)
assert_tree_structure_node_root(self.root)

def test_add_dataframe_to_tree_by_name_zero_attribute(self):
data = pd.DataFrame(
[
["a", 0],
["b", None],
["c", -1],
["d", 40],
["e", 35],
["f", 38],
["g", 10],
["h", 6],
],
columns=["NAME", "value"],
)
add_dataframe_to_tree_by_name(self.root, data)
assert_tree_structure_basenode_root(self.root)
assert_tree_structure_node_root(self.root)
assert hasattr(
self.root, "value"
), "Check root attribute, expected value attribute"
assert self.root.value == 0, "Check root value, expected 0"
assert not hasattr(
self.root["b"], "value"
), "Check b attribute, expected no value attribute"
assert self.root["c"].value == -1, "Check c value, expected -1"

def test_add_dataframe_to_tree_by_name_empty_error(self):
with pytest.raises(ValueError) as exc_info:
add_dataframe_to_tree_by_name(self.root, pd.DataFrame())
Expand Down Expand Up @@ -2075,6 +2127,30 @@ def test_dataframe_to_tree_no_attribute():
root = dataframe_to_tree(path_data)
assert_tree_structure_basenode_root(root)

@staticmethod
def test_dataframe_to_tree_zero_attribute():
path_data = pd.DataFrame(
[
["a", 0],
["a/b", None],
["a/c", -1],
["a/b/d", 1],
["a/b/e", 1],
["a/c/f", 1],
["a/b/e/g", 1],
["a/b/e/h", 1],
],
columns=["PATH", "value"],
)
root = dataframe_to_tree(path_data)
assert_tree_structure_basenode_root(root)
assert hasattr(root, "value"), "Check root attribute, expected value attribute"
assert root.value == 0, "Check root value, expected 0"
assert not hasattr(
root["b"], "value"
), "Check b attribute, expected no value attribute"
assert root["c"].value == -1, "Check c value, expected -1"

@staticmethod
def test_dataframe_to_tree_empty_row_error():
path_data = pd.DataFrame(columns=["PATH", "age"])
Expand Down Expand Up @@ -2427,6 +2503,31 @@ def test_dataframe_to_tree_by_relation_col_name_reverse(self):
assert_tree_structure_basenode_root_attr(root)
assert_tree_structure_node_root(root)

@staticmethod
def test_dataframe_to_tree_by_relation_zero_attribute():
relation_data = pd.DataFrame(
[
["a", None, 0],
["b", "a", None],
["c", "a", -1],
["d", "b", 40],
["e", "b", 35],
["f", "c", 38],
["g", "e", 10],
["h", "e", 6],
],
columns=["child", "parent", "value"],
)
root = dataframe_to_tree_by_relation(relation_data)
assert_tree_structure_basenode_root(root)
assert_tree_structure_node_root(root)
assert hasattr(root, "value"), "Check root attribute, expected value attribute"
assert root.value == 0, "Check root value, expected 0"
assert not hasattr(
root["b"], "value"
), "Check b attribute, expected no value attribute"
assert root["c"].value == -1, "Check c value, expected -1"

@staticmethod
def test_dataframe_to_tree_by_relation_empty_row_error():
relation_data = pd.DataFrame(columns=["child", "parent"])
Expand Down
2 changes: 1 addition & 1 deletion tests/tree/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def test_print_tree_attr_omit_null_true(tree_node_negative_null_attr):
"│ └── e\n"
"│ ├── g [age=10]\n"
"│ └── h\n"
"└── c\n"
"└── c [age=0]\n"
" └── f\n"
)
assert_print_statement(
Expand Down