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')
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())
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())
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)
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)
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())
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
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
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
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')
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)
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)
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]
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]
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)
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())
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()
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
def column_iterator(): for a in Inspector(self.node).get_actions(): yield termcolor.colored(a.name, type_of_action(a).color), len( a.name)
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)
def type_of_node(node): group = Inspector(node).get_group() return NodeType(group.color)
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' })