|  | 
| 5 | 5 | from future.utils import python_2_unicode_compatible, iteritems | 
| 6 | 6 | 
 | 
| 7 | 7 | from collections import defaultdict | 
| 8 |  | -from copy import deepcopy | 
| 9 | 8 | from operator import attrgetter | 
| 10 | 9 | 
 | 
| 11 |  | -from .node import Node | 
|  | 10 | +from lighttree.node import Node | 
| 12 | 11 | from .utils import STYLES | 
| 13 | 12 | from .exceptions import MultipleRootError, NotFoundNodeError, DuplicatedNodeError | 
| 14 | 13 | 
 | 
| @@ -72,7 +71,7 @@ def _validate_node_insertion(self, node): | 
| 72 | 71 |             ) | 
| 73 | 72 | 
 | 
| 74 | 73 |     def _validate_tree_insertion(self, tree): | 
| 75 |  | -        if not isinstance(tree, self.__class__): | 
|  | 74 | +        if not isinstance(tree, Tree): | 
| 76 | 75 |             raise ValueError( | 
| 77 | 76 |                 "Tree must be instance of <%s>, got <%s>" | 
| 78 | 77 |                 % (self.__class__.__name__, type(tree)) | 
| @@ -114,11 +113,8 @@ def clone(self, with_tree=True, deep=False, new_root=None): | 
| 114 | 113 | 
 | 
| 115 | 114 |         for nid in self.expand_tree(nid=new_root): | 
| 116 | 115 |             node = self.get(nid) | 
| 117 |  | -            if deep: | 
| 118 |  | -                node = deepcopy(node) | 
| 119 | 116 |             pid = None if nid == self.root or nid == new_root else self.parent(nid) | 
| 120 |  | -            # with_children only makes sense when using "node hierarchy" syntax | 
| 121 |  | -            new_tree.insert_node(node, parent_id=pid, with_children=False) | 
|  | 117 | +            new_tree.insert_node(node, parent_id=pid, deep=deep) | 
| 122 | 118 |         return new_tree | 
| 123 | 119 | 
 | 
| 124 | 120 |     def parent(self, nid, id_only=True): | 
| @@ -210,39 +206,36 @@ def insert( | 
| 210 | 206 |             '"item" parameter must either be a Node, or a Tree, got <%s>.' % type(item) | 
| 211 | 207 |         ) | 
| 212 | 208 | 
 | 
| 213 |  | -    def insert_node( | 
| 214 |  | -        self, node, parent_id=None, child_id=None, deep=False, with_children=True | 
| 215 |  | -    ): | 
|  | 209 | +    def insert_node(self, node, parent_id=None, child_id=None, deep=False): | 
|  | 210 | +        """Make a copy of inserted node, and insert it. | 
|  | 211 | +
 | 
|  | 212 | +        Note: when using "Node hierarchy" syntax, _children attribute of copied node are reset so that insertion occurs | 
|  | 213 | +        once only. | 
|  | 214 | +        """ | 
| 216 | 215 |         self._validate_node_insertion(node) | 
| 217 |  | -        node = deepcopy(node) if deep else node | 
|  | 216 | +        node = node.clone(deep=deep) | 
| 218 | 217 |         if parent_id is not None and child_id is not None: | 
| 219 | 218 |             raise ValueError('Can declare at most "parent_id" or "child_id"') | 
| 220 | 219 |         if child_id is not None: | 
| 221 | 220 |             self._insert_node_above(node, child_id=child_id) | 
| 222 | 221 |             return self | 
| 223 |  | -        self._insert_node_below(node, parent_id=parent_id, with_children=with_children) | 
|  | 222 | +        self._insert_node_below(node, parent_id=parent_id) | 
| 224 | 223 |         return self | 
| 225 | 224 | 
 | 
| 226 |  | -    def _insert_node_below(self, node, parent_id, with_children=True): | 
|  | 225 | +    def _insert_node_below(self, node, parent_id): | 
| 227 | 226 |         # insertion at root | 
| 228 | 227 |         if parent_id is None: | 
| 229 | 228 |             if not self.is_empty(): | 
| 230 | 229 |                 raise MultipleRootError("A tree takes one root merely.") | 
| 231 | 230 |             self.root = node.identifier | 
| 232 | 231 |             self._nodes_map[node.identifier] = node | 
| 233 |  | -            if with_children and hasattr(node, "_children"): | 
| 234 |  | -                for child in node._children or []: | 
| 235 |  | -                    self.insert(child, parent_id=node.identifier) | 
| 236 | 232 |             return | 
| 237 | 233 | 
 | 
| 238 | 234 |         self._ensure_present(parent_id) | 
| 239 | 235 |         node_id = node.identifier | 
| 240 | 236 |         self._nodes_map[node_id] = node | 
| 241 | 237 |         self._nodes_parent[node_id] = parent_id | 
| 242 | 238 |         self._nodes_children[parent_id].add(node_id) | 
| 243 |  | -        if with_children and hasattr(node, "_children"): | 
| 244 |  | -            for child in node._children or []: | 
| 245 |  | -                self.insert(child, parent_id=node.identifier) | 
| 246 | 239 | 
 | 
| 247 | 240 |     def _insert_node_above(self, node, child_id): | 
| 248 | 241 |         self._ensure_present(child_id) | 
| @@ -280,10 +273,8 @@ def _insert_tree_below(self, new_tree, parent_id, deep): | 
| 280 | 273 |         for new_nid in new_tree.expand_tree(): | 
| 281 | 274 |             node = new_tree.get(new_nid) | 
| 282 | 275 |             pid = parent_id if new_nid == new_tree.root else new_tree.parent(new_nid) | 
| 283 |  | -            # with_children only makes sense when using "node hierarchy" syntax | 
| 284 |  | -            self.insert_node( | 
| 285 |  | -                deepcopy(node) if deep else node, parent_id=pid, with_children=False | 
| 286 |  | -            ) | 
|  | 276 | +            # node copy is handled in insert_node method | 
|  | 277 | +            self.insert_node(node, parent_id=pid, deep=deep) | 
| 287 | 278 |         return self | 
| 288 | 279 | 
 | 
| 289 | 280 |     def _insert_tree_above(self, new_tree, child_id, child_id_below, deep): | 
|  | 
0 commit comments