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
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ repos:
args: ["--pytest-test-first"]
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: https://github.com/commitizen-tools/commitizen
rev: v3.18.3
hooks:
- id: commitizen
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ 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.16.3] - 2024-03-14
### Added
- BaseNode: Add diameter property.
- Misc: Testing to include benchmark timings for tree creation, compare benchmark tests across commits, reject pull request if benchmark tests fails.
- Misc: Documentation to include benchmark results.
### Changed
- Misc: Documentation to enable zooming in of images, add navigation section headers, remove some meta tags.
- Misc: Split up testing into multiple conftest files.
### Fixed
- Tree Constructor: Tree creation from dictionary adds None for empty attributes instead of np.nan.
- [#216] Tree Exporter: `attr_omit_null` to handle nan/null values in addition to checking for None.

## [0.16.2] - 2024-02-06
### Added
Expand Down Expand Up @@ -502,7 +507,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 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.16.2...HEAD
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.16.3...HEAD
[0.16.3]: https://github.com/kayjan/bigtree/compare/0.16.2...0.16.3
[0.16.2]: https://github.com/kayjan/bigtree/compare/0.16.1...0.16.2
[0.16.1]: https://github.com/kayjan/bigtree/compare/0.16.0...0.16.1
[0.16.0]: https://github.com/kayjan/bigtree/compare/0.15.7...0.16.0
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.16.2"
__version__ = "0.16.3"

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: 2 additions & 0 deletions bigtree/tree/construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ def add_dict_to_tree_by_name(

# Convert dictionary to dataframe
data = pd.DataFrame(name_attrs).T.rename_axis("NAME").reset_index()
data = data.replace({float("nan"): None})
return add_dataframe_to_tree_by_name(tree, data=data, join_type=join_type)


Expand Down Expand Up @@ -681,6 +682,7 @@ def dict_to_tree(

# Convert dictionary to dataframe
data = pd.DataFrame(path_attrs).T.rename_axis("PATH").reset_index()
data = data.replace({float("nan"): None})
return dataframe_to_tree(
data,
sep=sep,
Expand Down
17 changes: 16 additions & 1 deletion bigtree/tree/export.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import collections
import math
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, TypeVar, Union
from urllib.request import urlopen

Expand Down Expand Up @@ -50,6 +51,20 @@
T = TypeVar("T", bound=Node)


def _isnull(value: Any) -> bool:
"""Check if value is null

Args:
value (Any): value to check

Returns:
(bool)
"""
if not value or math.isnan(value):
return True
return False


def print_tree(
tree: T,
node_name_or_path: str = "",
Expand Down Expand Up @@ -195,7 +210,7 @@ def print_tree(
attr_str_list = [
f"{attr_name}={_node.get_attr(attr_name)}"
for attr_name in attr_list
if _node.get_attr(attr_name)
if not _isnull(_node.get_attr(attr_name))
]
else:
attr_str_list = [
Expand Down
2 changes: 1 addition & 1 deletion tests/tree/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def tree_node_negative_null_attr():
c = Node("c", age=0)
d = Node("d", age=1)
e = Node("e", age=None)
f = Node("f")
f = Node("f", age=float("nan"))
g = Node("g")
h = Node("h")

Expand Down
23 changes: 23 additions & 0 deletions tests/tree/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,18 @@ def test_add_dict_to_tree_by_name_custom_node_type(self):
assert_tree_structure_customnode_root_attr(root)
assert_tree_structure_node_root(root)

def test_add_dict_to_tree_by_name_inconsistent_attributes(self):
name_dict = {
"a": {"age": 90},
"b": {},
"c": {"age": 60},
}
root = add_dict_to_tree_by_name(self.root, name_dict)
expected_root_str = "a [age=90.0]\n" "├── b\n" "└── c [age=60.0]\n"
assert_print_statement(
print_tree, expected_root_str, root, all_attrs=True, max_depth=2
)


class TestAddDataFrameToTreeByPath(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -1683,6 +1695,17 @@ def test_dict_to_tree_different_root_error():
root1=root1, root2=root2
)

@staticmethod
def test_dict_to_tree_inconsistent_attributes():
path_dict = {
"a": {"age": 90},
"a/b": {},
"a/c": {"age": 60},
}
root = dict_to_tree(path_dict)
expected_root_str = "a [age=90.0]\n" "├── b\n" "└── c [age=60.0]\n"
assert_print_statement(print_tree, expected_root_str, root, all_attrs=True)


class TestNestedDictToTree(unittest.TestCase):
def setUp(self):
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 @@ -100,7 +100,7 @@ def test_print_tree_attr_omit_null_false(tree_node_negative_null_attr):
"│ ├── g\n"
"│ └── h\n"
"└── c [age=0]\n"
" └── f\n"
" └── f [age=nan]\n"
)
assert_print_statement(
print_tree,
Expand Down