Example #1
0
        def run():
            # Print nodes
            if Inspector(self.node).get_childnodes():
                yield 'Child nodes:'

                def column_iterator():
                    for c in Inspector(self.node).get_childnodes():
                        name = Inspector(c).get_name()
                        yield termcolor.colored(
                            name,
                            type_of_node(c).color), len(name)

                for line in console.in_columns(column_iterator()):
                    yield line

            # Print actions
            if Inspector(self.node).get_actions():
                yield 'Actions:'

                def column_iterator():
                    for a in Inspector(self.node).get_actions():
                        yield termcolor.colored(a.name,
                                                type_of_action(a).color), len(
                                                    a.name)

                for line in console.in_columns(column_iterator()):
                    yield line
    def test_get_name(self):
        s = self.s
        self.assertEqual(Inspector(s.A).get_name(), 'A')
        self.assertEqual(Inspector(s.B.C).get_name(), 'C')

        self.assertEqual(Inspector(s.A).get_full_name(), 'Root.A')
        self.assertEqual(Inspector(s.B.C).get_full_name(), 'Root.B.C')
Example #3
0
    def complete_subhandlers(self, part):
        parent = self.node.parent
        include_private = part.startswith('_')
        cls = self.__class__

        # No autocompletion anymore after an action has been typed.
        if self.attr_name:
            return

        # Current node
        if '.'.startswith(part):
            yield '.', self

        # Previous location
        if '-'.startswith(part) and self.shell.state.can_cdback:
            yield '-', cls(self.shell, self.shell.state.previous_node)

        # Root node
        if parent and '/'.startswith(part):
            root = Inspector(parent).get_root()
            yield '/', cls(self.shell, root)

        # Parent node
        if parent and '..'.startswith(part):
            yield ('..', cls(self.shell, parent))

        # TODO: ~ -->> Home

        # Isolation
        for i, n in Inspector(self.node).iter_isolations(IsolationIdentifierType.HOSTS_SLUG):
            if i:
                # Prefix all isolations with colons.
                name = ':%s' % ':'.join(i)
                if name.startswith(part):
                    yield name, cls(self.shell, n)

        # Childnodes:
        # Note: when an underscore has been typed, include private too.
        for c in Inspector(self.node).get_childnodes(include_private=include_private):
            name = Inspector(c).get_name()
            if name.startswith(part):
                yield name, cls(self.shell, c)

        # Actions
        if AUTOCOMPLETE_TYPE.ACTION in self.autocomplete_types:
            for action in Inspector(self.node).get_actions(include_private=include_private):
                if action.name.startswith(part):
                    yield action.name, cls(self.shell, self.node, action.name)

        # Queries
        if AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE in self.autocomplete_types:
            for action in Inspector(self.node).get_queries(include_private=include_private):
                if action.name.startswith(part):
                    yield action.name, cls(self.shell, self.node, action.name)

        # Properties
        if AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE in self.autocomplete_types:
            for action in Inspector(self.node).get_properties(include_private=include_private):
                if action.name.startswith(part):
                    yield action.name, cls(self.shell, self.node, action.name)
 def test_get_path(self):
     s = self.s
     self.assertEqual(repr(Inspector(s.A).get_path()), "('Root', 'A')")
     self.assertEqual(repr(Inspector(s.B.C).get_path()), "('Root', 'B', 'C')")
     self.assertEqual(repr(Inspector(s.B.C).get_path(path_type=PathType.NODE_AND_NAME)),
                     "((<Node Root>, 'Root'), (<Node Root.B>, 'B'), (<Node Root.B.C>, 'C'))")
     self.assertEqual(repr(Inspector(s.B.C).get_path(path_type=PathType.NODE_ONLY)),
                     "(<Node Root>, <Node Root.B>, <Node Root.B.C>)")
 def setUp(self):
     class Root(Node):
         attr = 'value'
         query = Q.attr + Q.attr
         def my_action(self): pass
     self.env = Env(Root())
     self.env_insp = Inspector(self.env)
     self.node_insp = Inspector(Root())
Example #6
0
    def __call__(self):
        result = []

        for node, name in Inspector(self.node).get_path(
                PathType.NODE_AND_NAME):
            color = Inspector(node).get_group().color
            result.append(termcolor.colored(name, color))

        sys.stdout.write(termcolor.colored('/', 'cyan'))
        sys.stdout.write(termcolor.colored('.', 'cyan').join(result) + '\n')
        sys.stdout.flush()
    def setUp(self):
        class Root(Node):
            def a(self):
                pass

            @suppress_action_result
            def b(self):
                pass

        self.env = Env(Root())
        self.env_insp = Inspector(self.env)
        self.node_insp = Inspector(Root())
Example #8
0
                def item_iterator():
                    for n in nodes:
                        name = Inspector(n).get_name()

                        if n.parent == self.node:
                            text = termcolor.colored(name,
                                                     type_of_node(n).color)
                            length = len(name)
                        else:
                            full_name = Inspector(n).get_full_name()
                            text = termcolor.colored(
                                '%s -> %s' % (name, full_name),
                                type_of_node(n).color)
                            length = len('%s -> %s' % (name, full_name))
                        yield text, length
    def setUp(self):
        class Root(Node):
            @production
            class A(Node):
                pass
            @staging
            class B(Node):
                class C(Node):
                    def __call__(self):
                        # __call__ is the default action
                        pass
            def a(self): pass
            def b(self): pass
            def c(self): pass
            c.__name__ = 'another-name' # Even if we override this name, Action.name should remain 'c'

            @property
            def p1(self):
                return 'p1'

            @property
            def p2(self):
                return 'p1'

            query1 = Q.something
            query2 = Q.something_else

        self.s = Root()
        self.insp = Inspector(self.s)
Example #10
0
    def prompt(self):
        # Returns a list of (text,color) tuples for the prompt.
        result = []
        for node in Inspector(
                self._node).get_path(path_type=PathType.NODE_ONLY):
            if result:
                result.append(('.', None))

            name = Inspector(node).get_name()
            ii = Inspector(node).get_isolation_identifier()
            color = Inspector(node).get_group().color

            result.append((name, color))
            if ii:
                result.append(('[%s]' % ii, color))
        return result
    def test_filter_on_group(self):
        insp = self.insp
        # Following are production nodes B, B.C, B.D
        self.assertEqual(len(list(insp.walk().filter(filters.InGroup(Production)))), 3)

        for node in insp.walk().filter(filters.InGroup(Production)):
            self.assertEqual(Inspector(node).get_group(), Production)
Example #12
0
    def _inspect_query_attribute(self):
        console = Console(self.shell.pty)
        query = Inspector(self.node).get_query(self.attr_name).query

        def run():
            yield termcolor.colored('  Node:       ', 'cyan') + \
                  termcolor.colored(Inspector(self.node).get_full_name(), 'yellow')
            yield termcolor.colored('  Filename:   ', 'cyan') + \
                  termcolor.colored(query._filename, 'yellow')
            yield termcolor.colored('  Line:       ', 'cyan') + \
                  termcolor.colored(query._line, 'yellow')
            yield termcolor.colored('  Expression: ', 'cyan') + \
                  termcolor.colored(repr(query.query), 'yellow')
            yield ''

            # Execute query in sandboxed environment.
            yield 'Trace query:'
            try:
                insp = Inspector(self._get_env())
                result = insp.trace_query(self.attr_name)
            except Exception as e:
                yield 'Failed to execute query: %r' % e
                return

            # Print query and all subqueries with their results.
            for subquery in result.walk_through_subqueries():
                yield termcolor.colored(repr(subquery[0]), 'cyan')
                yield '    %s' % subquery[1]

        console.lesspipe(run())
Example #13
0
 def cd(self, cd_path):
     for p in cd_path:
         try:
             self.state.cd(Inspector(self.state._node).get_childnode(p))
         except AttributeError:
             print 'Unknown path given.'
             return
Example #14
0
        def _list_nested_nodes(node, prefix):
            for a in Inspector(node).get_actions():
                yield '%s %s' % (prefix,
                                 termcolor.colored(
                                     a.name,
                                     Inspector(a.node).get_group().color))

            for c in Inspector(node).get_childnodes():
                # Check the parent, to avoid loops.
                if c.parent == node:
                    name = Inspector(c).get_name()
                    for i in _list_nested_nodes(
                            c, '%s %s' %
                        (prefix,
                         termcolor.colored(name,
                                           Inspector(c).get_group().color))):
                        yield i
Example #15
0
        def run():
            yield termcolor.colored('  Node:       ', 'cyan') + \
                  termcolor.colored(Inspector(self.node).get_full_name(), 'yellow')
            yield termcolor.colored('  Filename:   ', 'cyan') + \
                  termcolor.colored(query._filename, 'yellow')
            yield termcolor.colored('  Line:       ', 'cyan') + \
                  termcolor.colored(query._line, 'yellow')
            yield termcolor.colored('  Expression: ', 'cyan') + \
                  termcolor.colored(repr(query.query), 'yellow')
            yield ''

            # Execute query in sandboxed environment.
            yield 'Trace query:'
            try:
                insp = Inspector(self._get_env())
                result = insp.trace_query(self.attr_name)
            except Exception, e:
                yield 'Failed to execute query: %r' % e
                return
Example #16
0
    def get_type(self):
        """
        Return the ``AUTOCOMPLETE_TYPE`` for this node.
        """
        insp = Inspector(self.node)
        atypes = self.autocomplete_types

        if AUTOCOMPLETE_TYPE.NODE in atypes and not self.attr_name:
            return AUTOCOMPLETE_TYPE.NODE

        if AUTOCOMPLETE_TYPE.ACTION in atypes and not self.attr_name and insp.is_callable():
            return AUTOCOMPLETE_TYPE.ACTION

        if AUTOCOMPLETE_TYPE.ACTION in atypes and insp.has_action(self.attr_name):
            return AUTOCOMPLETE_TYPE.ACTION

        if AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE in atypes and insp.has_query(self.attr_name):
            return AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE

        if AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE in atypes and insp.has_property(self.attr_name):
            return AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE
class QueryInspectionTest(unittest.TestCase):
    def setUp(self):
        class Root(Node):
            attr = 'value'
            query = Q.attr + Q.attr
            def my_action(self): pass
        self.env = Env(Root())
        self.env_insp = Inspector(self.env)
        self.node_insp = Inspector(Root())

    def test_has_query(self):
        self.assertEqual(self.env_insp.has_query('query'), True)
        self.assertEqual(self.env_insp.has_query('not_a_query'), False)

        self.assertEqual(self.node_insp.has_query('query'), True)
        self.assertEqual(self.node_insp.has_query('not_a_query'), False)

    def test_get_query(self):
        self.assertIsInstance(self.node_insp.get_query('query'), Action)
        self.assertRaises(AttributeError, self.node_insp.get_query, 'not_a_query')

    def test_trace_query(self):
        # trace_query is private because it's for internal use. (In the
        # shell.)
        result = self.env_insp.trace_query('query')
        self.assertIsInstance(result, QueryResult)
        self.assertEqual(result.result, 'valuevalue')
Example #18
0
    def get_type(self):
        """
        Return the ``AUTOCOMPLETE_TYPE`` for this node.
        """
        insp = Inspector(self.node)
        atypes = self.autocomplete_types

        if AUTOCOMPLETE_TYPE.NODE in atypes and not self.attr_name:
            return AUTOCOMPLETE_TYPE.NODE

        if AUTOCOMPLETE_TYPE.ACTION in atypes and not self.attr_name and insp.is_callable(
        ):
            return AUTOCOMPLETE_TYPE.ACTION

        if AUTOCOMPLETE_TYPE.ACTION in atypes and insp.has_action(
                self.attr_name):
            return AUTOCOMPLETE_TYPE.ACTION

        if AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE in atypes and insp.has_query(
                self.attr_name):
            return AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE

        if AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE in atypes and insp.has_property(
                self.attr_name):
            return AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE
    def test_get_childnodes_order(self):
        """
        The inspector should return the childnodes in the order, as they were
        nested inside the node definition.
        """
        # Automatic
        class Root(Node):
            class A(Node): pass
            class B(Node): pass

        self.assertEqual(repr(Inspector(Root()).get_childnodes()), '[<Node Root.A>, <Node Root.B>]')
        self.assertEqual(repr(Inspector(Env(Root())).get_childnodes()), '[Env(Root.A), Env(Root.B)]')

        # Manually set creation order
        class Root(Node):
            class A(Node): pass
            class B(Node): pass
            A._node_creation_counter = 44
            B._node_creation_counter = 45

        self.assertEqual(repr(Inspector(Root()).get_childnodes()), '[<Node Root.A>, <Node Root.B>]')
        self.assertEqual(repr(Inspector(Env(Root())).get_childnodes()), '[Env(Root.A), Env(Root.B)]')

        # Manually revert the creation order
        class Root(Node):
            class A(Node): pass
            class B(Node): pass
            A._node_creation_counter = 45
            B._node_creation_counter = 44

        self.assertEqual(repr(Inspector(Root()).get_childnodes()), '[<Node Root.B>, <Node Root.A>]')
        self.assertEqual(repr(Inspector(Env(Root())).get_childnodes()), '[Env(Root.B), Env(Root.A)]')
class SuppressResultTest(unittest.TestCase):
    def setUp(self):
        class Root(Node):
            def a(self):
                pass

            @suppress_action_result
            def b(self):
                pass

        self.env = Env(Root())
        self.env_insp = Inspector(self.env)
        self.node_insp = Inspector(Root())

    def test_suppress_decorator(self):
        # On an node object
        self.assertEqual(self.node_insp.suppress_result_for_action('a'), False)
        self.assertEqual(self.node_insp.suppress_result_for_action('b'), True)

        # On an env object
        self.assertEqual(self.env_insp.suppress_result_for_action('a'), False)
        self.assertEqual(self.env_insp.suppress_result_for_action('b'), True)
Example #21
0
    def _inspect_action(self):
        console = Console(self.shell.pty)
        action = Inspector(self.node).get_action(self.attr_name)

        def run():
            yield termcolor.colored('  Action name:   ', 'cyan') + \
                  termcolor.colored(self.attr_name, 'yellow')
            yield termcolor.colored('  __repr__:      ', 'cyan') + \
                  termcolor.colored(repr(action._func), 'yellow')
            yield termcolor.colored('  Node:          ', 'cyan') + \
                  termcolor.colored(repr(self.node), 'yellow')

        console.lesspipe(run())
    def test_inspection_env_node(self):
        A = self.A
        def test(insp, type):
            self.assertEqual(len(list(insp.iter_isolations())), 9) # 3x3

            # Inspection on env should yield Env objects, Node should yield
            # node objects.
            for i, node in insp.iter_isolations():
                self.assertIsInstance(node, type)

            # Test get_isolation
            node = insp.get_isolation((0, 0))
            self.assertIsInstance(node, type)
            self.assertEqual(repr(node),
                '<Node A.B[0].C.D[0]>' if type == Node else 'Env(A.B[0].C.D[0])')

            node = insp.get_isolation((2, 2))
            self.assertIsInstance(node, type)
            self.assertEqual(repr(node),
                '<Node A.B[2].C.D[2]>' if type == Node else 'Env(A.B[2].C.D[2])')

        test(Inspector(A().B.C.D), Node)
        test(Inspector(Env(A()).B.C.D), Env)
Example #23
0
        def run():
            yield termcolor.colored('  Node:       ', 'cyan') + \
                  termcolor.colored(Inspector(self.node).get_full_name(), 'yellow')
            yield termcolor.colored('  Filename:   ', 'cyan') + \
                  termcolor.colored(query._filename, 'yellow')
            yield termcolor.colored('  Line:       ', 'cyan') + \
                  termcolor.colored(query._line, 'yellow')
            yield termcolor.colored('  Expression: ', 'cyan') + \
                  termcolor.colored(repr(query.query), 'yellow')
            yield ''

            # Execute query in sandboxed environment.
            yield 'Trace query:'
            try:
                insp = Inspector(self._get_env())
                result = insp.trace_query(self.attr_name)
            except Exception as e:
                yield 'Failed to execute query: %r' % e
                return

            # Print query and all subqueries with their results.
            for subquery in result.walk_through_subqueries():
                yield termcolor.colored(repr(subquery[0]), 'cyan')
                yield '    %s' % subquery[1]
Example #24
0
    def select_node_isolation(self, node):
        """
        Ask for a host, from a list of hosts.
        """
        from deployer.inspection import Inspector
        from deployer.node import IsolationIdentifierType

        # List isolations first. (This is a list of index/node tuples.)
        options = [
                (' '.join([ '%s (%s)' % (h.slug, h.address) for h in hosts ]), node) for hosts, node in
                Inspector(node).iter_isolations(identifier_type=IsolationIdentifierType.HOST_TUPLES)
                ]

        if len(options) > 1:
            return self.choice('Choose a host', options, allow_random=True)
        else:
            return options[0][1]
Example #25
0
    def __call__(self):
        # Execute
        logger_interface = self.shell.logger_interface

        try:
            # Create env
            env = Env(self.node,
                      self.shell.pty,
                      logger_interface,
                      is_sandbox=self.sandbox)

            # Call action
            if self.attr_name is not None:
                result = getattr(env, self.attr_name)(*self.args)
                suppress_result = Inspector(
                    self.node).suppress_result_for_action(self.attr_name)
            else:
                result = env(*self.args)
                suppress_result = False

            # When the result is a subnode, start a subshell.
            def handle_result(result):
                if isinstance(result, deployer.node.Env):
                    print ''
                    print 'Starting subshell ...'
                    self.shell.state = ShellState(
                        result._node, return_state=self.shell.state)

                # Otherwise, print result
                elif result is not None and not suppress_result:
                    print result

            if isinstance(result, list):
                for r in result:
                    handle_result(r)
            else:
                handle_result(result)

        except ActionException as e:
            # Already sent to logger_interface in the Action itself.
            pass

        except Exception as e:
            logger_interface.log_exception(e)
    def setUp(self):
        class Base(Node):
            pass

        self.Base = Base

        # Ensure that we have a correct __repr__ for this class
        self.Base.__module__ = 'inspector_test'
        assert repr(Base) == "<class 'inspector_test.Base'>"

        class A(Node):
            def my_action(self): return 'a'

            @production
            class B(Base):
                def my_action(self): return 'b'
                def my_other_action(self): return 'b2'

                class C(SimpleNode.Array):
                    class Hosts:
                        host = { LocalHost1, LocalHost2, LocalHost3, LocalHost4 }

                    def my_action(self): return 'c'

                    @staging
                    class E(Base):
                        def my_action(self): return 'e'

            @production
            class D(Base):
                def my_action(self): return 'd'
                def my_other_action(self): return 'd2'

            @staging
            class _P(Base):
                # A private node
                def my_action(self): return '_p'

        self.env = Env(A())
        self.insp = Inspector(self.env)
    def setUp(self):
        class Root(Node):
            class A(Node):
                pass
            class B(Node):
                def action(self):
                    return 'action-b'
            def action(self):
                return 'action-root'
            def action2(self):
                return 'action-root2'

            @property
            def p1(self):
                return 'p1'

            @property
            def p2(self):
                return 'p2'

        self.env = Env(Root())
        self.insp = Inspector(self.env)
Example #28
0
    def _inspect_property_attribute(self):
        console = Console(self.shell.pty)
        action = Inspector(self.node).get_property(self.attr_name)

        def run():
            yield termcolor.colored('  Property name:   ', 'cyan') + \
                  termcolor.colored(self.attr_name, 'yellow')
            yield termcolor.colored('  __repr__:      ', 'cyan') + \
                  termcolor.colored(repr(action._func), 'yellow')
            yield termcolor.colored('  Node:          ', 'cyan') + \
                  termcolor.colored(repr(self.node), 'yellow')

            # Value
            try:
                value = getattr(self._get_env(), self.attr_name)

                yield termcolor.colored('  Value:          ', 'cyan') + \
                      termcolor.colored(repr(value), 'yellow')
            except Exception as e:
                yield termcolor.colored('  Value:          ', 'cyan') + \
                      termcolor.colored('Failed to evaluate value...', 'yellow')

        console.lesspipe(run())
Example #29
0
    def handler_type(self):
        if self._root:
            return BuiltinType()
        else:
            node_color = Inspector(self.node).get_group().color

            def get_postfix():
                type_ = self.get_type()
                if type_ == AUTOCOMPLETE_TYPE.ACTION:
                    return '*'

                if type_ == AUTOCOMPLETE_TYPE.QUERY_ATTRIBUTE:
                    return '?'

                if type_ == AUTOCOMPLETE_TYPE.PROPERTY_ATTRIBUTE:
                    return '@'

                return ''

            class Type(HandlerType):
                color = node_color
                postfix = get_postfix()

            return Type()
Example #30
0
        def inspect():
            # Print full name
            yield termcolor.colored('  Node:    ', 'cyan') + \
                  termcolor.colored(Inspector(self.node).get_full_name(), 'yellow')

            # Print mro
            yield termcolor.colored('  Mro:', 'cyan')
            i = 1
            for m in self.node.__class__.__mro__:
                if m.__module__ != 'deployer.node' and m != object:
                    yield termcolor.colored('              %i ' % i, 'cyan') + \
                          termcolor.colored('%s.' % m.__module__, 'red') + \
                          termcolor.colored('%s' % m.__name__, 'yellow')
                    i += 1

            # File names
            yield termcolor.colored('  Files:', 'cyan')
            i = 1
            for m in self.node.__class__.__mro__:
                if m.__module__ != 'deployer.node' and m != object:
                    yield termcolor.colored('              %i ' % i, 'cyan') + \
                          termcolor.colored(getfile(m), 'red')
                    i += 1

            # Print host mappings
            yield termcolor.colored('  Hosts:', 'cyan')

            for role in sorted(self.node.hosts._hosts.keys()):
                items = self.node.hosts._hosts[role]
                yield termcolor.colored('         "%s"' % role, 'yellow')
                i = 1
                for host in sorted(items, key=lambda h: h.slug):
                    yield termcolor.colored('            %3i ' % i, 'cyan') + \
                          termcolor.colored('%-25s (%s)' % (host.slug, getattr(host, 'address', '')), 'red')
                    i += 1

            # Print the first docstring (look to the parents)
            for m in self.node.__class__.__mro__:
                if m.__module__ != 'deployer.node' and m != object and m.__doc__:
                    yield termcolor.colored('  Docstring:\n', 'cyan') + \
                          termcolor.colored(m.__doc__ or '<None>', 'red')
                    break

            # Actions
            yield termcolor.colored('  Actions:', 'cyan')

            def item_iterator():
                for a in Inspector(self.node).get_actions():
                    yield termcolor.colored(a.name, 'red'), len(a.name)

            for line in console.in_columns(item_iterator(), margin_left=13):
                yield line

            # Nodes
            yield termcolor.colored('  Sub nodes:', 'cyan')

            # Group by node group
            grouper = lambda c: Inspector(c).get_group()
            for group, nodes in groupby(
                    sorted(Inspector(self.node).get_childnodes(), key=grouper),
                    grouper):
                yield termcolor.colored('         "%s"' % group.name, 'yellow')

                # Create iterator for all the items in this group
                def item_iterator():
                    for n in nodes:
                        name = Inspector(n).get_name()

                        if n.parent == self.node:
                            text = termcolor.colored(name,
                                                     type_of_node(n).color)
                            length = len(name)
                        else:
                            full_name = Inspector(n).get_full_name()
                            text = termcolor.colored(
                                '%s -> %s' % (name, full_name),
                                type_of_node(n).color)
                            length = len('%s -> %s' % (name, full_name))
                        yield text, length

                # Show in columns
                for line in console.in_columns(item_iterator(),
                                               margin_left=13):
                    yield line
Example #31
0
 def column_iterator():
     for a in Inspector(self.node).get_actions():
         yield termcolor.colored(a.name,
                                 type_of_action(a).color), len(
                                     a.name)
Example #32
0
 def column_iterator():
     for c in Inspector(self.node).get_childnodes():
         name = Inspector(c).get_name()
         yield termcolor.colored(
             name,
             type_of_node(c).color), len(name)
Example #33
0
def type_of_node(node):
    group = Inspector(node).get_group()
    return NodeType(group.color)
Example #34
0
 def item_iterator():
     for a in Inspector(self.node).get_actions():
         yield termcolor.colored(a.name, 'red'), len(a.name)
 def test_walk_from_childnode(self):
     s = self.s
     insp = Inspector(s.B)
     self.assertEqual(len(list(insp.walk())), 2)
     self.assertEqual({ Inspector(i).get_name() for i in insp.walk() }, { 'B', 'C' })