📝 Modify
Merging trees modification
There are two types of usage 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 later 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
Sample Tree Modification (Shift, Copy, Delete)
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 |
Sample Tree Modification (Advanced)
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 c If 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 d If 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=True
to overwrite origin node - Set
merge_attribute=True
to 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=True
ormerge_leaves=True
to 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:
overriding
andmerge_attribute
withmerge_children
andmerge_leaves
overriding
+merge_children
: Behaves likemerge_children
when there is no clash in node name, otherwise behaves likeoverriding
Note that clashes will preserve origin node parent and destination nodes' childrenoverriding
+merge_leaves
: Behaves likemerge_leaves
when there is no clash in node name, otherwise behaves likeoverriding
Note that clashes will preserve origin node parent and destination nodes' leavesmerge_attribute
+merge_children
: Behaves likemerge_children
when there is no clash in node name, otherwise behaves likemerge_attribute
Note that attributes will be merged for node and all descendants, and will preserve origin and destination nodes' childrenmerge_attribute
+merge_leaves
: Behaves likemerge_leaves
when there is no clash in node name, otherwise behaves likemerge_attribute
Note 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 thatcopy
must be set to False
If merge_children=True
,
- If
to_path
is not present, it shifts children offrom_path
- If
to_path
is present, andoverriding=False
, original and new children are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new children are retained
If merge_leaves=True
,
- If
to_path
is not present, it shifts leaves offrom_path
- If
to_path
is present, andoverriding=False
, original children and leaves are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new leaves are retained, original child nodes infrom_path
are retained
Note:
merge_children
andmerge_leaves
cannot be both True at the same timeoverriding
andmerge_attribute
cannot 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[Optional[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
|
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_path
is not present, it copies children offrom_path
- If
to_path
is present, andoverriding=False
, original and new children are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new children are retained
If merge_leaves=True
,
- If
to_path
is not present, it copies leaves offrom_path
- If
to_path
is present, andoverriding=False
, original children and leaves are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new leaves are retained, original child nodes infrom_path
are retained
Note:
merge_children
andmerge_leaves
cannot be both True at the same timeoverriding
andmerge_attribute
cannot 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[Optional[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
|
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_path
is not present, it copies children offrom_path
- If
to_path
is present, andoverriding=False
, original and new children are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new children are retained
If merge_leaves=True
,
- If
to_path
is not present, it copies leaves offrom_path
- If
to_path
is present, andoverriding=False
, original children and leaves are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new leaves are retained, original child nodes infrom_path
are retained
Note:
merge_children
andmerge_leaves
cannot be both True at the same timeoverriding
andmerge_attribute
cannot 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[Optional[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
|
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 thatcopy
must be set to False
If merge_children=True
,
- If
to_path
is not present, it shifts/copies children offrom_path
- If
to_path
is present, andoverriding=False
, original and new children are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new children are retained
If merge_leaves=True
,
- If
to_path
is not present, it shifts/copies leaves offrom_path
- If
to_path
is present, andoverriding=False
, original children and leaves are merged - If
to_path
is present andoverriding=True
, it behaves like overriding and only new leaves are retained, original child nodes infrom_path
are retained
Note:
merge_children
andmerge_leaves
cannot be both True at the same timeoverriding
andmerge_attribute
cannot 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[Optional[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
|
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
|
Optional[T]
|
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
|
Optional[T]
|
tree to copy to |
None
|
with_full_path
|
bool
|
indicator to copy/shift node with full path in |
False
|