""" This code adapted from the library "pptree," Copyright (c) 2017 Clément Michard and released under the MIT license: https://github.com/clemtoy/pptree """ import io def render_tree(current_node, nameattr='name', left_child='left', right_child='right', indent='', last='updown', buffer=None): """Print a tree-like structure, `current_node`. This is a mostly-direct-copy of the print_tree() function from the ppbtree module of the pptree library, but instead of printing to standard out, we write to a StringIO buffer, then use that buffer to accumulate written lines during recursive calls to render_tree(). """ if buffer is None: buffer = io.StringIO() if hasattr(current_node, nameattr): name = lambda node: getattr(node, nameattr) else: name = lambda node: str(node) up = getattr(current_node, left_child, None) down = getattr(current_node, right_child, None) if up is not None: next_last = 'up' next_indent = '{0}{1}{2}'.format(indent, ' ' if 'up' in last else '|', ' ' * len(str(name(current_node)))) render_tree(up, nameattr, left_child, right_child, next_indent, next_last, buffer) if last == 'up': start_shape = '┌' elif last == 'down': start_shape = '└' elif last == 'updown': start_shape = ' ' else: start_shape = '├' if up is not None and down is not None: end_shape = '┤' elif up: end_shape = '┘' elif down: end_shape = '┐' else: end_shape = '' print('{0}{1}{2}{3}'.format(indent, start_shape, name(current_node), end_shape), file=buffer) if down is not None: next_last = 'down' next_indent = '{0}{1}{2}'.format(indent, ' ' if 'down' in last else '|', ' ' * len(str(name(current_node)))) render_tree(down, nameattr, left_child, right_child, next_indent, next_last, buffer) return f"\n{buffer.getvalue()}"