diff --git a/celery/canvas.py b/celery/canvas.py index 7871f7b395..9844ff81ec 100644 --- a/celery/canvas.py +++ b/celery/canvas.py @@ -1028,8 +1028,16 @@ class group(Signature): @classmethod def from_dict(cls, d, app=None): + # We need to mutate the `kwargs` element in place to avoid confusing + # `freeze()` implementations which end up here and expect to be able to + # access elements from that dictionary later and refer to objects + # canonicalized here + orig_tasks = d["kwargs"]["tasks"] + d["kwargs"]["tasks"] = rebuilt_tasks = type(orig_tasks)(( + maybe_signature(task, app=app) for task in orig_tasks + )) return _upgrade( - d, group(d['kwargs']['tasks'], app=app, **d['options']), + d, group(rebuilt_tasks, app=app, **d['options']), ) def __init__(self, *tasks, **options): diff --git a/t/integration/test_canvas.py b/t/integration/test_canvas.py index 3c8f6e2d57..67c3120dbc 100644 --- a/t/integration/test_canvas.py +++ b/t/integration/test_canvas.py @@ -1029,7 +1029,6 @@ def test_rebuild_nested_chain_chord(self, manager): ) sig.delay().get(timeout=TIMEOUT) - @pytest.mark.xfail(reason="#6341") def test_rebuild_nested_group_chain(self, manager): sig = chain( tasks.return_nested_signature_group_chain.s(), @@ -1037,7 +1036,6 @@ def test_rebuild_nested_group_chain(self, manager): ) sig.delay().get(timeout=TIMEOUT) - @pytest.mark.xfail(reason="#6341") def test_rebuild_nested_group_group(self, manager): sig = chain( tasks.return_nested_signature_group_group.s(), @@ -1045,7 +1043,6 @@ def test_rebuild_nested_group_group(self, manager): ) sig.delay().get(timeout=TIMEOUT) - @pytest.mark.xfail(reason="#6341") def test_rebuild_nested_group_chord(self, manager): try: manager.app.backend.ensure_chords_allowed() diff --git a/t/unit/tasks/test_canvas.py b/t/unit/tasks/test_canvas.py index e66019c90e..ee0c584f05 100644 --- a/t/unit/tasks/test_canvas.py +++ b/t/unit/tasks/test_canvas.py @@ -633,7 +633,6 @@ def test_from_dict(self): x['args'] = None assert group.from_dict(dict(x)) - @pytest.mark.xfail(reason="#6341") def test_from_dict_deep_deserialize(self): original_group = group([self.add.s(1, 2)] * 42) serialized_group = json.loads(json.dumps(original_group)) @@ -641,7 +640,6 @@ def test_from_dict_deep_deserialize(self): for ds_task in deserialized_group.tasks: assert isinstance(ds_task, Signature) - @pytest.mark.xfail(reason="#6341") def test_from_dict_deeper_deserialize(self): inner_group = group([self.add.s(1, 2)] * 42) outer_group = group([inner_group] * 42) @@ -859,7 +857,6 @@ def test_from_dict_deep_deserialize(self): assert isinstance(task, Signature) assert isinstance(deserialized_chord.body, Signature) - @pytest.mark.xfail(reason="#6341") def test_from_dict_deep_deserialize_group(self): header = body = group([self.add.s(1, 2)]* 42) original_chord = chord(header=header, body=body) @@ -874,7 +871,6 @@ def test_from_dict_deep_deserialize_group(self): for task in deserialized_chord.body.tasks: assert isinstance(task, Signature) - @pytest.mark.xfail(reason="#6341") def test_from_dict_deeper_deserialize_group(self): inner_group = group([self.add.s(1, 2)] * 42) header = body = group([inner_group] * 42)