Source code for treelib.node
#!/usr/bin/env python
# Copyright (C) 2011
# Brett Alistair Kromkamp - brettkromkamp@gmail.com
# Copyright (C) 2012-2017
# Xiaming Chen - chenxm35@gmail.com
# and other contributors.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Node structure in treelib.
A :class:`Node` object contains basic properties such as node identifier,
node tag, parent node, children nodes etc., and some operations for a node.
"""
import uuid
from .exceptions import NodePropertyError
[docs]class Node(object):
"""
Nodes are elementary objects that are stored in the `_nodes` dictionary of a Tree.
Use `data` attribute to store node-specific data.
"""
#: Mode constants for routine `update_fpointer()`.
(ADD, DELETE, INSERT, REPLACE) = list(range(4))
def __init__(self, tag=None, identifier=None, expanded=True, data=None):
"""Create a new Node object to be placed inside a Tree object"""
#: if given as a parameter, must be unique
self._identifier = None
self._set_identifier(identifier)
#: None or something else
#: if None, self._identifier will be set to the identifier's value.
if tag is None:
self._tag = self._identifier
else:
self._tag = tag
#: boolean
self.expanded = expanded
#: identifier of the parent's node :
self._bpointer = None
#: identifier(s) of the soons' node(s) :
self._fpointer = list()
#: User payload associated with this node.
self.data = data
def __lt__(self, other):
return self.tag < other.tag
def _set_identifier(self, nid):
"""Initialize self._set_identifier"""
if nid is None:
self._identifier = str(uuid.uuid1())
else:
self._identifier = nid
@property
def bpointer(self):
"""
The parent ID of a node. This attribute can be
accessed and modified with ``.`` and ``=`` operator respectively.
"""
return self._bpointer
@bpointer.setter
def bpointer(self, nid):
"""Set the value of `_bpointer`."""
if nid is not None:
self._bpointer = nid
else:
# print("WARNING: the bpointer of node %s " \
# "is set to None" % self._identifier)
self._bpointer = None
@property
def fpointer(self):
"""
With a getting operator, a list of IDs of node's children is obtained. With
a setting operator, the value can be list, set, or dict. For list or set,
it is converted to a list type by the package; for dict, the keys are
treated as the node IDs.
"""
return self._fpointer
@fpointer.setter
def fpointer(self, value):
"""Set the value of `_fpointer`."""
if value is None:
self._fpointer = list()
elif isinstance(value, list):
self._fpointer = value
elif isinstance(value, dict):
self._fpointer = list(value.keys())
elif isinstance(value, set):
self._fpointer = list(value)
else: # TODO: add deprecated routine
pass
@property
def identifier(self):
"""
The unique ID of a node within the scope of a tree. This attribute can be
accessed and modified with ``.`` and ``=`` operator respectively.
"""
return self._identifier
@identifier.setter
def identifier(self, value):
"""Set the value of `_identifier`."""
if value is None:
print("WARNING: node ID can not be None")
else:
self._set_identifier(value)
[docs] def is_leaf(self):
"""Return true if current node has no children."""
if len(self.fpointer) == 0:
return True
else:
return False
[docs] def is_root(self):
"""Return true if self has no parent, i.e. as root."""
return self._bpointer is None
@property
def tag(self):
"""
The readable node name for human. This attribute can be accessed and
modified with ``.`` and ``=`` operator respectively.
"""
return self._tag
@tag.setter
def tag(self, value):
"""Set the value of `_tag`."""
self._tag = value if value is not None else None
[docs] def update_bpointer(self, nid):
"""Set the parent (indicated by the ``nid`` parameter) of a node."""
self.bpointer = nid
[docs] def update_fpointer(self, nid, mode=ADD, replace=None):
"""
Update the children list with different modes: addition (Node.ADD or
Node.INSERT) and deletion (Node.DELETE).
"""
if nid is None:
return
if mode is self.ADD:
self._fpointer.append(nid)
elif mode is self.DELETE:
if nid in self._fpointer:
self._fpointer.remove(nid)
elif mode is self.INSERT: # deprecate to ADD mode
print("WARNING: INSERT is deprecated to ADD mode")
self.update_fpointer(nid)
elif mode is self.REPLACE:
if replace is None:
raise NodePropertyError(
'Argument "repalce" should be provided when mode is {}'.format(mode)
)
ind = self._fpointer.index(nid)
self._fpointer[ind] = replace
def __repr__(self):
name = self.__class__.__name__
kwargs = [
"tag={0}".format(self.tag),
"identifier={0}".format(self.identifier),
"data={0}".format(self.data),
]
return "%s(%s)" % (name, ", ".join(kwargs))