Skip to content

📝 Modify

Merging trees modification

There are two types of usage available

  1. 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
  2. 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

  1. Non-replacing scenario: Shift or copy nodes within same tree or between two trees using from_paths (list of paths) and to_paths (list of paths)
  2. Replacing scenario: Shift or copy nodes within same tree or between two trees while replacing the to-node using from_paths (list of paths) and to_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 and Copy Example

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

Advanced Shift Example

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
  • 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 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 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 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 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 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

bigtree.tree.modify

merge_trees

merge_trees(trees, exact=False)

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 that copy must be set to False

If merge_children=True,

  • If to_path is not present, it shifts children of from_path
  • If to_path is present, and overriding=False, original and new children are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new children are retained

If merge_leaves=True,

  • If to_path is not present, it shifts leaves of from_path
  • If to_path is present, and overriding=False, original children and leaves are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new leaves are retained, original child nodes in from_path are retained

Note:

  • merge_children and merge_leaves cannot be both True at the same time
  • overriding and merge_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
>>> shift_nodes(root, ["Downloads/photo1.jpg"], [None])
>>> root.show()
Downloads
└── 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 from_path and to_path

'/'
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 from_paths, results in faster search

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 of from_path
  • If to_path is present, and overriding=False, original and new children are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new children are retained

If merge_leaves=True,

  • If to_path is not present, it copies leaves of from_path
  • If to_path is present, and overriding=False, original children and leaves are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new leaves are retained, original child nodes in from_path are retained

Note:

  • merge_children and merge_leaves cannot be both True at the same time
  • overriding and merge_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 from_path and to_path

'/'
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 from_paths, results in faster search

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 from_path and to_path

'/'
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 from_paths, results in faster search

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 of from_path
  • If to_path is present, and overriding=False, original and new children are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new children are retained

If merge_leaves=True,

  • If to_path is not present, it copies leaves of from_path
  • If to_path is present, and overriding=False, original children and leaves are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new leaves are retained, original child nodes in from_path are retained

Note:

  • merge_children and merge_leaves cannot be both True at the same time
  • overriding and merge_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.

>>> root_other = Node("Documents")
>>> root_other.show()
Documents
>>> 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 from_path and to_path

'/'
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 from_paths, results in faster search

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 from_path and to_path

'/'
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 from_paths, results in faster search

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 that copy must be set to False

If merge_children=True,

  • If to_path is not present, it shifts/copies children of from_path
  • If to_path is present, and overriding=False, original and new children are merged
  • If to_path is present and overriding=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 of from_path
  • If to_path is present, and overriding=False, original children and leaves are merged
  • If to_path is present and overriding=True, it behaves like overriding and only new leaves are retained, original child nodes in from_path are retained

Note:

  • merge_children and merge_leaves cannot be both True at the same time
  • overriding and merge_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 from_path and to_path

'/'
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 from_paths, results in faster search

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 from_path and to_path

'/'
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 from_paths, results in faster search

False