def can_clone_into_a_subclass(self): orig = Call(self.task) class MyCall(Call): pass clone = orig.clone(into=MyCall) eq_(clone, orig) ok_(isinstance(clone, MyCall))
def can_clone_into_a_subclass(self): orig = Call(self.task) class MyCall(Call): pass clone = orig.clone(into=MyCall) assert clone == orig assert isinstance(clone, MyCall)
def can_be_given_extra_kwargs_to_clone_with(self): orig = Call(self.task) class MyCall(Call): def __init__(self, *args, **kwargs): self.hooray = kwargs.pop("hooray") super(MyCall, self).__init__(*args, **kwargs) clone = orig.clone(into=MyCall, with_={"hooray": "woo"}) assert clone.hooray == "woo"
def expand_calls(self, calls, parent=None): ret = [] for call in calls: if isinstance(call, Task): call = Call(task=call) call.parent = parent ret.extend(self.expand_calls(call.pre, call)) ret.append(call) ret.extend(self.expand_calls(call.post, call)) return ret
def expand_calls(self, calls, apply_hosts=True): # Generate new call list with per-host variants & Connections inserted ret = [] cli_hosts = [] host_str = self.core[0].args.hosts.value if apply_hosts and host_str: cli_hosts = host_str.split(",") config_hosts = self.config.hosts for call in calls: if isinstance(call, Task): call = Call(task=call) # TODO: expand this to allow multiple types of execution plans, # pending outcome of invoke#461 (which, if flexible enough to # handle intersect of dependencies+parameterization, just becomes # 'honor that new feature of Invoke') # TODO: roles, other non-runtime host parameterizations, etc # Pre-tasks get added only once, not once per host. ret.extend(self.expand_calls(call.pre, apply_hosts=False)) # Determine final desired host list based on CLI and task values # (with CLI, being closer to runtime, winning) and normalize to # Connection-init kwargs. call_hosts = getattr(call, "hosts", None) cxn_params = self.normalize_hosts(cli_hosts or config_hosts or call_hosts) # Main task, per host/connection for init_kwargs in cxn_params: ret.append(self.parameterize(call, init_kwargs)) # Deal with lack of hosts list (acts same as `inv` in that case) # TODO: no tests for this branch? if not cxn_params: ret.append(call) # Post-tasks added once, not once per host. ret.extend(self.expand_calls(call.post, apply_hosts=False)) # Add remainder as anonymous task if self.core.remainder: # TODO: this will need to change once there are more options for # setting host lists besides "-H or 100% within-task" if not cli_hosts: raise NothingToDo( "Was told to run a command, but not given any hosts to run it on!" # noqa ) def anonymous(c): c.run(self.core.remainder) anon = Call(Task(body=anonymous)) # TODO: see above TODOs about non-parameterized setups, roles etc # TODO: will likely need to refactor that logic some more so it can # be used both there and here. for init_kwargs in self.normalize_hosts(cli_hosts): ret.append(self.parameterize(anon, init_kwargs)) return ret
def expand_calls(self, calls, apply_hosts=True): # Generate new call list with per-host variants & Connections inserted ret = [] # TODO: mesh well with Invoke list-type args helper (inv #132) hosts = [] host_str = self.core[0].args.hosts.value if apply_hosts and host_str: hosts = host_str.split(",") for call in calls: if isinstance(call, Task): call = Call(task=call) # TODO: expand this to allow multiple types of execution plans, # pending outcome of invoke#461 (which, if flexible enough to # handle intersect of dependencies+parameterization, just becomes # 'honor that new feature of Invoke') # TODO: roles, other non-runtime host parameterizations, etc # Pre-tasks get added only once, not once per host. ret.extend(self.expand_calls(call.pre, apply_hosts=False)) # Main task, per host for host in hosts: ret.append(self.parameterize(call, host)) # Deal with lack of hosts arg (acts same as `inv` in that case) # TODO: no tests for this branch? if not hosts: ret.append(call) # Post-tasks added once, not once per host. ret.extend(self.expand_calls(call.post, apply_hosts=False)) # Add remainder as anonymous task if self.core.remainder: # TODO: this will need to change once there are more options for # setting host lists besides "-H or 100% within-task" if not hosts: raise NothingToDo( "Was told to run a command, but not given any hosts to run it on!" # noqa ) def anonymous(c): # TODO: how to make all our tests configure in_stream=False? c.run(self.core.remainder, in_stream=False) anon = Call(Task(body=anonymous)) # TODO: see above TODOs about non-parameterized setups, roles etc # TODO: will likely need to refactor that logic some more so it can # be used both there and here. for host in hosts: ret.append(self.parameterize(anon, host)) return ret
def includes_args_and_kwargs(self): call = Call( self.task, args=("posarg1", "posarg2"), # Single-key dict to avoid dict ordering issues kwargs={"kwarg1": "val1"}, ) expected = "<Call 'mytask', args: ('posarg1', 'posarg2'), kwargs: {'kwarg1': 'val1'}>" # noqa assert str(call) == expected
def always_generates_ConnectionCall_with_host_attr(self): task, executor = _get_executor(hosts_flag="host1,host2,host3") calls = executor.expand_calls(calls=[Call(task)]) assert len(calls) == 3 assert all(isinstance(x, ConnectionCall) for x in calls) assert [x.init_kwargs["host"] for x in calls] == [ "host1", "host2", "host3", ]
def includes_args_and_kwargs(self): call = Call( self.task, args=('posarg1', 'posarg2'), # Single-key dict to avoid dict ordering issues kwargs={'kwarg1': 'val1'}, ) assert str( call ) == "<Call 'mytask', args: ('posarg1', 'posarg2'), kwargs: {'kwarg1': 'val1'}>" # noqa
def defaults_to_empty_dict(self): eq_(Call(_).kwargs, dict())
def may_be_given(self): eq_(Call(_, args=(1, 2, 3)).args, (1, 2, 3))
def defaults_to_empty_tuple(self): eq_(Call(_).args, tuple())
def may_be_given(self): eq_(Call(_, called_as='foo').called_as, 'foo')
def defaults_to_empty_tuple(self): assert Call(_).args == tuple()
def returns_new_but_equivalent_object(self): orig = Call(self.task) clone = orig.clone() ok_(clone is not orig) ok_(clone == orig)
def requires_config_argument(self): Call(_).make_context()
def includes_aka_if_explicit_name_given(self): call = Call(self.task, called_as='notmytask') eq_(str( call ), "<Call 'mytask' (called as: 'notmytask'), args: (), kwargs: {}>" ) # noqa
def may_be_given(self): eq_(Call(_, kwargs={'foo': 'bar'}).kwargs, {'foo': 'bar'})
def requires_config_argument(self): with raises(TypeError): Call(_).make_context()
def includes_task_name(self): call = Call(self.task) assert str(call) == "<Call 'mytask', args: (), kwargs: {}>"
def may_be_given(self): assert Call(_, kwargs={'foo': 'bar'}).kwargs == {'foo': 'bar'}
def defaults_to_empty_dict(self): assert Call(_).kwargs == dict()
def may_be_given(self): assert Call(_, args=(1, 2, 3)).args == (1, 2, 3)
def includes_task_name(self): call = Call(self.task) eq_(str(call), "<Call 'mytask', args: (), kwargs: {}>")
def is_required(self): Call()
def skips_aka_if_explicit_name_same_as_task_name(self): call = Call(self.task, called_as='mytask') eq_(str(call), "<Call 'mytask', args: (), kwargs: {}>")
def is_first_posarg(self): ok_(Call(_).task is _)
def creates_a_new_Context_from_given_config(self): conf = Config(defaults={'foo': 'bar'}) ctx = Call(_).make_context(conf) ok_(isinstance(ctx, Context)) eq_(ctx.foo, 'bar')
def defaults_to_None(self): eq_(Call(_).called_as, None)
def creates_a_new_Context_from_given_config(self): conf = Config(defaults={'foo': 'bar'}) c = Call(_).make_context(conf) assert isinstance(c, Context) assert c.foo == 'bar'