Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.23.0 + Modify module logic changes #335

Merged
merged 2 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 6 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.23.0] - 2024-12-26
### Changed:
- Tree Modify: Update documentation and docstring with some rephrasing.
- Tree Modify: Clean up test cases.
### Added:
- Tree Modify: Add parameter `merge_attribute` to allow from-node and to-node attributes to be merged if there are clashes.
### Fixed:
- Tree Modify: Fixed bug when `merge_children` is used with `overriding` as the `merge_children` value is changed in for-loop (bad move, literally).
- Tree Modify: Fixed bug when `merge_children` is used with `overriding` as the `merge_children` value is changed in
for-loop (bad move, literally). Modified the logic such that if there are clashes for `merge_children=True, overriding=True`,
the origin node parent and destination node children are preserved. The origin node's children are overridden.
**This might not be backwards-compatible!**

## [0.22.3] - 2024-11-14
### Added:
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.22.3"
__version__ = "0.23.0"

from bigtree.binarytree.construct import list_to_binarytree
from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag
Expand Down
29 changes: 11 additions & 18 deletions bigtree/tree/modify.py
Original file line number Diff line number Diff line change
Expand Up @@ -1216,10 +1216,6 @@ def copy_or_shift_logic(

# Perform shifting/copying
for from_path, to_path in zip(from_paths, to_paths):
# Reset parameters
merge_children2 = merge_children
merge_leaves2 = merge_leaves

if with_full_path:
from_node = search.find_full_path(tree, from_path)
else:
Expand Down Expand Up @@ -1264,10 +1260,7 @@ def copy_or_shift_logic(
logging.info(
f"Path {to_path} already exists and its children be overridden by the merge"
)
parent = to_node.parent
to_node.parent = None
to_node = parent
merge_children2 = False
del to_node.children
elif merge_attribute:
logging.info(
f"Path {to_path} already exists and their attributes will be merged"
Expand All @@ -1279,10 +1272,10 @@ def copy_or_shift_logic(
merge_children=merge_children,
merge_leaves=merge_leaves,
)
parent = to_node.parent
to_node.parent = None
to_node = parent
merge_children2 = False
to_node.set_attrs(
dict(from_node.describe(exclude_prefix="_"))
)
del to_node.children
else:
logging.info(
f"Path {to_path} already exists and children are merged"
Expand All @@ -1304,10 +1297,10 @@ def copy_or_shift_logic(
merge_children=merge_children,
merge_leaves=merge_leaves,
)
parent = to_node.parent
to_node.parent = None
to_node = parent
merge_leaves2 = False
to_node.set_attrs(
dict(from_node.describe(exclude_prefix="_"))
)
del to_node.children
else:
logging.info(
f"Path {to_path} already exists and leaves are merged"
Expand Down Expand Up @@ -1353,7 +1346,7 @@ def copy_or_shift_logic(
if copy:
logging.debug(f"Copying {from_node.node_name}")
from_node = from_node.copy()
if merge_children2:
if merge_children:
# overriding / merge_attribute handled merge_children, set merge_children=False
logging.debug(
f"Reassigning children from {from_node.node_name} to {to_node.node_name}"
Expand All @@ -1363,7 +1356,7 @@ def copy_or_shift_logic(
del children.children
children.parent = to_node
from_node.parent = None
elif merge_leaves2:
elif merge_leaves:
logging.debug(
f"Reassigning leaf nodes from {from_node.node_name} to {to_node.node_name}"
)
Expand Down
22 changes: 13 additions & 9 deletions docs/bigtree/tree/modify.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,33 +94,37 @@ If you're still feeling lost over the parameters, here are some guiding question
- Do I want to retain the original node where they are?
- Yes: Set `copy=True`
- Default performs a shift instead of copy
- Am I unsure of what nodes I am going to shift, they may or may not exist and this is perfectly fine?
- Am I unsure of what nodes I am going to copy/shift, they may or may not exist and this is perfectly fine?
- Yes: Set `skippable=True`
- Default throws error if origin node is not found
- The origin node (and its descendants) may clash with the destination node(s), how do I want to handle it?
- Set `overriding=True` to overwrite origin node
- Set `merge_attribute=True` to combine both nodes' attributes
- Default throws error about the clash in node name
- I want to shift everything under the node, but not the node itself
- I want to copy/shift everything under the node, but not the node itself
- Set `merge_children=True` or `merge_leaves=True` to shift the children and leaf nodes respectively
- Default shifts the node itself, and everything under it
- I want to shift the node and only the node, and not everything under it
- I want to copy/shift the node and only the node, and not everything under it
- Yes: Set `delete_children=True`
- Default shifts the node itself, and everything under it
- I want to shift things from one tree to another tree
- I want to copy/shift things from one tree to another tree
- Specify `to_tree`
- Default shifts nodes within the same tree

What about the permutations between the parameters?

- These parameters are standalone and does not produce any interaction effect
- These parameters are standalone and do not produce any interaction effect
- `copy`, `skippable`, `delete_children`
- These parameters have some interaction:
- `overriding` and `merge_attribute` with `merge_children` and `merge_leaves`
- `overriding` + `merge_children`: Behaves like `merge_children` when there is no clash in node name, otherwise behaves like `overriding`. Note that clashes will preserve destination nodes' children only.
- `overriding` + `merge_leaves`: Behaves like `merge_leaves` when there is no clash in node name, otherwise behaves like `overriding`. Note that clashes will preserve destination nodes' leaves only.
- `merge_attribute` + `merge_children`: Behaves like `merge_children` when there is no clash in node name, otherwise behaves like `merge_attribute`. Note that attributes will be merged for node and all descendants, and will preserve origin and destination nodes' children.
- `merge_attribute` + `merge_leaves`: Behaves like `merge_leaves` when there is no clash in node name, otherwise behaves like `merge_attribute`. Note that attributes will be merged for node and all descendants, and will preserve origin nodes' children and destination nodes' leaves.
- `overriding` + `merge_children`: Behaves like `merge_children` when there is no clash in node name, otherwise behaves like `overriding`.
Note that clashes will preserve origin node parent and destination nodes' children.
- `overriding` + `merge_leaves`: Behaves like `merge_leaves` when there is no clash in node name, otherwise behaves like `overriding`.
Note that clashes will preserve origin node parent and destination nodes' leaves.
- `merge_attribute` + `merge_children`: Behaves like `merge_children` when there is no clash in node name, otherwise behaves like `merge_attribute`.
Note that attributes will be merged for node and all descendants, and will preserve origin and destination nodes' children.
- `merge_attribute` + `merge_leaves`: Behaves like `merge_leaves` when there is no clash in node name, otherwise behaves like `merge_attribute`.
Note that attributes will be merged for node and all descendants, and will preserve origin nodes' children and destination nodes' leaves.

-----

Expand Down
3 changes: 3 additions & 0 deletions docs/gettingstarted/demo/tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,9 @@ Nodes can be <mark>shifted</mark> (with or without replacement) or <mark>copied<
from one path to another, this changes the tree in-place.
Nodes can also be copied (with or without replacement) <mark>between two different trees</mark>.

There are various other configurations for performing copying/shifting, refer to [code documentation](../../bigtree/tree/modify.md)
for more examples.

=== "Shift nodes"
```python hl_lines="12-16 24-28"
from bigtree import list_to_tree, shift_nodes, shift_and_replace_nodes
Expand Down
2 changes: 1 addition & 1 deletion tests/tree/test_modify.py
Original file line number Diff line number Diff line change
Expand Up @@ -2377,7 +2377,7 @@ def test_copy_nodes_from_tree_to_tree_merge_children_overriding(self):
overriding=True,
)
assert_tree_structure_basenode_root(self.root_other_full_wrong)
assert_tree_structure_basenode_root_attr(self.root_other_full_wrong)
assert_tree_structure_basenode_root_attr(self.root_other_full_wrong, c=("c", 1))
assert_tree_structure_node_root(self.root_other_full_wrong)

# merge_children, merge_attribute
Expand Down
Loading