|
@@ -30,6 +30,39 @@ __all__ = [
|
|
|
]
|
|
|
|
|
|
|
|
|
+def _shorten_names(task_name, s):
|
|
|
+ # type: (str, str) -> str
|
|
|
+ """Remove repeating module names from string.
|
|
|
+
|
|
|
+ Arguments:
|
|
|
+ task_name (str): Task name (full path including module),
|
|
|
+ to use as the basis for removing module names.
|
|
|
+ s (str): The string we want to work on.
|
|
|
+
|
|
|
+ Example:
|
|
|
+
|
|
|
+ >>> _shorten_names(
|
|
|
+ ... 'x.tasks.add',
|
|
|
+ ... 'x.tasks.add(2, 2) | x.tasks.add(4) | x.tasks.mul(8)',
|
|
|
+ ... )
|
|
|
+ 'x.tasks.add(2, 2) | add(4) | mul(8)'
|
|
|
+ """
|
|
|
+ # This is used by repr(), to remove repeating module names.
|
|
|
+
|
|
|
+ # extract the module part of the task name
|
|
|
+ module = task_name.rpartition('.')[0] + '.'
|
|
|
+ # find the first occurance of the module name in the string.
|
|
|
+ index = s.find(module)
|
|
|
+ if index >= 0:
|
|
|
+ s = ''.join([
|
|
|
+ # leave the first occurance of the module name untouched.
|
|
|
+ s[:index + len(module)],
|
|
|
+ # strip seen module name from the rest of the string.
|
|
|
+ s[index + len(module):].replace(module, ''),
|
|
|
+ ])
|
|
|
+ return s
|
|
|
+
|
|
|
+
|
|
|
class _getitem_property:
|
|
|
"""Attribute -> dict key descriptor.
|
|
|
|
|
@@ -376,9 +409,6 @@ class Signature(dict):
|
|
|
def set_immutable(self, immutable):
|
|
|
self.immutable = immutable
|
|
|
|
|
|
- def set_parent_id(self, parent_id):
|
|
|
- self.parent_id = parent_id
|
|
|
-
|
|
|
def _with_list_option(self, key):
|
|
|
items = self.options.setdefault(key, [])
|
|
|
if not isinstance(items, MutableSequence):
|
|
@@ -445,26 +475,48 @@ class Signature(dict):
|
|
|
# group() | task -> chord
|
|
|
return chord(self, body=other, app=self._app)
|
|
|
elif isinstance(other, group):
|
|
|
- # task | group() -> unroll group with one member
|
|
|
+ # unroll group with one member
|
|
|
other = maybe_unroll_group(other)
|
|
|
- return chain(self, other, app=self._app)
|
|
|
+ if isinstance(self, chain):
|
|
|
+ # chain | group() -> chain
|
|
|
+ sig = self.clone()
|
|
|
+ sig.tasks.append(other)
|
|
|
+ return sig
|
|
|
+ # task | group() -> chain
|
|
|
+ return chain(self, other, app=self.app)
|
|
|
if not isinstance(self, chain) and isinstance(other, chain):
|
|
|
# task | chain -> chain
|
|
|
return chain(
|
|
|
_seq_concat_seq((self,), other.tasks), app=self._app)
|
|
|
elif isinstance(other, chain):
|
|
|
# chain | chain -> chain
|
|
|
- return chain(
|
|
|
- _seq_concat_seq(self.tasks, other.tasks), app=self._app)
|
|
|
+ sig = self.clone()
|
|
|
+ if isinstance(sig.tasks, tuple):
|
|
|
+ sig.tasks = list(sig.tasks)
|
|
|
+ sig.tasks.extend(other.tasks)
|
|
|
+ return sig
|
|
|
elif isinstance(self, chord):
|
|
|
+ # chord | task -> attach to body
|
|
|
sig = self.clone()
|
|
|
sig.body = sig.body | other
|
|
|
return sig
|
|
|
elif isinstance(other, Signature):
|
|
|
if isinstance(self, chain):
|
|
|
- # chain | task -> chain
|
|
|
- return chain(
|
|
|
- _seq_concat_item(self.tasks, other), app=self._app)
|
|
|
+ if isinstance(self.tasks[-1], group):
|
|
|
+ # CHAIN [last item is group] | TASK -> chord
|
|
|
+ sig = self.clone()
|
|
|
+ sig.tasks[-1] = chord(
|
|
|
+ sig.tasks[-1], other, app=self._app)
|
|
|
+ return sig
|
|
|
+ elif isinstance(self.tasks[-1], chord):
|
|
|
+ # CHAIN [last item is chord] -> chain with chord body.
|
|
|
+ sig = self.clone()
|
|
|
+ sig.tasks[-1].body = sig.tasks[-1].body | other
|
|
|
+ return sig
|
|
|
+ else:
|
|
|
+ # chain | task -> chain
|
|
|
+ return chain(
|
|
|
+ _seq_concat_item(self.tasks, other), app=self._app)
|
|
|
# task | task -> chain
|
|
|
return chain(self, other, app=self._app)
|
|
|
return NotImplemented
|
|
@@ -694,7 +746,7 @@ class chain(Signature):
|
|
|
steps_extend = steps.extend
|
|
|
|
|
|
prev_task = None
|
|
|
- prev_res = prev_prev_res = None
|
|
|
+ prev_res = None
|
|
|
tasks, results = [], []
|
|
|
i = 0
|
|
|
while steps:
|
|
@@ -727,7 +779,6 @@ class chain(Signature):
|
|
|
task, body=prev_task,
|
|
|
task_id=prev_res.id, root_id=root_id, app=app,
|
|
|
)
|
|
|
- prev_res = prev_prev_res
|
|
|
|
|
|
if is_last_task:
|
|
|
# chain(task_id=id) means task id is set for the last task
|
|
@@ -745,27 +796,12 @@ class chain(Signature):
|
|
|
i += 1
|
|
|
|
|
|
if prev_task:
|
|
|
- prev_task.set_parent_id(task.id)
|
|
|
-
|
|
|
if use_link:
|
|
|
# link previous task to this task.
|
|
|
task.link(prev_task)
|
|
|
|
|
|
- if prev_res:
|
|
|
- if isinstance(prev_task, chord):
|
|
|
- # If previous task was a chord,
|
|
|
- # the freeze above would have set a parent for
|
|
|
- # us, but we'd be overwriting it here.
|
|
|
-
|
|
|
- # so fix this relationship so it's:
|
|
|
- # chord body -> group -> THIS RES
|
|
|
- assert isinstance(prev_res.parent, GroupResult)
|
|
|
- prev_res.parent.parent = res
|
|
|
- else:
|
|
|
- prev_res.parent = res
|
|
|
-
|
|
|
- if is_first_task and parent_id is not None:
|
|
|
- task.set_parent_id(parent_id)
|
|
|
+ if prev_res and not prev_res.parent:
|
|
|
+ prev_res.parent = res
|
|
|
|
|
|
if link_error:
|
|
|
for errback in maybe_list(link_error):
|
|
@@ -774,14 +810,18 @@ class chain(Signature):
|
|
|
tasks.append(task)
|
|
|
results.append(res)
|
|
|
|
|
|
- prev_task, prev_prev_res, prev_res = (
|
|
|
- task, prev_res, res,
|
|
|
- )
|
|
|
-
|
|
|
- if root_id is None and tasks:
|
|
|
- root_id = tasks[-1].id
|
|
|
- for task in reversed(tasks):
|
|
|
- task.options['root_id'] = root_id
|
|
|
+ prev_task, prev_res = task, res
|
|
|
+ if isinstance(task, chord):
|
|
|
+ # If the task is a chord, and the body is a chain
|
|
|
+ # the chain has already been prepared, and res is
|
|
|
+ # set to the last task in the callback chain.
|
|
|
+
|
|
|
+ # We need to change that so that it points to the
|
|
|
+ # group result object.
|
|
|
+ node = res
|
|
|
+ while node.parent:
|
|
|
+ node = node.parent
|
|
|
+ prev_res = node
|
|
|
return tasks, results
|
|
|
|
|
|
def apply(self, args=(), kwargs={}, **options):
|
|
@@ -806,7 +846,9 @@ class chain(Signature):
|
|
|
if not self.tasks:
|
|
|
return '<{0}@{1:#x}: empty>'.format(
|
|
|
type(self).__name__, id(self))
|
|
|
- return ' | '.join(repr(t) for t in self.tasks)
|
|
|
+ return _shorten_names(
|
|
|
+ self.tasks[0]['task'],
|
|
|
+ ' | '.join(repr(t) for t in self.tasks))
|
|
|
|
|
|
|
|
|
class _basemap(Signature):
|
|
@@ -1091,10 +1133,6 @@ class group(Signature):
|
|
|
options.pop('task_id', uuid()))
|
|
|
return options, group_id, options.get('root_id')
|
|
|
|
|
|
- def set_parent_id(self, parent_id):
|
|
|
- for task in self.tasks:
|
|
|
- task.set_parent_id(parent_id)
|
|
|
-
|
|
|
def freeze(self, _id=None, group_id=None, chord=None,
|
|
|
root_id=None, parent_id=None):
|
|
|
# pylint: disable=redefined-outer-name
|
|
@@ -1141,7 +1179,11 @@ class group(Signature):
|
|
|
return iter(self.tasks)
|
|
|
|
|
|
def __repr__(self):
|
|
|
- return 'group({0.tasks!r})'.format(self)
|
|
|
+ if self.tasks:
|
|
|
+ return _shorten_names(
|
|
|
+ self.tasks[0]['task'],
|
|
|
+ 'group({0.tasks!r})'.format(self))
|
|
|
+ return 'group(<empty>)'
|
|
|
|
|
|
def __len__(self):
|
|
|
return len(self.tasks)
|
|
@@ -1216,21 +1258,19 @@ class chord(Signature):
|
|
|
self.tasks = group(self.tasks, app=self.app)
|
|
|
header_result = self.tasks.freeze(
|
|
|
parent_id=parent_id, root_id=root_id, chord=self.body)
|
|
|
- bodyres = self.body.freeze(
|
|
|
- _id, parent_id=header_result.id, root_id=root_id)
|
|
|
- bodyres.parent = header_result
|
|
|
+ bodyres = self.body.freeze(_id, root_id=root_id)
|
|
|
+ # we need to link the body result back to the group result,
|
|
|
+ # but the body may actually be a chain,
|
|
|
+ # so find the first result without a parent
|
|
|
+ node = bodyres
|
|
|
+ while node:
|
|
|
+ if not node.parent:
|
|
|
+ node.parent = header_result
|
|
|
+ break
|
|
|
+ node = node.parent
|
|
|
self.id = self.tasks.id
|
|
|
- self.body.set_parent_id(self.id)
|
|
|
return bodyres
|
|
|
|
|
|
- def set_parent_id(self, parent_id):
|
|
|
- tasks = self.tasks
|
|
|
- if isinstance(tasks, group):
|
|
|
- tasks = tasks.tasks
|
|
|
- for task in tasks:
|
|
|
- task.set_parent_id(parent_id)
|
|
|
- self.parent_id = parent_id
|
|
|
-
|
|
|
def apply_async(self, args=(), kwargs={}, task_id=None,
|
|
|
producer=None, connection=None,
|
|
|
router=None, result_cls=None, **options):
|
|
@@ -1282,7 +1322,6 @@ class chord(Signature):
|
|
|
|
|
|
results = header.freeze(
|
|
|
group_id=group_id, chord=body, root_id=root_id).results
|
|
|
- body.set_parent_id(group_id)
|
|
|
bodyres = body.freeze(task_id, root_id=root_id)
|
|
|
|
|
|
parent = app.backend.apply_chord(
|
|
@@ -1317,7 +1356,16 @@ class chord(Signature):
|
|
|
|
|
|
def __repr__(self):
|
|
|
if self.body:
|
|
|
- return self.body.reprcall(self.tasks)
|
|
|
+ if isinstance(self.body, chain):
|
|
|
+ return _shorten_names(
|
|
|
+ self.body.tasks[0]['task'],
|
|
|
+ '({0} | {1!r})'.format(
|
|
|
+ self.body.tasks[0].reprcall(self.tasks),
|
|
|
+ chain(self.body.tasks[1:], app=self._app),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ return _shorten_names(
|
|
|
+ self.body['task'], self.body.reprcall(self.tasks))
|
|
|
return '<chord without body: {0.tasks!r}>'.format(self)
|
|
|
|
|
|
@cached_property
|