diff --git a/bonobo/execution/graph.py b/bonobo/execution/graph.py index deaa150..0c5bc36 100644 --- a/bonobo/execution/graph.py +++ b/bonobo/execution/graph.py @@ -77,7 +77,7 @@ class GraphExecutionContext: def start(self, starter=None): self.register_plugins() self.dispatch(events.START) - self.tick() + self.tick(pause=False) for node in self.nodes: if starter is None: node.start() @@ -85,9 +85,10 @@ class GraphExecutionContext: starter(node) self.dispatch(events.STARTED) - def tick(self): + def tick(self, pause=True): self.dispatch(events.TICK) - sleep(self.TICK_PERIOD) + if pause: + sleep(self.TICK_PERIOD) def kill(self): self.dispatch(events.KILL) @@ -102,7 +103,7 @@ class GraphExecutionContext: node_context.stop() else: stopper(node_context) - self.tick() + self.tick(pause=False) self.dispatch(events.STOPPED) self.unregister_plugins() diff --git a/bonobo/execution/node.py b/bonobo/execution/node.py index 7771812..daa035f 100644 --- a/bonobo/execution/node.py +++ b/bonobo/execution/node.py @@ -42,6 +42,8 @@ class NodeExecutionContext(WithStatistics, LoopingExecutionContext): def get_flags_as_string(self): if self.killed: return '[killed]' + if self.stopped: + return '[done]' return '' def write(self, *messages): diff --git a/bonobo/plugins/console.py b/bonobo/plugins/console.py index 0548d68..dc511b7 100644 --- a/bonobo/plugins/console.py +++ b/bonobo/plugins/console.py @@ -30,7 +30,7 @@ class ConsoleOutputPlugin(Plugin): _stdout = sys.stdout _stderr = sys.stderr - # When the plugin is started, we'll set the real value of this. + # When the plugin is instanciated, we'll set the real value of this. isatty = False # Whether we're on windows, or a real operating system. @@ -50,6 +50,10 @@ class ConsoleOutputPlugin(Plugin): dispatcher.remove_listener(events.START, self.setup) def setup(self, event): + # TODO this wont work if one instance is registered with more than one context. + # Two options: + # - move state to context + # - forbid registering more than once self.prefix = '' self.counter = 0 self._append_cache = '' @@ -88,41 +92,22 @@ class ConsoleOutputPlugin(Plugin): for i in context.graph.topologically_sorted_indexes: node = context[i] name_suffix = '({})'.format(i) if settings.DEBUG.get() else '' - if node.alive: - _line = ''.join( - ( - ' ', - alive_color, - '+', - Style.RESET_ALL, - ' ', - node.name, - name_suffix, - ' ', - node.get_statistics_as_string(), - ' ', - node.get_flags_as_string(), - Style.RESET_ALL, - ' ', - ) - ) - else: - _line = ''.join( - ( - ' ', - dead_color, - '-', - ' ', - node.name, - name_suffix, - ' ', - node.get_statistics_as_string(), - ' ', - node.get_flags_as_string(), - Style.RESET_ALL, - ' ', - ) + + liveliness_color = alive_color if node.alive else dead_color + liveliness_prefix = ' {}{}{} '.format(liveliness_color, node.status, Style.RESET_ALL) + _line = ''.join( + ( + liveliness_prefix, + node.name, + name_suffix, + ' ', + node.get_statistics_as_string(), + ' ', + node.get_flags_as_string(), + Style.RESET_ALL, + ' ', ) + ) print(prefix + _line + CLEAR_EOL, file=self._stderr) if append: @@ -185,4 +170,4 @@ class IOBuffer(): def memory_usage(): import os, psutil process = psutil.Process(os.getpid()) - return process.memory_info()[0] / float(2**20) + return process.memory_info()[0] / float(2 ** 20) diff --git a/tests/plugins/test_console.py b/tests/plugins/test_console.py new file mode 100644 index 0000000..4a34f7a --- /dev/null +++ b/tests/plugins/test_console.py @@ -0,0 +1,36 @@ +from unittest.mock import MagicMock + +import bonobo +from bonobo.execution import events +from bonobo.execution.graph import GraphExecutionContext +from bonobo.plugins.console import ConsoleOutputPlugin +from whistle import EventDispatcher + + +def test_register_unregister(): + plugin = ConsoleOutputPlugin() + dispatcher = EventDispatcher() + + plugin.register(dispatcher) + assert plugin.setup in dispatcher.get_listeners(events.START) + assert plugin.tick in dispatcher.get_listeners(events.TICK) + assert plugin.teardown in dispatcher.get_listeners(events.STOPPED) + plugin.unregister(dispatcher) + assert plugin.setup not in dispatcher.get_listeners(events.START) + assert plugin.tick not in dispatcher.get_listeners(events.TICK) + assert plugin.teardown not in dispatcher.get_listeners(events.STOPPED) + + +def test_one_pass(): + plugin = ConsoleOutputPlugin() + dispatcher = EventDispatcher() + plugin.register(dispatcher) + + graph = bonobo.Graph() + context = MagicMock(spec=GraphExecutionContext(graph)) + + dispatcher.dispatch(events.START, events.ExecutionEvent(context)) + dispatcher.dispatch(events.TICK, events.ExecutionEvent(context)) + dispatcher.dispatch(events.STOPPED, events.ExecutionEvent(context)) + + plugin.unregister(dispatcher)