📝 Modify
Merging trees modification
There are two types of merging available
- Merge all nodes of multiple trees together
- The root node name of the trees can be different, resulting tree will take the root name of the first tree
- Attributes are also merged, if there are clashes in attributes, it will take the attribute of the latter tree
- Create a tree with only branches provided (
exact=True)- The root node name of the tree must be the same
- Attributes, if any, exist only for the branches provided. Intermediate node(s) will be created, but without attributes
Shifting and copying node modification
There are two types of modification available
- Non-replacing scenario: Shift or copy nodes within same tree or between two trees using
from_paths(list of paths) andto_paths(list of paths) - Replacing scenario: Shift or copy nodes within same tree or between two trees while replacing the to-node using
from_paths(list of paths) andto_paths(list of paths)
Available Configurations for Customisation
In non-replacing scenario, there are several configurations available for customisation.
| Configuration | Description | Default Value |
|---|---|---|
copy |
Indicates whether it is to shift the nodes, or copy the nodes | False (nodes are shifted, not copied) |
to_tree |
Indicates whether shifting/copying is within the same tree, or between different trees | None (nodes are shifted/copied within the same tree) |
skippable |
Skip shifting/copying of nodes if from_path cannot be found | False (from-node must be found) |
overriding |
Override existing node if it exists | False (to-node must not exist) |
merge_attribute |
Merge attributes of existing node if it exists | False (to-node must not exist, attributes are not merged) |
merge_children |
Shift/copy children of from-node and remove intermediate parent node | False (children are not merged) |
merge_leaves |
Shift/copy leaves of from-node and remove all intermediate nodes | False (leaves are not merged) |
delete_children |
Shift/copy node only and delete its children | False (nodes are shifted/copied together with children) |
In replacing scenario, all the configurations are also available except overriding, merge_attribute,
merge_children, and merge_leaves as it is doing a one-to-one replacement. It is by default overriding, and there is
nothing to merge.
Note
overriding and merge_attribute cannot be simultaneously set to True. One deals with clashing nodes by
overriding, another deals with it by merging attributes of both nodes.
Note
merge_children and merge_leaves cannot be simultaneously set to True.
Note
Error will always be thrown if multiple from-nodes are found, paths in from_paths must be unique.
Tree Modification Permutations
There are several ways you can mix and match the tree modification methods. If you know all the parameters to choose,
feel free to use copy_or_shift_logic or replace_logic methods as they are the most customizable. All other
methods call these 2 methods directly.
| Shift / Copy? | Same tree / Between two trees? | Replace destination node? | Method to use |
|---|---|---|---|
| Shift | Same tree | No | shift_nodes |
| Copy | Same tree | No | copy_nodes |
| Copy | Between two trees | No | copy_nodes_from_tree_to_tree |
| Any | Any | No | copy_or_shift_logic |
| Shift | Same tree | Yes | shift_and_replace_nodes |
| Copy | Between two trees | Yes | copy_and_replace_nodes_from_tree_to_tree |
| Any | Any | Yes | replace_logic |
Tree Modification Illustration
Shift, Copy, Delete
Click to expand code
from bigtree import Node
from bigtree.tree import modify
tree = Node(
"a",
colour="yellow",
children=[
Node("b", colour="yellow"),
Node("c", colour="red"),
Node("d", colour="blue"),
Node("e"),
],
)
tree.show(rich=True, node_format_attr="colour")
# Shift
tree_shift = tree.copy()
modify.shift_nodes(
tree_shift,
from_paths=["a/c", "a/d", "a/e"],
to_paths=["a/b/c", "a/f/d", None],
)
tree_shift.show(rich=True, node_format_attr="colour")
# Copy
tree_copy = tree.copy()
modify.copy_nodes(
tree_copy,
from_paths=["a/c"],
to_paths=["a/b/c"],
)
tree_copy.show(rich=True, node_format_attr="colour")
| Setting | Sample path in from_paths |
Sample path in to_paths |
Description |
|---|---|---|---|
| Default | "/a/c" | "/a/b/c" | Shift/copy node c |
| Default | "/c" | "/a/b/c" | Shift/copy node c |
| Default | "c" | "/a/b/c" | Shift/copy node c |
| Default | "/a/e" | None | Delete node e |
| skippable | "/a/c" | "/a/b/c" | Shift/copy node c, skip if "/a/c" cannot be found |
Advanced
Click to expand code
from bigtree import Tree
from bigtree.tree import modify
tree = Tree.from_dict(
{
"a": dict(colour="yellow"),
"a/b": dict(colour="yellow"),
"a/b/c": dict(colour="red"),
"a/b/c/e": dict(colour="red"),
"a/d": dict(colour="blue"),
"a/d/c": dict(colour="blue"),
"a/d/c/f": dict(colour="blue"),
"a/d/g": dict(colour="blue"),
}
)
tree.show(rich=True, node_format_attr="colour")
# Overriding
tree_overriding = tree.copy()
tree_overriding.shift_nodes(
from_paths=["a/b/c"],
to_paths=["a/d/c"],
overriding=True,
)
tree_overriding.show(rich=True, node_format_attr="colour")
# Merge children
tree_merge_children = tree.copy()
tree_merge_children.shift_nodes(
from_paths=["a/b/c"],
to_paths=["a/d/c"],
merge_children=True,
)
tree_merge_children.show(rich=True, node_format_attr="colour")
# Merge leaves
tree_merge_leaves = tree.copy()
tree_merge_leaves.shift_nodes(
from_paths=["a/b/c"],
to_paths=["a/d/c"],
merge_leaves=True,
)
tree_merge_leaves.show(rich=True, node_format_attr="colour")
# Delete children
tree_delete_children = tree.copy()
tree_delete_children.shift_nodes(
from_paths=["a/b"],
to_paths=["a/d/b"],
delete_children=True,
)
tree_delete_children.show(rich=True, node_format_attr="colour")
| Setting | Sample path in from_paths |
Sample path in to_paths |
Description |
|---|---|---|---|
| overriding | "a/b/c" | "a/d/c" | Shift/copy node c, override if "a/d/c" exists |
| merge_children | "a/b/c" | "a/d/c" | If path not present: Shift/copy children of node c to be children of node d, removing node cIf path present: Shift/copy children of node c to be merged with existing "a/d/c" children |
| merge_children + overriding/merge_attribute | "a/b/c" | "a/d/c" | If path not present: Behaves like merge_children If path present: Behaves like overriding/merge_attribute |
| merge_leaves | "a/b/c" | "a/d/c" | If path not present: Shift/copy leaves of node c to be children of node dIf path present: Shift/copy leaves of node c to be merged with existing "a/d/c" children |
| merge_leaves + overriding/merge_attribute | "a/b/c" | "a/d/c" | If path not present: Behaves like merge_leaves If path present: Behaves like overriding/merge_attribute, but original node c remains |
| delete_children | "a/b" | "a/d/b" | Shift/copy node b only without any node b children |
Guideline
If you're still feeling lost over the parameters, here are some guiding questions to ask yourself.
- Do I want to retain the original node where they are?
- Yes: Set
copy=True - Default performs a shift instead of copy
- Yes: Set
- 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
- Yes: Set
- The origin node (and its descendants) may clash with the destination node(s), how do I want to handle it?
- Set
overriding=Trueto overwrite origin node - Set
merge_attribute=Trueto combine both nodes' attributes - Default throws error about the clash in node name
- Set
- I want to copy/shift everything under the node, but not the node itself
- Set
merge_children=Trueormerge_leaves=Trueto shift the children and leaf nodes respectively - Default shifts the node itself, and everything under it
- Set
- 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
- Yes: Set
- I want to copy/shift things from one tree to another tree
- Specify
to_tree - Default shifts nodes within the same tree
- Specify
What about the permutations between the parameters?
- These parameters are standalone and do not produce any interaction effect
copy,skippable,delete_children
- These parameters have some interaction:
overridingandmerge_attributewithmerge_childrenandmerge_leavesoverriding+merge_children: Behaves likemerge_childrenwhen there is no clash in node name, otherwise behaves likeoverridingNote that clashes will preserve origin node parent and destination nodes' childrenoverriding+merge_leaves: Behaves likemerge_leaveswhen there is no clash in node name, otherwise behaves likeoverridingNote that clashes will preserve origin node parent and destination nodes' leavesmerge_attribute+merge_children: Behaves likemerge_childrenwhen there is no clash in node name, otherwise behaves likemerge_attributeNote that attributes will be merged for node and all descendants, and will preserve origin and destination nodes' childrenmerge_attribute+merge_leaves: Behaves likemerge_leaveswhen there is no clash in node name, otherwise behaves likemerge_attributeNote that attributes will be merged for node and all descendants, and will preserve origin nodes' children and destination nodes' leaves
bigtree.tree.modify
merge_trees
Merge multiple trees into a single tree. Returns a new tree.
If trees have different root names, it will take the root name of the first tree. If same path exists, the attributes of both nodes will be combined, with priority given to the later tree.
- Able to merge only the tree/branches provided exactly, defaults to False (the whole tree is merged), in the case when it is True, it is meant to merge tree branches and only the paths and attributes in the branches are retained. All branches must have the same root name
Examples:
>>> from bigtree import list_to_tree, merge_trees
>>> downloads_folder = list_to_tree(["Downloads/Pictures/photo1.jpg", "Downloads/file1.doc"])
>>> downloads_folder.show()
Downloads
├── Pictures
│ └── photo1.jpg
└── file1.doc
>>> documents_folder = list_to_tree(["Documents/Pictures/photo2.jpg", "Documents/file1.doc"])
>>> documents_folder["file1.doc"].size = 100
>>> documents_folder.show(all_attrs=True)
Documents
├── Pictures
│ └── photo2.jpg
└── file1.doc [size=100]
>>> root = merge_trees([downloads_folder, documents_folder])
>>> root.show(all_attrs=True)
Downloads
├── Pictures
│ ├── photo1.jpg
│ └── photo2.jpg
└── file1.doc [size=100]
In exact=True case, only path and attributes of branches are retained.
>>> from bigtree import dict_to_tree, merge_trees, find_attrs
>>> path_dict = {
... "a": {"age": 90},
... "a/b": {"age": 65},
... "a/c": {"age": 60},
... "a/b/d": {"age": 40},
... "a/b/e": {"age": 35},
... "a/c/f": {"age": 10},
... "a/b/e/g": {"age": 10},
... "a/b/e/h": {"age": 6},
... }
>>> root = dict_to_tree(path_dict)
>>> root.show(attr_list=["age"])
a [age=90]
├── b [age=65]
│ ├── d [age=40]
│ └── e [age=35]
│ ├── g [age=10]
│ └── h [age=6]
└── c [age=60]
└── f [age=10]
>>> nodes = find_attrs(root, "age", 10)
>>> nodes
(Node(/a/b/e/g, age=10), Node(/a/c/f, age=10))
>>> root_filtered = merge_trees(nodes, exact=True)
>>> root_filtered.show(attr_list=["age"])
a
├── b
│ └── e
│ └── g [age=10]
└── c
└── f [age=10]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trees
|
Sequence[T]
|
trees to merge, it can be the tree root or a branch of the tree |
required |
exact
|
bool
|
whether to merge the trees provided exactly; only the paths and attributes of the trees/branches are used. If false, the whole tree is merged |
False
|
Returns:
| Type | Description |
|---|---|
T
|
Merged tree |
shift_nodes
shift_nodes(
tree,
from_paths,
to_paths,
sep="/",
skippable=False,
overriding=False,
merge_attribute=False,
merge_children=False,
merge_leaves=False,
delete_children=False,
with_full_path=False,
)
Shift nodes from from_paths to to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to override existing node if it exists, defaults to False (to-nodes must not exist; not overridden)
- Able to merge attributes of node if it exists, defaults to False (to-nodes must not exist; no attributes to merge)
- Able to merge children and remove intermediate parent node, defaults to False (nodes are shifted; not merged)
- Able to merge leaf nodes and remove all intermediate nodes, defaults to False (nodes are shifted; not merged)
- Able to shift node only and delete children, defaults to False (nodes are shifted together with children)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
- Can set to empty string or None to delete the path in
from_paths, note thatcopymust be set to False
If merge_children=True,
- If
to_pathis not present, it shifts children offrom_path - If
to_pathis present, andoverriding=False, original and new children are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new children are retained
If merge_leaves=True,
- If
to_pathis not present, it shifts leaves offrom_path - If
to_pathis present, andoverriding=False, original children and leaves are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new leaves are retained, original child nodes infrom_pathare retained
Note:
merge_childrenandmerge_leavescannot be both True at the same timeoverridingandmerge_attributecannot be both True at the same time
Examples:
>>> from bigtree import list_to_tree, str_to_tree, shift_nodes
>>> root = list_to_tree(["Downloads/photo1.jpg", "Downloads/file1.doc"])
>>> root.show()
Downloads
├── photo1.jpg
└── file1.doc
>>> shift_nodes(
... tree=root,
... from_paths=["Downloads/photo1.jpg", "Downloads/file1.doc"],
... to_paths=["Downloads/Pictures/photo1.jpg", "Downloads/Files/file1.doc"],
... )
>>> root.show()
Downloads
├── Pictures
│ └── photo1.jpg
└── Files
└── file1.doc
To delete node,
>>> root = list_to_tree(["Downloads/photo1.jpg", "Downloads/file1.doc"])
>>> root.show()
Downloads
├── photo1.jpg
└── file1.doc
In overriding case,
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ └── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Pictures\n"
... " └── photo2.jpg"
... )
>>> root.show()
Downloads
├── Misc
│ └── Pictures
│ └── photo1.jpg
└── Pictures
└── photo2.jpg
>>> shift_nodes(root, ["Downloads/Misc/Pictures"], ["Downloads/Pictures"], overriding=True)
>>> root.show()
Downloads
├── Misc
└── Pictures
└── photo1.jpg
In merge_children=True case, child nodes are shifted instead of the parent node.
- If the path already exists, child nodes are merged with existing children
- Otherwise, the child nodes of the node are merged with the node's parent
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ ├── Pictures\n"
... "│ │ └── photo2.jpg\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── dummy\n"
... " └── Files\n"
... " └── file1.doc"
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ └── photo1.jpg
└── dummy
└── Files
└── file1.doc
>>> shift_nodes(
... root,
... ["Downloads/Misc/Pictures", "Applications", "Downloads/dummy"],
... ["Downloads/Pictures", "Downloads/Applications", "Downloads/dummy"],
... merge_children=True,
... )
>>> root.show()
Downloads
├── Misc
├── Pictures
│ ├── photo1.jpg
│ └── photo2.jpg
├── Chrome.exe
└── Files
└── file1.doc
In merge_leaves=True case, leaf nodes are shifted instead of the parent node.
- If the path already exists, leaf nodes are merged with existing children
- Otherwise, the leaf nodes of the node are merged with the node's parent
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ ├── Pictures\n"
... "│ │ └── photo2.jpg\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── dummy\n"
... " └── Files\n"
... " └── file1.doc"
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ └── photo1.jpg
└── dummy
└── Files
└── file1.doc
>>> shift_nodes(
... root,
... ["Downloads/Misc/Pictures", "Applications", "Downloads/dummy"],
... ["Downloads/Pictures", "Downloads/Applications", "Downloads/dummy"],
... merge_leaves=True,
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ └── Applications
├── Pictures
│ ├── photo1.jpg
│ └── photo2.jpg
├── dummy
│ └── Files
├── Chrome.exe
└── file1.doc
In delete_children=True case, only the node is shifted without its accompanying children/descendants.
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "└── Pictures\n"
... " └── photo1.jpg"
... )
>>> root.show()
Downloads
├── Misc
│ └── Applications
│ └── Chrome.exe
└── Pictures
└── photo1.jpg
>>> shift_nodes(root, ["Applications"], ["Downloads/Applications"], delete_children=True)
>>> root.show()
Downloads
├── Misc
├── Pictures
│ └── photo1.jpg
└── Applications
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
T
|
tree to modify |
required |
from_paths
|
Collection[str]
|
original paths to shift nodes from |
required |
to_paths
|
Collection[str | None]
|
new paths to shift nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
skippable
|
bool
|
indicator to skip if from-path is not found |
False
|
overriding
|
bool
|
indicator to override existing to-path if there are clashes |
False
|
merge_attribute
|
bool
|
indicator to merge attributes of from-path and to-path if there are clashes |
False
|
merge_children
|
bool
|
indicator to merge from-path's children and remove intermediate parent node |
False
|
merge_leaves
|
bool
|
indicator to merge from-path's leaf nodes and remove intermediate parent node(s) |
False
|
delete_children
|
bool
|
indicator to shift node only without children |
False
|
with_full_path
|
bool
|
indicator to shift node with full path in |
False
|
copy_nodes
copy_nodes(
tree,
from_paths,
to_paths,
sep="/",
skippable=False,
overriding=False,
merge_attribute=False,
merge_children=False,
merge_leaves=False,
delete_children=False,
with_full_path=False,
)
Copy nodes from from_paths to to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to override existing node if it exists, defaults to False (to-nodes must not exist; not overridden)
- Able to merge attributes of node if it exists, defaults to False (to-nodes must not exist; no attributes to merge)
- Able to merge children and remove intermediate parent node, defaults to False (nodes are copied; not merged)
- Able to merge only leaf nodes and remove all intermediate nodes, defaults to False (nodes are copied; not merged)
- Able to copy node only and delete children, defaults to False (nodes are copied together with children)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
If merge_children=True,
- If
to_pathis not present, it copies children offrom_path - If
to_pathis present, andoverriding=False, original and new children are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new children are retained
If merge_leaves=True,
- If
to_pathis not present, it copies leaves offrom_path - If
to_pathis present, andoverriding=False, original children and leaves are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new leaves are retained, original child nodes infrom_pathare retained
Note:
merge_childrenandmerge_leavescannot be both True at the same timeoverridingandmerge_attributecannot be both True at the same time
Examples:
>>> from bigtree import list_to_tree, str_to_tree, copy_nodes
>>> root = list_to_tree(["Downloads/Pictures", "Downloads/photo1.jpg", "Downloads/file1.doc"])
>>> root.show()
Downloads
├── Pictures
├── photo1.jpg
└── file1.doc
>>> copy_nodes(
... tree=root,
... from_paths=["Downloads/photo1.jpg", "Downloads/file1.doc"],
... to_paths=["Downloads/Pictures/photo1.jpg", "Downloads/Files/file1.doc"],
... )
>>> root.show()
Downloads
├── Pictures
│ └── photo1.jpg
├── photo1.jpg
├── file1.doc
└── Files
└── file1.doc
In overriding case,
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ └── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Pictures\n"
... " └── photo2.jpg"
... )
>>> root.show()
Downloads
├── Misc
│ └── Pictures
│ └── photo1.jpg
└── Pictures
└── photo2.jpg
>>> copy_nodes(root, ["Downloads/Misc/Pictures"], ["Downloads/Pictures"], overriding=True)
>>> root.show()
Downloads
├── Misc
│ └── Pictures
│ └── photo1.jpg
└── Pictures
└── photo1.jpg
In merge_children=True case, child nodes are copied instead of the parent node.
- If the path already exists, child nodes are merged with existing children
- Otherwise, the child nodes of the node are merged with the node's parent
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ ├── Pictures\n"
... "│ │ └── photo2.jpg\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── dummy\n"
... " └── Files\n"
... " └── file1.doc"
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ └── photo1.jpg
└── dummy
└── Files
└── file1.doc
>>> copy_nodes(
... root,
... ["Downloads/Misc/Pictures", "Applications", "Downloads/dummy"],
... ["Downloads/Pictures", "Downloads/Applications", "Downloads/dummy"],
... merge_children=True,
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ ├── photo1.jpg
│ └── photo2.jpg
├── Chrome.exe
└── Files
└── file1.doc
In merge_leaves=True case, leaf nodes are copied instead of the parent node.
- If the path already exists, leaf nodes are merged with existing children
- Otherwise, the leaf nodes of the node are merged with the node's parent
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ ├── Pictures\n"
... "│ │ └── photo2.jpg\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── dummy\n"
... " └── Files\n"
... " └── file1.doc"
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ └── photo1.jpg
└── dummy
└── Files
└── file1.doc
>>> copy_nodes(
... root,
... ["Downloads/Misc/Pictures", "Applications", "Downloads/dummy"],
... ["Downloads/Pictures", "Downloads/Applications", "Downloads/dummy"],
... merge_leaves=True,
... )
>>> root.show()
Downloads
├── Misc
│ ├── Pictures
│ │ └── photo2.jpg
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ ├── photo1.jpg
│ └── photo2.jpg
├── dummy
│ └── Files
│ └── file1.doc
├── Chrome.exe
└── file1.doc
In delete_children=True case, only the node is copied without its accompanying children/descendants.
>>> root = str_to_tree(
... "Downloads\n"
... "├── Misc\n"
... "│ └── Applications\n"
... "│ └── Chrome.exe\n"
... "└── Pictures\n"
... " └── photo1.jpg"
... )
>>> root.show()
Downloads
├── Misc
│ └── Applications
│ └── Chrome.exe
└── Pictures
└── photo1.jpg
>>> copy_nodes(root, ["Applications"], ["Downloads/Applications"], delete_children=True)
>>> root.show()
Downloads
├── Misc
│ └── Applications
│ └── Chrome.exe
├── Pictures
│ └── photo1.jpg
└── Applications
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
T
|
tree to modify |
required |
from_paths
|
Collection[str]
|
original paths to copy nodes from |
required |
to_paths
|
Collection[str | None]
|
new paths to copy nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
skippable
|
bool
|
indicator to skip if from-path is not found |
False
|
overriding
|
bool
|
indicator to override existing to-path if there are clashes |
False
|
merge_attribute
|
bool
|
indicator to merge attributes of from-path and to-path if there are clashes |
False
|
merge_children
|
bool
|
indicator to merge from-path's children and remove intermediate parent node |
False
|
merge_leaves
|
bool
|
indicator to merge from-path's leaf nodes and remove intermediate parent node(s) |
False
|
delete_children
|
bool
|
indicator to copy node only without children |
False
|
with_full_path
|
bool
|
indicator to copy node with full path in |
False
|
shift_and_replace_nodes
shift_and_replace_nodes(
tree,
from_paths,
to_paths,
sep="/",
skippable=False,
delete_children=False,
with_full_path=False,
)
Shift nodes from from_paths to replace to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to shift node only and delete children, defaults to False (nodes are shifted together with children)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
- Path must exist, node-to-be-replaced must be present
Examples:
>>> from bigtree import str_to_tree, shift_and_replace_nodes
>>> root = str_to_tree(
... "Downloads\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Misc\n"
... " └── dummy"
... )
>>> root.show()
Downloads
├── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
>>> shift_and_replace_nodes(root, ["Downloads/Pictures"], ["Downloads/Misc/dummy"])
>>> root.show()
Downloads
└── Misc
└── Pictures
└── photo1.jpg
In delete_children=True case, only the node is shifted without its accompanying children/descendants.
>>> root = str_to_tree(
... "Downloads\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Misc\n"
... " └── dummy"
... )
>>> root.show()
Downloads
├── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
>>> shift_and_replace_nodes(root, ["Downloads/Pictures"], ["Downloads/Misc/dummy"], delete_children=True)
>>> root.show()
Downloads
└── Misc
└── Pictures
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
T
|
tree to modify |
required |
from_paths
|
Collection[str]
|
original paths to shift nodes from |
required |
to_paths
|
Collection[str]
|
new paths to shift nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
skippable
|
bool
|
indicator to skip if from-path is not found |
False
|
delete_children
|
bool
|
indicator to shift node only without children |
False
|
with_full_path
|
bool
|
indicator to shift node with full path in |
False
|
copy_nodes_from_tree_to_tree
copy_nodes_from_tree_to_tree(
from_tree,
to_tree,
from_paths,
to_paths,
sep="/",
skippable=False,
overriding=False,
merge_attribute=False,
merge_children=False,
merge_leaves=False,
delete_children=False,
with_full_path=False,
)
Copy nodes from from_paths to to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to override existing node if it exists, defaults to False (to-nodes must not exist; not overridden)
- Able to merge attributes of node if it exists, defaults to False (to-nodes must not exist; no attributes to merge)
- Able to merge children and remove intermediate parent node, defaults to False (nodes are shifted; not merged)
- Able to merge leaf nodes and remove all intermediate nodes, defaults to False (nodes are shifted; not merged)
- Able to copy node only and delete children, defaults to False (nodes are copied together with children)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
If merge_children=True,
- If
to_pathis not present, it copies children offrom_path - If
to_pathis present, andoverriding=False, original and new children are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new children are retained
If merge_leaves=True,
- If
to_pathis not present, it copies leaves offrom_path - If
to_pathis present, andoverriding=False, original children and leaves are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new leaves are retained, original child nodes infrom_pathare retained
Note:
merge_childrenandmerge_leavescannot be both True at the same timeoverridingandmerge_attributecannot be both True at the same time
Examples:
>>> from bigtree import Node, str_to_tree, copy_nodes_from_tree_to_tree
>>> root = str_to_tree(
... "Downloads\n"
... "├── file1.doc\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Misc\n"
... " └── dummy\n"
... " └── photo2.jpg"
... )
>>> root.show()
Downloads
├── file1.doc
├── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
└── photo2.jpg
>>> root_other = Node("Documents")
>>> copy_nodes_from_tree_to_tree(
... from_tree=root,
... to_tree=root_other,
... from_paths=["Downloads/Pictures", "Downloads/Misc"],
... to_paths=["Documents/Pictures", "Documents/New Misc/Misc"],
... )
>>> root_other.show()
Documents
├── Pictures
│ └── photo1.jpg
└── New Misc
└── Misc
└── dummy
└── photo2.jpg
In overriding case,
>>> root_other = str_to_tree(
... "Documents\n"
... "└── Pictures\n"
... " └── photo3.jpg"
... )
>>> root_other.show()
Documents
└── Pictures
└── photo3.jpg
>>> copy_nodes_from_tree_to_tree(
... root,
... root_other,
... ["Downloads/Pictures", "Downloads/Misc"],
... ["Documents/Pictures", "Documents/Misc"],
... overriding=True,
... )
>>> root_other.show()
Documents
├── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
└── photo2.jpg
In merge_children=True case, child nodes are copied instead of the parent node.
- If the path already exists, child nodes are merged with existing children
- Otherwise, the child nodes of the node are merged with the node's parent
>>> root_other = str_to_tree(
... "Documents\n"
... "└── Pictures\n"
... " └── photo3.jpg"
... )
>>> root_other.show()
Documents
└── Pictures
└── photo3.jpg
>>> copy_nodes_from_tree_to_tree(
... root,
... root_other,
... ["Downloads/Pictures", "Downloads/Misc"],
... ["Documents/Pictures", "Documents/Misc"],
... merge_children=True,
... )
>>> root_other.show()
Documents
├── Pictures
│ ├── photo3.jpg
│ └── photo1.jpg
└── dummy
└── photo2.jpg
In merge_leaves=True case, leaf nodes are copied instead of the parent node.
- If the path already exists, leaf nodes are merged with existing children
- Otherwise, the leaf nodes of the node are merged with the node's parent
>>> root_other = str_to_tree(
... "Documents\n"
... "└── Pictures\n"
... " └── photo3.jpg"
... )
>>> root_other.show()
Documents
└── Pictures
└── photo3.jpg
>>> copy_nodes_from_tree_to_tree(
... root,
... root_other,
... ["Downloads/Pictures", "Downloads/Misc"],
... ["Documents/Pictures", "Documents/Misc"],
... merge_leaves=True,
... )
>>> root_other.show()
Documents
├── Pictures
│ ├── photo3.jpg
│ └── photo1.jpg
└── photo2.jpg
In delete_children=True case, only the node is copied without its accompanying children/descendants.
>>> copy_nodes_from_tree_to_tree(
... root,
... root_other,
... ["Downloads/Pictures", "Downloads/Misc"],
... ["Documents/Pictures", "Documents/Misc"],
... delete_children=True,
... )
>>> root_other.show()
Documents
├── Pictures
└── Misc
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_tree
|
T
|
tree to copy nodes from |
required |
to_tree
|
T
|
tree to copy nodes to |
required |
from_paths
|
Collection[str]
|
original paths to copy nodes from |
required |
to_paths
|
Collection[str | None]
|
new paths to copy nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
skippable
|
bool
|
indicator to skip if from path is not found |
False
|
overriding
|
bool
|
indicator to override existing to path if there is clashes |
False
|
merge_attribute
|
bool
|
indicator to merge attributes of from-path and to-path if there are clashes |
False
|
merge_children
|
bool
|
indicator to merge from-path's children and remove intermediate parent node |
False
|
merge_leaves
|
bool
|
indicator to merge from-path's leaf nodes and remove intermediate parent node(s) |
False
|
delete_children
|
bool
|
indicator to copy node only without children |
False
|
with_full_path
|
bool
|
indicator to copy node with full path in |
False
|
copy_and_replace_nodes_from_tree_to_tree
copy_and_replace_nodes_from_tree_to_tree(
from_tree,
to_tree,
from_paths,
to_paths,
sep="/",
skippable=False,
delete_children=False,
with_full_path=False,
)
Copy nodes from from_paths to replace to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to copy node only and delete children, defaults to False (nodes are copied together with children)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
- Path must exist, node-to-be-replaced must be present
Examples:
>>> from bigtree import str_to_tree, copy_and_replace_nodes_from_tree_to_tree
>>> root = str_to_tree(
... "Downloads\n"
... "├── file1.doc\n"
... "├── Pictures\n"
... "│ └── photo1.jpg\n"
... "└── Misc\n"
... " └── dummy\n"
... " └── photo2.jpg"
... )
>>> root.show()
Downloads
├── file1.doc
├── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
└── photo2.jpg
>>> root_other = str_to_tree(
... "Documents\n"
... "├── Pictures2\n"
... "│ └── photo2.jpg\n"
... "└── Misc2"
... )
>>> root_other.show()
Documents
├── Pictures2
│ └── photo2.jpg
└── Misc2
>>> copy_and_replace_nodes_from_tree_to_tree(
... from_tree=root,
... to_tree=root_other,
... from_paths=["Downloads/Pictures", "Downloads/Misc"],
... to_paths=["Documents/Pictures2/photo2.jpg", "Documents/Misc2"],
... )
>>> root_other.show()
Documents
├── Pictures2
│ └── Pictures
│ └── photo1.jpg
└── Misc
└── dummy
└── photo2.jpg
In delete_children=True case, only the node is copied without its accompanying children/descendants.
>>> root_other = str_to_tree(
... "Documents\n"
... "├── Pictures2\n"
... "│ └── photo2.jpg\n"
... "└── Misc2"
... )
>>> root_other.show()
Documents
├── Pictures2
│ └── photo2.jpg
└── Misc2
>>> copy_and_replace_nodes_from_tree_to_tree(
... from_tree=root,
... to_tree=root_other,
... from_paths=["Downloads/Pictures", "Downloads/Misc"],
... to_paths=["Documents/Pictures2/photo2.jpg", "Documents/Misc2"],
... delete_children=True,
... )
>>> root_other.show()
Documents
├── Pictures2
│ └── Pictures
└── Misc
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_tree
|
T
|
tree to copy nodes from |
required |
to_tree
|
T
|
tree to copy nodes to |
required |
from_paths
|
Collection[str]
|
original paths to copy nodes from |
required |
to_paths
|
Collection[str]
|
new paths to copy nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
skippable
|
bool
|
indicator to skip if from path is not found |
False
|
delete_children
|
bool
|
indicator to copy node only without children |
False
|
with_full_path
|
bool
|
indicator to copy node with full path in |
False
|
copy_or_shift_logic
copy_or_shift_logic(
tree,
from_paths,
to_paths,
sep="/",
copy=False,
skippable=False,
overriding=False,
merge_attribute=False,
merge_children=False,
merge_leaves=False,
delete_children=False,
to_tree=None,
with_full_path=False,
)
Shift or copy nodes from from_paths to to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to copy node, defaults to False (nodes are shifted; not copied)
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to override existing node if it exists, defaults to False (to-nodes must not exist; not overridden)
- Able to merge attributes of node if it exists, defaults to False (to-nodes must not exist; no attributes to merge)
- Able to merge children and remove intermediate parent node, defaults to False (nodes are shifted; not merged)
- Able to merge only leaf nodes and remove all intermediate nodes, defaults to False (nodes are shifted; not merged)
- Able to shift/copy node only and delete children, defaults to False (nodes are shifted/copied together with children)
- Able to shift/copy nodes from one tree to another tree, defaults to None (shifting/copying happens within same tree)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
- Can set to empty string or None to delete the path in
from_paths, note thatcopymust be set to False
If merge_children=True,
- If
to_pathis not present, it shifts/copies children offrom_path - If
to_pathis present, andoverriding=False, original and new children are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new children are retained
If merge_leaves=True,
- If
to_pathis not present, it shifts/copies leaves offrom_path - If
to_pathis present, andoverriding=False, original children and leaves are merged - If
to_pathis present andoverriding=True, it behaves like overriding and only new leaves are retained, original child nodes infrom_pathare retained
Note:
merge_childrenandmerge_leavescannot be both True at the same timeoverridingandmerge_attributecannot be both True at the same time
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
T
|
tree to modify |
required |
from_paths
|
Collection[str]
|
original paths to copy/shift nodes from |
required |
to_paths
|
Collection[str | None]
|
new paths to copy/shift nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
copy
|
bool
|
indicator to copy node, |
False
|
skippable
|
bool
|
indicator to skip if from-path is not found |
False
|
overriding
|
bool
|
indicator to override existing to-path if there are clashes |
False
|
merge_attribute
|
bool
|
indicator to merge attributes of from-path and to-path if there are clashes |
False
|
merge_children
|
bool
|
indicator to merge from-path's children and remove intermediate parent node |
False
|
merge_leaves
|
bool
|
indicator to merge from-path's leaf nodes and remove intermediate parent node(s) |
False
|
delete_children
|
bool
|
indicator to copy/shift node only without children |
False
|
to_tree
|
T | None
|
tree to copy to |
None
|
with_full_path
|
bool
|
indicator to copy/shift node with full path in |
False
|
replace_logic
replace_logic(
tree,
from_paths,
to_paths,
sep="/",
copy=False,
skippable=False,
delete_children=False,
to_tree=None,
with_full_path=False,
)
Shift or copy nodes from from_paths to replace to_paths in-place.
- Creates intermediate nodes if to-path is not present
- Able to copy node, defaults to False (nodes are shifted; not copied)
- Able to skip nodes if from-path is not found, defaults to False (from-nodes must be found; not skippable)
- Able to replace node only and delete children, defaults to False (nodes are shifted/copied together with children)
- Able to shift/copy nodes from one tree to another tree, defaults to None (shifting/copying happens within same tree)
For paths in from_paths and to_paths,
- Path name can be with or without leading tree path separator symbol
For paths in from_paths,
- Path name can be partial path (trailing part of path) or node name
- If
with_full_path=True, path name must be full path - Path name must be unique to one node
For paths in to_paths,
- Path name must be full path
- Path must exist, node-to-be-replaced must be present
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
T
|
tree to modify |
required |
from_paths
|
Collection[str]
|
original paths to copy/shift nodes from |
required |
to_paths
|
Collection[str]
|
new paths to copy/shift nodes to |
required |
sep
|
str
|
path separator for input paths, applies to |
'/'
|
copy
|
bool
|
indicator to copy node |
False
|
skippable
|
bool
|
indicator to skip if from-path is not found |
False
|
delete_children
|
bool
|
indicator to copy/shift node only without children |
False
|
to_tree
|
T | None
|
tree to copy to |
None
|
with_full_path
|
bool
|
indicator to copy/shift node with full path in |
False
|

