Skip to content

Commit

Permalink
Add tests for expand_tree
Browse files Browse the repository at this point in the history
  • Loading branch information
caesar0301 committed Oct 3, 2016
1 parent e6dab98 commit 16e90b1
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 49 deletions.
15 changes: 9 additions & 6 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ Welcome to treelib's documentation!

**Redistributed under Apache License (2.0) since version 1.3.0.**

`Tree data structure <http://en.wikipedia.org/wiki/Tree_%28data_structure%29>`_
is an important data structure in computer programming languages. It has
important applications where hierarchical data connections are present such as
computer folder structure and decision-tree algorithm in Machine Learning. Thus
`treelib <https://github.com/caesar0301/pyTree>`_ is created to provide an
`Tree data structure
<http://en.wikipedia.org/wiki/Tree_%28data_structure%29>`_ is an
important data structure in computer programming languages. It has
wide applications with hierarchical data connections say file systems
and some algorithms in Machine Learning. `treelib
<https://github.com/caesar0301/pyTree>`_ is created to provide an
efficient implementation of tree data structure in Python.

The main features of `treelib` includes:

* Simple to use in both python 2 and 3.
* Efficient operation of node indexing with the benefit of dictionary type.
* Support various tree operations like **traversing**, **insertion**, **deletion**, **node moving**, **shallow/deep copying**, **subtree cutting** etc.
* Support common tree operations like **traversing**,
**insertion**, **deletion**, **node moving**, **shallow/deep
copying**, **subtree cutting** etc.
* Support user-defined data payload to accelerate your model construction.
* Has pretty tree showing and text/json dump for pretty show and offline analysis.

Expand Down
39 changes: 22 additions & 17 deletions docs/source/pyapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ Useful APIs
.. module:: treelib
:synopsis: Tree data structure in Python.

This `treelib` is a simple module containing only two classes: ``Node`` and
``Tree``. Tree is a self-contained structure with some nodes and connected by
branches. One tree has and only has one root, while a node (except root) has
several children and merely one parent.

*Note:* To solve the string compatibility between Python 2.x and 3.x, treelib
follows the way of porting Python 3.x to 2/3. That means, all strings are
manipulated as unicode and you do not need `u''` prefix anymore. The impacted
functions include `str()`, `show()` and `save2file()` routines. But if your
data contains non-ascii characters and Python 2.x is used, you have to trigger
the compatibility by declaring `unicode_literals` in the code:
`treelib` is a Python module with two primary classes: ``Node`` and
``Tree``. Tree is a self-contained structure with some nodes and
connected by branches. A tree owns merely a root, while a
node (except root) has some children and one parent.

*Note:* To solve string compatibility between Python 2.x and 3.x,
treelib follows the way of porting Python 3.x to 2/3. That means, all
strings are manipulated as unicode and you do not need `u''` prefix
anymore. The impacted functions include `str()`, `show()` and
`save2file()` routines. But if your data contains non-ascii
characters and Python 2.x is used, you have to trigger the
compatibility by declaring `unicode_literals` in the code:

.. code-block:: sh
Expand Down Expand Up @@ -192,8 +193,10 @@ Instance attributes:

Traverse the tree nodes with different modes. ``nid`` refers to the
expanding point to start; ``mode`` refers to the search mode (Tree.DEPTH,
Tree.WIDTH); ``filter`` refers to the function of one variable to act on
the :class:`Node` object; ``key``, ``reverse`` are present to sort
Tree.WIDTH). ``filter`` refers to the function of one variable to act on
the :class:`Node` object. In this manner, the traversing will not continue to
following children of node whose condition does not pass the filter.
``key``, ``reverse`` are present to sort
:class:Node objects at the same level.


Expand Down Expand Up @@ -281,11 +284,13 @@ Instance attributes:

Print the tree structure in hierarchy style. ``nid`` refers to the
expanding point to start; ``level`` refers to the node level in the tree
(root as level 0); ``idhidden`` refers to hiding the node ID when printing;
(root as level 0).
``idhidden`` refers to hiding the node ID when printing.
``filter`` refers to the function of one variable to act on the
:class:`Node` object; ``key``, ``reverse`` are present to sort
:class:`Node` object in the same level. ``data_property`` refers to the property
on the node data object to be printed.
:class:`Node` object. In this manner, the traversing will not continue to
following children of node whose condition does not pass the filter.
``key``, ``reverse`` are present to sort :class:`Node` object in the same level.
``data_property`` refers to the property on the node data object to be printed.

You have three ways to output your tree data, i.e., stdout with ``show()``,
plain text file with ``save2file()``, and json string with ``to_json()``. The
Expand Down
5 changes: 4 additions & 1 deletion tests/test_treelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ def test_expand_tree(self):
self.assertEqual(len(nodes), 2)
nodes = [nid for nid in self.tree.expand_tree(mode=Tree.WIDTH)]
self.assertEqual(nodes, [u'h\xe1rry', u'bill', u'jane', u'george', u'diane'])
nodes = [nid for nid in self.tree.expand_tree(filter = lambda x: x.tag == "Diane")]
nodes = [nid for nid in self.tree.expand_tree(filter = lambda x: x.tag == "Bill")]
self.assertEqual(len(nodes), 0)
nodes = [nid for nid in self.tree.expand_tree(filter = lambda x: x.tag != "Bill")]
self.assertEqual(nodes, [u'h\xe1rry', u'jane', u'diane'])

def test_move_node(self):
diane_parent = self.tree.parent("diane")
Expand Down
2 changes: 1 addition & 1 deletion treelib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '1.3.5'
__version__ = '1.3.6'

from .tree import Tree
from .node import Node
49 changes: 25 additions & 24 deletions treelib/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,29 +246,6 @@ def __update_fpointer(self, nid, child_id, mode):
def __real_true(self, p):
return True

def to_dict(self, nid=None, key=None, sort=True, reverse=False, with_data=False):
"""transform self into a dict"""

nid = self.root if (nid is None) else nid
ntag = self[nid].tag
tree_dict = {ntag: {"children": []}}
if with_data:
tree_dict[ntag]["data"] = self[nid].data

if self[nid].expanded:
queue = [self[i] for i in self[nid].fpointer]
key = (lambda x: x) if (key is None) else key
if sort:
queue.sort(key=key, reverse=reverse)

for elem in queue:
tree_dict[ntag]["children"].append(
self.to_dict(elem.identifier, with_data=with_data, sort=sort, reverse=reverse))
if len(tree_dict[ntag]["children"]) == 0:
tree_dict = self[nid].tag if not with_data else \
{ntag: {"data":self[nid].data}}
return tree_dict

def add_node(self, node, parent=None):
"""
Add a new node to tree.
Expand Down Expand Up @@ -349,7 +326,8 @@ def expand_tree(self, nid=None, mode=DEPTH, filter=None, key=None,
Brian J. Reiser, page 239-241
UPDATE: the @filter function is performed on Node object during
traversing.
traversing. In this manner, the traversing will not continue to
following children of node whose condition does not pass the filter.
UPDATE: the @key and @reverse are present to sort nodes at each
level.
Expand Down Expand Up @@ -710,5 +688,28 @@ def to_json(self, with_data=False, sort=True, reverse=False):
"""Return the json string corresponding to self"""
return json.dumps(self.to_dict(with_data=with_data, sort=sort, reverse=reverse))

def to_dict(self, nid=None, key=None, sort=True, reverse=False, with_data=False):
"""transform self into a dict"""

nid = self.root if (nid is None) else nid
ntag = self[nid].tag
tree_dict = {ntag: {"children": []}}
if with_data:
tree_dict[ntag]["data"] = self[nid].data

if self[nid].expanded:
queue = [self[i] for i in self[nid].fpointer]
key = (lambda x: x) if (key is None) else key
if sort:
queue.sort(key=key, reverse=reverse)

for elem in queue:
tree_dict[ntag]["children"].append(
self.to_dict(elem.identifier, with_data=with_data, sort=sort, reverse=reverse))
if len(tree_dict[ntag]["children"]) == 0:
tree_dict = self[nid].tag if not with_data else \
{ntag: {"data":self[nid].data}}
return tree_dict

if __name__ == '__main__':
pass

0 comments on commit 16e90b1

Please sign in to comment.