Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-celery for openSUSE:Factory 
checked in at 2026-08-21 16:53:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-celery (Old)
 and      /work/SRC/openSUSE:Factory/.python-celery.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-celery"

Fri Aug 21 16:53:17 2026 rev:57 rq:1372557 version:5.6.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-celery/python-celery.changes      
2026-06-15 19:54:02.782093895 +0200
+++ /work/SRC/openSUSE:Factory/.python-celery.new.1258/python-celery.changes    
2026-08-21 16:54:28.024390774 +0200
@@ -1,0 +2,5 @@
+Wed Aug 19 14:44:30 UTC 2026 - Nico Krapp <[email protected]>
+
+- Add tests.patch to fix testsuite (boo#1275668)
+
+-------------------------------------------------------------------

New:
----
  tests.patch

----------(New B)----------
  New:
- Add tests.patch to fix testsuite (boo#1275668)
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-celery.spec ++++++
--- /var/tmp/diff_new_pack.oJGWkJ/_old  2026-08-21 16:54:29.299436049 +0200
+++ /var/tmp/diff_new_pack.oJGWkJ/_new  2026-08-21 16:54:29.305436262 +0200
@@ -35,6 +35,8 @@
 URL:            https://celeryproject.org
 Source:         
https://files.pythonhosted.org/packages/source/c/celery/celery-%{version}.tar.gz
 Patch0:         move-pytest-configuration-to-conftest.patch
+# PATCH-FIX-UPSTREAM tests.patch boo#1275668 gh#celery/celery@bf1cf69
+Patch1:         tests.patch
 BuildRequires:  %{python_module base >= 3.9}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}

++++++ tests.patch ++++++
>From bf1cf69e24e3ede7d7053c17d47e381be959880e Mon Sep 17 00:00:00 2001
From: Puneet Dixit <[email protected]>
Date: Mon, 25 May 2026 11:01:20 +0530
Subject: [PATCH] Skip empty groups in chains (#10321)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Skip empty groups in chains

* Tolerate Click option error wording

* Potential fix for pull request finding

* Handle generator-backed empty groups

* Skip empty groups during chain preparation

* Skip known-empty generator groups in chains

* Fix chord freeze for empty group bodies

Treat an empty group chord body as present so freeze() returns the body's 
GroupResult instead of None. This keeps callers that traverse chord body 
results from seeing a missing result when the body exists but is empty.

Assisted-by: OpenAI GPT-5 <[email protected]>

* Clarify prepared task variable in chain test

---------

Co-authored-by: Asif Saif Uddin {"Auvi":"অভি"} <[email protected]>
---
 celery/canvas.py               | 16 ++++++++-
 t/unit/app/test_preload_cli.py |  3 +-
 t/unit/tasks/test_canvas.py    | 64 ++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 2 deletions(-)

Index: celery-5.6.3/celery/canvas.py
===================================================================
--- celery-5.6.3.orig/celery/canvas.py
+++ celery-5.6.3/celery/canvas.py
@@ -1187,6 +1187,13 @@ class _chain(Signature):
                 # when groups are nested, they are unrolled - all tasks within
                 # groups should be called in parallel
                 task = maybe_unroll_group(task)
+                if (
+                    isinstance(task, group) and
+                    isinstance(task.tasks, (list, tuple)) and
+                    not task.tasks and
+                    (steps or prev_task)
+                ):
+                    continue
 
             # first task gets partial args from chain
             if clone:
@@ -1582,6 +1589,13 @@ class group(Signature):
         return self.apply_async(partial_args, **options)
 
     def __or__(self, other):
+        if (
+            isinstance(other, group) and
+            not isinstance(other.tasks, _regen) and
+            isinstance(other.tasks, (list, tuple)) and
+            not other.tasks
+        ):
+            return self
         # group() | task -> chord
         return chord(self, body=other, app=self._app)
 
@@ -2083,7 +2097,7 @@ class _chord(Signature):
         # secondly freeze all tasks in the body: those that should be called 
after the header
 
         body_result = None
-        if self.body:
+        if self.body is not None:
             body_result = self.body.freeze(
                 _id, root_id=root_id, chord=chord, group_id=group_id,
                 group_index=group_index)
Index: celery-5.6.3/t/unit/app/test_preload_cli.py
===================================================================
--- celery-5.6.3.orig/t/unit/app/test_preload_cli.py
+++ celery-5.6.3/t/unit/app/test_preload_cli.py
@@ -38,7 +38,8 @@ def test_preload_options(subcommand_with
         catch_exceptions=False,
     )
 
-    assert "No such option: --ini" in res_without_preload.output
+    assert "No such option" in res_without_preload.output
+    assert "--ini" in res_without_preload.output
     assert res_without_preload.exit_code == 2
 
     res_with_preload = isolated_cli_runner.invoke(
Index: celery-5.6.3/t/unit/tasks/test_canvas.py
===================================================================
--- celery-5.6.3.orig/t/unit/tasks/test_canvas.py
+++ celery-5.6.3/t/unit/tasks/test_canvas.py
@@ -467,6 +467,53 @@ class test_chain(CanvasCase):
         c = g1 | g2
         assert isinstance(c, chord)
 
+    def test_empty_groups_are_skipped_in_chain(self):
+        c = chain(
+            group([self.add.s(2, 2), self.add.s(4, 4)], app=self.app),
+            group(app=self.app),
+            group(app=self.app),
+        )
+
+        assert isinstance(c, group)
+        result = c.apply_async()
+        assert isinstance(result, GroupResult)
+        assert len(result.results) == 2
+
+    def test_empty_group_body_is_skipped_when_chain_upgrades_to_chord(self):
+        c = self.add.s(1, 1) | group(
+            [self.add.s(2, 2), self.add.s(3, 3)],
+            app=self.app,
+        ) | group(app=self.app)
+
+        result = c.apply_async()
+
+        assert isinstance(result, GroupResult)
+        assert len(result.results) == 2
+
+    def test_generator_backed_empty_group_is_not_skipped_when_chained(self):
+        def tasks():
+            yield from ()
+
+        c = group([self.add.s(2, 2)], app=self.app) | group(tasks(), 
app=self.app)
+
+        assert isinstance(c, chord)
+
+    def test_known_empty_generator_backed_group_is_skipped_in_chain(self):
+        def tasks():
+            yield from ()
+
+        c = _chain(
+            group([self.add.s(2, 2)], app=self.app),
+            group(tasks(), app=self.app),
+            app=self.app,
+        )
+
+        prepared_tasks, results = c.prepare_steps((), {}, c.tasks)
+
+        assert len(prepared_tasks) == 1
+        assert prepared_tasks[0].task == self.add.name
+        assert isinstance(results[0], AsyncResult)
+
     def test_prepare_steps_set_last_task_id_to_chain(self):
         last_task = self.add.s(2).set(task_id='42')
         c = self.add.s(4) | last_task
@@ -1335,6 +1382,23 @@ class test_chord(CanvasCase):
         x = chord([], self.add.s(4, 4))
         assert x.app is self.add.app
 
+    def test_freeze_empty_group_body_returns_result(self):
+        """An empty group body still exists and should be frozen.
+
+        This is a defensive check for chains that may upgrade a group into a
+        chord whose body is an empty group.
+        """
+        x = chord(
+            group(self.add.s(2, 2), app=self.app),
+            group(app=self.app),
+            app=self.app,
+        )
+
+        result = x.freeze()
+
+        assert isinstance(result, GroupResult)
+        assert result.parent is not None
+
     @pytest.mark.usefixtures('depends_on_current_app')
     def test_app_fallback_to_current(self):
         from celery._state import current_app

Reply via email to