def _call_objs(self, contextualized): # Setup pre_body, post_body = Mock(), Mock() t1 = Task(pre_body, contextualized=contextualized) t2 = Task(post_body, contextualized=contextualized) t3 = Task(Mock(), pre=[call(t1, 5, foo='bar')], post=[call(t2, 7, biz='baz')], ) c = Collection(t1=t1, t2=t2, t3=t3) e = Executor(collection=c) e.execute('t3') # Pre-task asserts args, kwargs = pre_body.call_args eq_(kwargs, {'foo': 'bar'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 5) else: eq_(args, (5,)) # Post-task asserts args, kwargs = post_body.call_args eq_(kwargs, {'biz': 'baz'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 7) else: eq_(args, (7,))
def _call_objs(self, contextualized): # Setup pre_body, post_body = Mock(), Mock() t1 = Task(pre_body, contextualized=contextualized) t2 = Task(post_body, contextualized=contextualized) t3 = Task( Mock(), pre=[call(t1, 5, foo='bar')], post=[call(t2, 7, biz='baz')], ) c = Collection(t1=t1, t2=t2, t3=t3) e = Executor(collection=c) e.execute('t3') # Pre-task asserts args, kwargs = pre_body.call_args eq_(kwargs, {'foo': 'bar'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 5) else: eq_(args, (5, )) # Post-task asserts args, kwargs = post_body.call_args eq_(kwargs, {'biz': 'baz'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 7) else: eq_(args, (7, ))
class Executor_(Spec): def setup(self): self.task1 = Task(Mock()) self.task2 = Task(Mock(), pre=['task1']) self.task3 = Task(Mock(), pre=['task1']) coll = Collection() coll.add_task(self.task1, name='task1') coll.add_task(self.task2, name='task2') coll.add_task(self.task3, name='task3') self.executor = Executor(coll) self.coll = coll def base_case(self): self.executor.execute('task1') assert self.task1.body.called def kwargs(self): k = {'foo': 'bar'} self.executor.execute(name='task1', kwargs=k) self.task1.body.assert_called_once_with(**k) def pre_tasks(self): self.executor.execute(name='task2') eq_(self.task1.body.call_count, 1) def enabled_deduping(self): self.executor.execute(name='task2') self.executor.execute(name='task3') eq_(self.task1.body.call_count, 1) def disabled_deduping(self): self.executor.execute(name='task2', dedupe=False) self.executor.execute(name='task3', dedupe=False) eq_(self.task1.body.call_count, 2)
def default_tasks_called_when_no_tasks_specified(self): # NOTE: when no tasks AND no default, Program will print global # help. We just won't do anything at all, which is fine for now. task = Task(Mock('default-task')) coll = Collection() coll.add_task(task, name='mytask', default=True) executor = Executor(collection=coll) executor.execute() task.body.assert_called_with()
def calls_default_to_empty_args_always(self): pre_body, post_body = Mock(), Mock() t1 = Task(pre_body) t2 = Task(post_body) t3 = Task(Mock(), pre=[t1], post=[t2]) e = Executor(collection=Collection(t1=t1, t2=t2, t3=t3)) e.execute(('t3', {'something': 'meh'})) for body in (pre_body, post_body): eq_(body.call_args, tuple())
def deduping_treats_different_calls_to_same_task_differently(self): body = Mock() t1 = Task(body) pre = [call(t1, 5), call(t1, 7), call(t1, 5)] t2 = Task(Mock(), pre=pre) c = Collection(t1=t1, t2=t2) e = Executor(collection=c) e.execute('t2') # Does not call the second t1(5) body.assert_has_calls([mock_call(5), mock_call(7)])
def execute_cleanup_tasks(ctx, cleanup_tasks, dry_run=False): """Execute several cleanup tasks as part of the cleanup. :param ctx: Context object for the tasks. :param cleanup_tasks: Collection of cleanup tasks (as Collection). :param dry_run: Indicates dry-run mode (bool) """ executor = Executor(cleanup_tasks, ctx.config) for cleanup_task in cleanup_tasks.tasks: print("CLEANUP TASK: %s" % cleanup_task) executor.execute((cleanup_task, dict(dry_run=dry_run)))
def execute_cleanup_tasks(ctx, cleanup_tasks, dry_run=False): """Execute several cleanup tasks as part of the cleanup. REQUIRES: ``clean(ctx, dry_run=False)`` signature in cleanup tasks. :param ctx: Context object for the tasks. :param cleanup_tasks: Collection of cleanup tasks (as Collection). :param dry_run: Indicates dry-run mode (bool) """ executor = Executor(cleanup_tasks, ctx.config) for cleanup_task in cleanup_tasks.tasks: print("CLEANUP TASK: %s" % cleanup_task) executor.execute((cleanup_task, dict(dry_run=dry_run)))
def hands_task_specific_configuration_to_context(self): @ctask def mytask(ctx): eq_(ctx['my.config.key'], 'value') @ctask def othertask(ctx): eq_(ctx['my.config.key'], 'othervalue') inner1 = Collection('inner1', mytask) inner1.configure({'my.config.key': 'value'}) inner2 = Collection('inner2', othertask) inner2.configure({'my.config.key': 'othervalue'}) c = Collection(inner1, inner2) e = Executor(collection=c, context=Context()) e.execute('inner1.mytask', 'inner2.othertask')
def execute_cleanup_tasks(ctx, cleanup_tasks, dry_run=False): """Execute several cleanup tasks as part of the cleanup. REQUIRES: ``clean(ctx, dry_run=False)`` signature in cleanup tasks. :param ctx: Context object for the tasks. :param cleanup_tasks: Collection of cleanup tasks (as Collection). :param dry_run: Indicates dry-run mode (bool) """ # pylint: disable=redefined-outer-name executor = Executor(cleanup_tasks, ctx.config) for cleanup_task in cleanup_tasks.tasks: print("CLEANUP TASK: %s" % cleanup_task) executor.execute((cleanup_task, dict(dry_run=dry_run)))
def hands_task_specific_configuration_to_context(self): @ctask def mytask(ctx): eq_(ctx.my_key, 'value') @ctask def othertask(ctx): eq_(ctx.my_key, 'othervalue') inner1 = Collection('inner1', mytask) inner1.configure({'my_key': 'value'}) inner2 = Collection('inner2', othertask) inner2.configure({'my_key': 'othervalue'}) c = Collection(inner1, inner2) e = Executor(collection=c) e.execute('inner1.mytask', 'inner2.othertask')
def hands_collection_configuration_to_context(self): @ctask def mytask(ctx): eq_(ctx['my.config.key'], 'value') c = Collection(mytask) c.configure({'my.config.key': 'value'}) Executor(collection=c, context=Context()).execute('mytask')
def invoke_execute(context, command_name, **kwargs): """ 执行Invoke Task的帮助函数 """ results = Executor(namespace, config=context.config).execute((command_name, kwargs)) target_task = context.root_namespace[command_name] return results[target_task]
def invoke_execute(context, command_name, **kwargs): """ Helper function to make invoke-tasks execution easier. """ results = Executor(namespace, config=context.config).execute((command_name, kwargs)) target_task = context.root_namespace[command_name] return results[target_task]
def run(self): """Override Process method""" self.configure_logging() from tasks import ns rc = 1 try: with self._std_streams as (out, err): self._task_kwargs.update({'stdout': out, 'stderr': err}) _result = Executor(ns).execute( (self._task_name, self._task_kwargs)) # result: {<Task 'task_to_build_doc'>: 0} rc = list(_result.values())[0] except Exception as e: self._root_logger.error('Task %s failed with traceback:\n' % self._task_name + traceback.format_exc()) finally: exit(0) if rc is None else exit(rc)
def setup(self): self.task1 = Task(Mock(return_value=7)) self.task2 = Task(Mock(return_value=10), pre=['task1']) self.task3 = Task(Mock(), pre=['task1']) coll = Collection() coll.add_task(self.task1, name='task1') coll.add_task(self.task2, name='task2') coll.add_task(self.task3, name='task3') self.executor = Executor(collection=coll, context=Context())
def unit_test(ctx, version="3", setup=False): # pylint: disable=redefined-outer-name """ Run unit tests for the desired python version """ if setup: Executor(ns).execute(("setup", { "version": version, "skip_lock": True })) ctx.run( "pipenv run pytest --cov-report term-missing --cov=pycodeflow tests/")
def setup(self): self.task1 = Task(Mock()) self.task2 = Task(Mock(), pre=['task1']) self.task3 = Task(Mock(), pre=['task1']) coll = Collection() coll.add_task(self.task1, name='task1') coll.add_task(self.task2, name='task2') coll.add_task(self.task3, name='task3') self.executor = Executor(coll) self.coll = coll
def subcollection_config_works_with_default_tasks(self): @ctask(default=True) def mytask(ctx): eq_(ctx['my.config.key'], 'value') # Sets up a task "known as" sub.mytask which may be called as just # 'sub' due to being default. sub = Collection('sub', mytask=mytask) sub.configure({'my.config.key': 'value'}) main = Collection(sub=sub) # Execute via collection default 'task' name. Executor(collection=main, context=Context()).execute('sub')
def execute_cleanup_tasks(ctx, cleanup_tasks): """Execute several cleanup tasks as part of the cleanup. :param ctx: Context object for the tasks. :param cleanup_tasks: Collection of cleanup tasks (as Collection). """ # pylint: disable=redefined-outer-name executor = Executor(cleanup_tasks, ctx.config) failure_count = 0 for cleanup_task in cleanup_tasks.tasks: try: print("CLEANUP TASK: %s" % cleanup_task) executor.execute(cleanup_task) except (Exit, Failure, UnexpectedExit) as e: print(e) print("FAILURE in CLEANUP TASK: %s (GRACEFULLY-IGNORED)" % cleanup_task) failure_count += 1 if failure_count: print("CLEANUP TASKS: %d failure(s) occured" % failure_count)
def setup(self): s = super(Executor_, self) s.setup() self.task1 = Task(Mock(return_value=7)) self.task2 = Task(Mock(return_value=10), pre=[self.task1]) self.task3 = Task(Mock(), pre=[self.task1]) self.task4 = Task(Mock(return_value=15), post=[self.task1]) coll = Collection() coll.add_task(self.task1, name='task1') coll.add_task(self.task2, name='task2') coll.add_task(self.task3, name='task3') coll.add_task(self.task4, name='task4') self.executor = Executor(collection=coll)
def execute_cleanup_tasks(ctx, cleanup_tasks, dry_run=False): """Execute several cleanup tasks as part of the cleanup. REQUIRES: ``clean(ctx, dry_run=False)`` signature in cleanup tasks. :param ctx: Context object for the tasks. :param cleanup_tasks: Collection of cleanup tasks (as Collection). :param dry_run: Indicates dry-run mode (bool) """ # pylint: disable=redefined-outer-name executor = Executor(cleanup_tasks, ctx.config) failure_count = 0 for cleanup_task in cleanup_tasks.tasks: try: print("CLEANUP TASK: %s" % cleanup_task) executor.execute((cleanup_task, dict(dry_run=dry_run))) except (Exit, Failure, UnexpectedExit) as e: print("FAILURE in CLEANUP TASK: %s (GRACEFULLY-IGNORED)" % cleanup_task) failure_count += 1 if failure_count: print("CLEANUP TASKS: %d failure(s) occured" % failure_count)
c.run(f"git stash push -q --keep-index") @task def stage_changes(c): """ Stage the newly changed files only. Only works in a pre-commit context. """ c.run(f"git add -u") # Until invoke has proper support for prgramatic accsess # see https://github.com/pyinvoke/invoke/issues/170 for details namespace = Collection(stash_changes, stage_changes, format, check, test) namespace.configure({"root_namespace": namespace}) executor = Executor(namespace) try: executor.execute("stash_changes") # will be deleted in post-commit on success executor.execute("format") executor.execute("check") executor.execute("test") executor.execute("stage_changes") except UnexpectedExit: print("\n\n[ERROR]] Pre-commit hook failed, commit aborted!") print("[ERROR]] Working directory contains files potentially changed by pre-commit hook") print("[ERROR]] Unaltered changes can be found in latest stash: 'git stash list'") print("[ERROR]] Cleanup of he stashes may be needed after failure") exit(1)
def uses_blank_config_by_default(self): e = Executor(collection=Collection()) assert isinstance(e.config, Config)
def allows_collection_and_config(self): coll = Collection() conf = Config() e = Executor(collection=coll, config=conf) assert e.collection is coll assert e.config is conf
def needs_collection_and_context(self): coll = Collection() cont = Context() e = Executor(collection=coll, context=cont) assert e.collection is coll assert e.context is cont