Source code for wbia.guitool.api_tree_node

# -*- coding: utf-8 -*-
# TODO: Rename api_item_model
from __future__ import absolute_import, division, print_function
from wbia.guitool.__PYQT__ import QtCore  # NOQA
from types import GeneratorType
from six.moves import zip, range
import utool
import utool as ut

(print, print_, rrr) = utool.inject2(__name__)


TREE_NODE_BASE = QtCore.QObject
# TREE_NODE_BASE = object
VERBOSE_TREE_NODE = ut.get_argflag(('--verb-qt-tree'))


[docs]class TreeNode(TREE_NODE_BASE): """ Cyth: cdef: long id_, level list child_nodes TreeNode parent_node """ # __slots__ = ('id_', 'parent_node', 'child_nodes', 'level',) def __init__(self, id_, parent_node, level): TREE_NODE_BASE.__init__(self, parent=parent_node) # super(TreeNode, self).__init__(parent_node) # if TREE_NODE_BASE is not object: # if VERBOSE_TREE_NODE: # print('[TreeNode] __init__') # super(TreeNode, self).__init__(parent=parent_node) self.id_ = id_ self.parent_node = parent_node self.child_nodes = [] self.level = level def __del__(self): # print('[guitool] DELETING THE TREE NODE!:') if VERBOSE_TREE_NODE: print('[guitool] DELETING THE TREE NODE!: id_=%r' % self.id_) def __getitem__(self, index): """ <CYTH returns="TreeNode"> cdef long index """ return self.get_child(index)
[docs] def set_children(self, child_nodes): """ <CYTH returns="void"> """ self.child_nodes = child_nodes
[docs] def get_children(self): """ </CYTH returns="list"> """ self.lazy_checks() return self.child_nodes
[docs] def child_index(self, child_node): """ <CYTH returns=long> cdef TreeNode child_node """ self.lazy_checks() return self.child_nodes.index(child_node)
[docs] def get_child(self, index): """ <CYTH returns="TreeNode"> cdef long index """ self.lazy_checks() return self.child_nodes[index]
[docs] def get_parent(self): """ <CYTH returns="TreeNode"> """ try: return self.parent_node except AttributeError as ex: import utool as ut ut.printex(ex, 'Error getting parent', tb=True) # print(ex) # print('[tree_node] dir(self)=') # print(dir(self)) # print('[tree_node] self.__dict__=') # print(utool.repr2(self.__dict__)) raise
[docs] def get_num_children(self): """ <CYTH returns=long> """ self.lazy_checks() return len(self.child_nodes)
[docs] def get_id(self): """ Returns python internal id of this class <CYTH returns="long"> """ return self.id_
[docs] def get_row(self): """ Returns the row_index of this node w.r.t its parent. cdef list sibling_nodes cdef long row """ sibling_nodes = self.parent_node.child_nodes row = sibling_nodes.index(self) return row
[docs] def get_level(self): """ <CYTH returns="long"> """ return self.level
[docs] def find_row_from_id(self, _id): """ given an id (like an wbia rowid) find the row of this item """ children = self.get_children() id_list = [child.get_id() for child in children] row = ut.listfind(id_list, _id) return row
[docs] def lazy_checks(self): # If the child is a generator, then the TreeNode hasn't been created yet # so create it if isinstance(self.child_nodes, GeneratorType): print('[tree_node] lazy evaluation level=%r' % self.level) # print('[tree_node] lazy evaluation level=%r' % self.level) self.child_nodes = list(self.child_nodes)
[docs]def tree_node_string(self, indent='', charids=True, id_dict=None, last=None): """ makes a recrusive string representation of a treee HACK:if charids is 2 uses ordinals instead of characters if charirsd is True triesto use Numbers otherwise uses nondetermensitic python ids """ if last is None: if charids == 2: last = [0] else: last = ['A'] if id_dict is None: id_dict = {} id_ = self.get_id() level = self.get_level() id_self = id(self) id_parent = id(self.get_parent()) if charids == 2: if id_parent not in id_dict: id_dict[id_parent] = last[0] last[0] = last[0] + 1 if id_self not in id_dict: id_dict[id_self] = last[0] last[0] = last[0] + 1 id_self = id_dict[id_self] id_parent = id_dict[id_parent] elif charids is True: # if ord(last[0]) < 255: # last[0] = [0] if id_parent not in id_dict: id_dict[id_parent] = last[0] last[0] = chr(ord(last[0]) + 1) if id_self not in id_dict: id_dict[id_self] = last[0] last[0] = chr(ord(last[0]) + 1) id_self = id_dict[id_self] id_parent = id_dict[id_parent] tup = (id_, level, str(id_self), str(id_parent)) self_str = indent + 'TreeNode(id_=%r, level=%r, self=%s, parent_node=%s)' % tup child_strs = [ tree_node_string( child, indent=indent + ' ', charids=charids, id_dict=id_dict, last=last ) for child in self.get_children() ] str_ = '\n'.join([self_str] + child_strs) return str_
def _populate_tree_iterative(root_node, num_levels, ider_list): """ Iteratively builds the tree structure. I dont quite trust this yet #@cython.boundscheck(False) #@cython.wraparound(False) Cyth:: @returns(TreeNode) <CYTH returns="TreeNode"> cdef: TreeNode parent_node size_t level size_t ix size_t sx long id_ list root_ids list parent_node_list list ids_list list id_list list next_ids list node_list list new_node_lists list new_ids_lists Args: root_node (?): num_levels (?): ider_list (list): CommandLine: python -m wbia.guitool.api_tree_node --test-_populate_tree_iterative Example: >>> # xdoctest: +REQUIRES(module:wbia) >>> from wbia.guitool.api_tree_node import * # NOQA >>> import utool as ut >>> from wbia.guitool import api_tree_node # NOQA >>> import wbia >>> ibs = wbia.opendb(ut.get_argval('--db', str, default='testdb1')) >>> # build test data >>> ider_list = [ibs.get_valid_nids, ibs.get_name_aids] >>> num_levels = len(ider_list) >>> # execute function >>> root_node = TreeNode(-1, None, -1) >>> api_tree_node._populate_tree_iterative(root_node, num_levels, ider_list) >>> # verify results >>> self = root_node >>> infostr = api_tree_node.tree_node_string(root_node, charids=2) >>> # print(ut.truncate_str(infostr, maxlen=2000)) >>> result = ut.hashstr(infostr) >>> print(result) """ root_ids = ider_list[0]() parent_node_list = [root_node] ids_list = [root_ids] if VERBOSE_TREE_NODE: print('_populate_tree_iterative') print('root_ids = %r' % (root_ids,)) print('num_levels = %r' % (num_levels,)) for level in range(num_levels): # print('------------ level=%r -----------' % (level,)) # print(utool.repr2(locals())) new_node_lists = [] new_ids_lists = [] for parent_node, id_list in zip(parent_node_list, ids_list): # pass # assert isinstance(parent_node, TreeNode), '%r\n%s' % (parent_node, # utool.repr2(locals())) node_list = [TreeNode(id_, parent_node, level) for id_ in id_list] if level + 1 < num_levels: child_ider = ider_list[level + 1] next_ids = child_ider(id_list) # [child_ider(id_) for id_ in child_ids] else: next_ids = [] parent_node.set_children(node_list) new_node_lists.extend(node_list) new_ids_lists.extend(next_ids) parent_node_list = new_node_lists ids_list = new_ids_lists def _populate_tree_recursive(parent_node, child_ids, num_levels, ider_list, level): """ Recursively builds the tree structure Cyth:: <CYTH returns="TreeNode"> cdef: size_t ix long id_ list child_nodes TreeNode next_node list next_ids Example: >>> # xdoctest: +REQUIRES(module:wbia) >>> from wbia.guitool.api_tree_node import * # NOQA >>> from wbia.guitool.api_tree_node import * # NOQA >>> import utool as ut >>> from wbia.guitool import api_tree_node # NOQA >>> import wbia >>> ibs = wbia.opendb(ut.get_argval('--db', str, default='testdb1')) >>> # build test data >>> ider_list = [ibs.get_valid_nids, ibs.get_name_aids] >>> num_levels = len(ider_list) >>> root_node = TreeNode(-1, None, -1) >>> if num_levels == 0: >>> root_id_list = [] >>> else: >>> root_id_list = ider_list[0]() >>> root_node = TreeNode(-1, None, -1) >>> level = 0 >>> # execute function >>> api_tree_node._populate_tree_recursive(root_node, root_id_list, num_levels, ider_list, level) >>> # verify results >>> self = root_node >>> infostr = api_tree_node.tree_node_string(root_node, charids=2) >>> # print(ut.truncate_str(infostr, maxlen=2000)) >>> result = ut.hashstr(infostr) >>> print(result) """ if level == num_levels - 1: child_nodes = (TreeNode(id_, parent_node, level) for id_ in child_ids) else: child_ider = ider_list[level + 1] child_nodes = [ _populate_tree_recursive( TreeNode(id_, parent_node, level), child_ider(id_), num_levels, ider_list, level + 1, ) for id_ in child_ids ] parent_node.set_children(child_nodes) return parent_node def _populate_tree_recursive_lazy(parent_node, child_ids, num_levels, ider_list, level): """ Recursively builds the tree structure Cyth:: <CYTH returns="TreeNode"> cdef: size_t ix long id_ list child_nodes TreeNode next_node list next_ids Example: >>> # xdoctest: +REQUIRES(module:wbia) >>> from wbia.guitool.api_tree_node import * # NOQA >>> import utool as ut >>> from wbia.guitool import api_tree_node # NOQA >>> import wbia >>> ibs = wbia.opendb(ut.get_argval('--db', str, default='testdb1')) >>> # build test data >>> ider_list = [ibs.get_valid_nids, ibs.get_name_aids] >>> num_levels = len(ider_list) >>> root_node = TreeNode(-1, None, -1) >>> if num_levels == 0: >>> root_id_list = [] >>> else: >>> root_id_list = ider_list[0]() >>> root_node = TreeNode(-1, None, -1) >>> level = 0 >>> # execute function >>> api_tree_node._populate_tree_recursive_lazy(root_node, root_id_list, num_levels, ider_list, level) >>> # verify results >>> self = root_node >>> infostr = api_tree_node.tree_node_string(root_node, charids=2) >>> # print(ut.truncate_str(infostr, maxlen=2000)) >>> result = ut.hashstr(infostr) >>> print(result) """ if level == num_levels - 1: child_nodes_iter = (TreeNode(id_, parent_node, level) for id_ in child_ids) else: child_ider = ider_list[level + 1] child_nodes_iter = ( _populate_tree_recursive( TreeNode(id_, parent_node, level), child_ider(id_), num_levels, ider_list, level + 1, ) for id_ in child_ids ) # seting children as an iterator triggers lazy loading parent_node.set_children(child_nodes_iter) return parent_node
[docs]def build_internal_structure(model): """ Cyth: <CYTH returns="TreeNode"> """ # from wbia.guitool.api_item_model import * ider_list = model.iders # an ider for each level ider_list = model.get_iders() num_levels = len(ider_list) # USE_RECURSIVE = True USE_RECURSIVE = False if USE_RECURSIVE: # I trust this code more although it is slightly slower if num_levels == 0: root_id_list = [] else: root_id_list = ider_list[0]() root_node = TreeNode(-1, None, -1) level = 0 # _populate_tree_recursive(root_node, root_id_list, num_levels, ider_list, level) _populate_tree_recursive_lazy( root_node, root_id_list, num_levels, ider_list, level ) else: # TODO: Vet this code a bit more. root_node = TreeNode(-1, None, -1) _populate_tree_iterative(root_node, num_levels, ider_list) if VERBOSE_TREE_NODE: print('ider_list = %r' % (ider_list,)) infostr = tree_node_string(root_node, charids=2) print(infostr) # print(ut.repr3(root_node.__dict__)) # assert root_node.__dict__, "root_node.__dict__ is empty" return root_node
[docs]def build_scope_hack_list(root_node, scope_hack_list=[]): scope_hack_list.append(root_node) for child in root_node.get_children(): build_scope_hack_list(child, scope_hack_list)
CYTHONIZED = False if __name__ == '__main__': """ CommandLine: python -m wbia.guitool.api_tree_node python -m wbia.guitool.api_tree_node --allexamples python -m wbia.guitool.api_tree_node --allexamples --noface --nosrc python -m wbia.guitool.api_tree_node --allexamples --noface --nosrc --db GZ_ALL python -m wbia.guitool.api_tree_node --allexamples --noface --nosrc --db PZ_Master0 """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()