# Source code for arandomness.trees.omnitree

```
#! /usr/bin/env python
"""A many-to-many tree with self-aware features
Copyright:
omnitree.py A many-to-many tree with self-aware features
Copyright (C) 2017 Alex Hyer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
__author__ = 'Alex Hyer'
__email__ = 'theonehyer@gmail.com'
__license__ = 'GPLv3'
__maintainer__ = 'Alex Hyer'
__status__ = 'Inactive'
__version__ = '0.1.0a7'
[docs]class OmniTree(object):
"""A many-to-many tree for organizing and manipulating hierarchical data
Attributes:
label (unicode): optional, arbitrary name for node
"""
[docs] def __init__(self, label=None, children=None, parents=None):
"""Initialize node and inform connected nodes"""
self._children = [] # list of child nodes
self._parents = [] # list of parent nodes
self.label = label
# Assign children and notify them if needed
if children is not None:
self._children = children
for child in self._children:
child.add_parents([self])
# Assign parents and notify them if needed
if parents is not None:
self._parents = parents
for parent in self._parents:
parent.add_children([self])
[docs] def add_children(self, children):
"""Adds new children nodes after filtering for duplicates
Args:
children (list): list of OmniTree nodes to add as children
"""
self._children += [c for c in children if c not in self._children]
[docs] def add_parents(self, parents):
"""Adds new parent nodes after filtering for duplicates
Args:
parents (list): list of OmniTree nodes to add as parents
"""
self._parents += [p for p in parents if p not in self._parents]
[docs] def find_loops(self, _path=None):
"""Crappy function that finds a single loop in the tree"""
if _path is None:
_path = []
if self in _path:
return _path + [self]
elif self._children == []:
return None
else:
for child in self._children:
return child.find_loops(_path + [self])
[docs] def find_branches(self, labels=False, unique=False):
"""Recursively constructs a list of pointers of the tree's structure
Args:
labels (bool): If True, returned lists consist of node labels.
If False (default), lists consist of node
pointers. This option is mostly intended for
debugging purposes.
unique (bool): If True, return lists of all unique, linear branches
of the tree. More accurately, it returns a list
of lists where each list contains a single,
unique, linear path from the calling node to the
tree's leaf nodes. If False (default),
a highly-nested list is returned where each nested
list represents a branch point in the tree.
See Examples for more.
Examples:
>>> from arandomness.trees import OmniTree
>>> a = OmniTree(label='a')
>>> b = OmniTree(label='b', parents=[a])
>>> c = OmniTree(label='c', parents=[b])
>>> d = OmniTree(label='d', parents=[b])
>>> e = OmniTree(label='e', parents=[c, d])
>>> a.find_branches(labels=True)
['a', ['b', ['c', ['e']], ['d', ['e']]]]
>>> a.find_branches(labels=True, unique=True)
[['a', 'b', 'c', 'e'], ['a', 'b', 'd', 'e']]
"""
branches = []
# Assign proper item, pointer or label, to return
if labels is True:
identifier = [self.label]
else:
identifier = [self]
if self._children == []: # Base Case: current node is a leaf/end node
return identifier
else: # Recursive Case: all other nodes
for child in self._children:
if unique is True:
for branch in child.find_branches(labels=labels,
unique=True):
# I don't know why this 'if' is necessary, but it is
if type(branch) is not list:
branch = list(branch)
branches.append(identifier + branch)
else:
branches.append(child.find_branches(labels=labels))
# Proper construction of list depends on 'unique'
if unique is True:
return branches
else:
return identifier + branches
```