Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-kombu for openSUSE:Factory checked in at 2026-01-12 11:50:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-kombu (Old) and /work/SRC/openSUSE:Factory/.python-kombu.new.1928 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-kombu" Mon Jan 12 11:50:06 2026 rev:92 rq:1326735 version:5.6.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-kombu/python-kombu.changes 2025-12-10 15:33:09.632906130 +0100 +++ /work/SRC/openSUSE:Factory/.python-kombu.new.1928/python-kombu.changes 2026-01-12 11:50:25.446398804 +0100 @@ -1,0 +2,10 @@ +Wed Jan 7 16:06:30 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 5.6.2 + * Improve error handling in GCP Pub/Sub ack deadline extension (#2430) + * Fix SentinelChannel to pass ACL credentials to master_for() (#2426) + * Fix credential_provider compatibility with redis-py < 5.3.0 (#2423) + * Simplify requirements given Py3.9+ baseline (#2414) + * Prepare for release: v5.6.2 (#2434) + +------------------------------------------------------------------- Old: ---- kombu-5.6.1.tar.gz New: ---- kombu-5.6.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-kombu.spec ++++++ --- /var/tmp/diff_new_pack.yU07Hq/_old 2026-01-12 11:50:26.222431566 +0100 +++ /var/tmp/diff_new_pack.yU07Hq/_new 2026-01-12 11:50:26.222431566 +0100 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-kombu -Version: 5.6.1 +Version: 5.6.2 Release: 0 Summary: AMQP Messaging Framework for Python License: BSD-3-Clause ++++++ kombu-5.6.1.tar.gz -> kombu-5.6.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/PKG-INFO new/kombu-5.6.2/PKG-INFO --- old/kombu-5.6.1/PKG-INFO 2025-11-25 12:07:23.611209400 +0100 +++ new/kombu-5.6.2/PKG-INFO 2025-12-29 21:29:51.248993000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: kombu -Version: 5.6.1 +Version: 5.6.2 Summary: Messaging library for Python. Home-page: https://kombu.readthedocs.io Author: Ask Solem @@ -30,7 +30,7 @@ License-File: LICENSE Requires-Dist: amqp<6.0.0,>=5.1.1 Requires-Dist: vine==5.1.0 -Requires-Dist: tzdata>=2025.2; python_version >= "3.9" +Requires-Dist: tzdata>=2025.2 Requires-Dist: packaging Provides-Extra: msgpack Requires-Dist: msgpack==1.1.2; extra == "msgpack" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/README.rst new/kombu-5.6.2/README.rst --- old/kombu-5.6.1/README.rst 2025-11-25 12:06:56.000000000 +0100 +++ new/kombu-5.6.2/README.rst 2025-12-29 21:29:34.000000000 +0100 @@ -4,7 +4,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| |downloads| -:Version: 5.6.1 +:Version: 5.6.2 :Documentation: https://kombu.readthedocs.io/ :Download: https://pypi.org/project/kombu/ :Source: https://github.com/celery/kombu/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/docs/includes/introduction.txt new/kombu-5.6.2/docs/includes/introduction.txt --- old/kombu-5.6.1/docs/includes/introduction.txt 2025-11-25 12:06:56.000000000 +0100 +++ new/kombu-5.6.2/docs/includes/introduction.txt 2025-12-29 21:29:34.000000000 +0100 @@ -1,4 +1,4 @@ -:Version: 5.6.1 +:Version: 5.6.2 :Web: https://kombu.readthedocs.io/ :Download: https://pypi.org/project/kombu/ :Source: https://github.com/celery/kombu/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/kombu/__init__.py new/kombu-5.6.2/kombu/__init__.py --- old/kombu-5.6.1/kombu/__init__.py 2025-11-25 12:06:56.000000000 +0100 +++ new/kombu-5.6.2/kombu/__init__.py 2025-12-29 21:29:34.000000000 +0100 @@ -8,7 +8,7 @@ from collections import namedtuple from typing import Any, cast -__version__ = '5.6.1' +__version__ = '5.6.2' __author__ = 'Ask Solem' __contact__ = '[email protected]' __homepage__ = 'https://kombu.readthedocs.io' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/kombu/transport/gcpubsub.py new/kombu-5.6.2/kombu/transport/gcpubsub.py --- old/kombu-5.6.1/kombu/transport/gcpubsub.py 2025-03-15 00:11:44.000000000 +0100 +++ new/kombu-5.6.2/kombu/transport/gcpubsub.py 2025-12-29 20:42:38.000000000 +0100 @@ -590,13 +590,22 @@ len(qdesc.unacked_ids), list(qdesc.unacked_ids), ) - self.subscriber.modify_ack_deadline( - request={ - "subscription": qdesc.subscription_path, - "ack_ids": list(qdesc.unacked_ids), - "ack_deadline_seconds": self.ack_deadline_seconds, - } - ) + try: + self.subscriber.modify_ack_deadline( + request={ + "subscription": qdesc.subscription_path, + "ack_ids": list(qdesc.unacked_ids), + "ack_deadline_seconds": self.ack_deadline_seconds, + } + ) + except Exception as exc: + logger.error( + 'thread [%s]: failed to extend ack deadline for %s: %s', + thread_id, + qdesc.subscription_path, + exc, + exc_info=True, + ) logger.info( 'unacked deadline extension thread [%s] stopped', thread_id ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/kombu/transport/redis.py new/kombu-5.6.2/kombu/transport/redis.py --- old/kombu-5.6.1/kombu/transport/redis.py 2025-11-24 19:12:10.000000000 +0100 +++ new/kombu-5.6.2/kombu/transport/redis.py 2025-12-29 20:42:38.000000000 +0100 @@ -1174,7 +1174,6 @@ 'virtual_host': conninfo.virtual_host, 'username': conninfo.userid, 'password': conninfo.password, - 'credential_provider': conninfo.credential_provider, 'max_connections': self.max_connections, 'socket_timeout': self.socket_timeout, 'socket_connect_timeout': self.socket_connect_timeout, @@ -1478,9 +1477,15 @@ "'master_name' transport option must be specified." ) + master_kwargs = { + k: additional_params[k] + for k in ('username', 'password') if k in additional_params + } + return sentinel_inst.master_for( master_name, redis.Redis, + **master_kwargs, ).connection_pool def _get_pool(self, asynchronous=False): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/kombu.egg-info/PKG-INFO new/kombu-5.6.2/kombu.egg-info/PKG-INFO --- old/kombu-5.6.1/kombu.egg-info/PKG-INFO 2025-11-25 12:07:23.000000000 +0100 +++ new/kombu-5.6.2/kombu.egg-info/PKG-INFO 2025-12-29 21:29:51.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: kombu -Version: 5.6.1 +Version: 5.6.2 Summary: Messaging library for Python. Home-page: https://kombu.readthedocs.io Author: Ask Solem @@ -30,7 +30,7 @@ License-File: LICENSE Requires-Dist: amqp<6.0.0,>=5.1.1 Requires-Dist: vine==5.1.0 -Requires-Dist: tzdata>=2025.2; python_version >= "3.9" +Requires-Dist: tzdata>=2025.2 Requires-Dist: packaging Provides-Extra: msgpack Requires-Dist: msgpack==1.1.2; extra == "msgpack" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/kombu.egg-info/requires.txt new/kombu-5.6.2/kombu.egg-info/requires.txt --- old/kombu-5.6.1/kombu.egg-info/requires.txt 2025-11-25 12:07:23.000000000 +0100 +++ new/kombu-5.6.2/kombu.egg-info/requires.txt 2025-12-29 21:29:51.000000000 +0100 @@ -1,9 +1,7 @@ amqp<6.0.0,>=5.1.1 vine==5.1.0 -packaging - -[:python_version >= "3.9"] tzdata>=2025.2 +packaging [azureservicebus] azure-servicebus>=7.10.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/requirements/default.txt new/kombu-5.6.2/requirements/default.txt --- old/kombu-5.6.1/requirements/default.txt 2025-10-19 15:26:38.000000000 +0200 +++ new/kombu-5.6.2/requirements/default.txt 2025-12-29 20:42:38.000000000 +0100 @@ -1,4 +1,4 @@ amqp>=5.1.1,<6.0.0 vine==5.1.0 -tzdata>=2025.2; python_version>="3.9" +tzdata>=2025.2 packaging diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/requirements/pkgutils.txt new/kombu-5.6.2/requirements/pkgutils.txt --- old/kombu-5.6.1/requirements/pkgutils.txt 2025-10-18 22:51:37.000000000 +0200 +++ new/kombu-5.6.2/requirements/pkgutils.txt 2025-12-29 20:42:38.000000000 +0100 @@ -5,5 +5,5 @@ sphinx2rst>=1.0 bumpversion==0.6.0 pydocstyle==6.3.0 -mypy==1.18.2 +mypy==1.19.1 typing_extensions==4.15.0; python_version<"3.10" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/requirements/test-ci.txt new/kombu-5.6.2/requirements/test-ci.txt --- old/kombu-5.6.1/requirements/test-ci.txt 2025-10-18 22:51:37.000000000 +0200 +++ new/kombu-5.6.2/requirements/test-ci.txt 2025-12-29 20:42:38.000000000 +0100 @@ -1,5 +1,4 @@ -pytest-cov==5.0.0; python_version<"3.9" -pytest-cov==7.0.0; python_version>="3.9" +pytest-cov==7.0.0 codecov==2.1.13; sys_platform == 'win32' librabbitmq>=2.0.0; sys_platform == 'win32' -r extras/redis.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/requirements/test.txt new/kombu-5.6.2/requirements/test.txt --- old/kombu-5.6.1/requirements/test.txt 2025-10-18 22:51:37.000000000 +0200 +++ new/kombu-5.6.2/requirements/test.txt 2025-12-29 20:42:38.000000000 +0100 @@ -3,5 +3,4 @@ pytest-freezer==0.4.9 pytest-sugar==1.1.1 pytest==8.4.2 -pre-commit>=3.5.0,<3.8.0; python_version < '3.9' -pre-commit>=4.0.1; python_version >= '3.9' +pre-commit>=4.0.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/t/unit/transport/test_gcpubsub.py new/kombu-5.6.2/t/unit/transport/test_gcpubsub.py --- old/kombu-5.6.1/t/unit/transport/test_gcpubsub.py 2025-03-15 00:21:49.000000000 +0100 +++ new/kombu-5.6.2/t/unit/transport/test_gcpubsub.py 2025-12-29 20:42:38.000000000 +0100 @@ -598,6 +598,131 @@ == modify_ack_deadline_calls ) + def test_extend_unacked_deadline_handles_exception(self, channel): + """Test that exceptions in modify_ack_deadline don't crash the thread.""" + # Given: A queue with unacked messages and modify_ack_deadline raises exception + queue = "test_queue" + subscription_path = ( + "projects/project-id/subscriptions/test_subscription" + ) + ack_ids = ["ack_id1", "ack_id2"] + qdesc = QueueDescriptor( + name=queue, + topic_path="projects/project-id/topics/test_topic", + subscription_id="test_subscription", + subscription_path=subscription_path, + ) + channel.transport_options = {"ack_deadline_seconds": 240} + channel._queue_cache[channel.entity_name(queue)] = qdesc + qdesc.unacked_ids.extend(ack_ids) + channel._stop_extender.wait = MagicMock(side_effect=[False, False, True]) + channel.subscriber.modify_ack_deadline = MagicMock( + side_effect=[Exception("Test error"), None] + ) + + # When: The deadline extension thread runs + with patch('kombu.transport.gcpubsub.logger') as mock_logger: + channel._extend_unacked_deadline() + + # Then: The thread continues processing and logs the error + assert channel.subscriber.modify_ack_deadline.call_count == 2 + mock_logger.error.assert_called_once() + error_call_args = mock_logger.error.call_args + assert 'failed to extend ack deadline' in error_call_args[0][0] + assert error_call_args[1]['exc_info'] is True + + @pytest.mark.parametrize( + "exception_class,exception_message", + [ + (DeadlineExceeded, "Timeout"), + (PermissionDenied, "Access denied"), + ], + ) + def test_extend_unacked_deadline_handles_specific_exceptions( + self, channel, exception_class, exception_message + ): + """Test handling of specific exception types.""" + # Given: A queue with unacked messages and modify_ack_deadline raises an exception + queue = "test_queue" + subscription_path = ( + "projects/project-id/subscriptions/test_subscription" + ) + ack_ids = ["ack_id1"] + qdesc = QueueDescriptor( + name=queue, + topic_path="projects/project-id/topics/test_topic", + subscription_id="test_subscription", + subscription_path=subscription_path, + ) + channel.transport_options = {"ack_deadline_seconds": 240} + channel._queue_cache[channel.entity_name(queue)] = qdesc + qdesc.unacked_ids.extend(ack_ids) + channel._stop_extender.wait = MagicMock(side_effect=[False, True]) + channel.subscriber.modify_ack_deadline = MagicMock( + side_effect=exception_class(exception_message) + ) + + # When: The deadline extension thread runs + with patch('kombu.transport.gcpubsub.logger') as mock_logger: + channel._extend_unacked_deadline() + + # Then: The error is logged appropriately + mock_logger.error.assert_called_once() + error_call_args = mock_logger.error.call_args + assert 'failed to extend ack deadline' in error_call_args[0][0] + + def test_extend_unacked_deadline_continues_after_exception(self, channel): + """Test that the thread continues processing other queues after exception.""" + # Given: Two queues with unacked messages, first raises exception, second succeeds + queue1 = "test_queue1" + queue2 = "test_queue2" + subscription_path1 = ( + "projects/project-id/subscriptions/test_subscription1" + ) + subscription_path2 = ( + "projects/project-id/subscriptions/test_subscription2" + ) + ack_ids = ["ack_id1"] + + qdesc1 = QueueDescriptor( + name=queue1, + topic_path="projects/project-id/topics/test_topic1", + subscription_id="test_subscription1", + subscription_path=subscription_path1, + ) + qdesc2 = QueueDescriptor( + name=queue2, + topic_path="projects/project-id/topics/test_topic2", + subscription_id="test_subscription2", + subscription_path=subscription_path2, + ) + + channel.transport_options = {"ack_deadline_seconds": 240} + channel._queue_cache[channel.entity_name(queue1)] = qdesc1 + channel._queue_cache[channel.entity_name(queue2)] = qdesc2 + qdesc1.unacked_ids.extend(ack_ids) + qdesc2.unacked_ids.extend(ack_ids) + channel._stop_extender.wait = MagicMock(side_effect=[False, True]) + + call_count = [0] + + def modify_side_effect(*args, **kwargs): + call_count[0] += 1 + if call_count[0] == 1: + raise Exception("First queue error") + return None + + channel.subscriber.modify_ack_deadline = MagicMock( + side_effect=modify_side_effect + ) + + # When: The deadline extension thread runs + with patch('kombu.transport.gcpubsub.logger'): + channel._extend_unacked_deadline() + + # Then: Both queues are processed despite the first one failing + assert channel.subscriber.modify_ack_deadline.call_count == 2 + def test_after_reply_message_received(self, channel): queue = 'test-queue' subscription_path = f'projects/test-project/subscriptions/{queue}' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.1/t/unit/transport/test_redis.py new/kombu-5.6.2/t/unit/transport/test_redis.py --- old/kombu-5.6.1/t/unit/transport/test_redis.py 2025-11-24 19:12:10.000000000 +0100 +++ new/kombu-5.6.2/t/unit/transport/test_redis.py 2025-12-29 20:42:38.000000000 +0100 @@ -986,6 +986,17 @@ with pytest.raises(ValueError): self.channel._process_credential_provider(credential_provider, connparams) + # test with provider instance + class MockCredentialProvider: + pass + + with patch('kombu.transport.redis.CredentialProvider', new=MockCredentialProvider): + provider = MockCredentialProvider() + connparams = {"username": "test", "password": "test"} + self.channel._process_credential_provider(provider, connparams) + assert connparams['credential_provider'] is provider + assert "username" not in connparams + def test_connparams_allows_slash_in_db(self): self.channel.connection.client.virtual_host = '/123' assert self.channel._connparams()['db'] == 123 @@ -1016,6 +1027,11 @@ assert connection_parameters['username'] == 'foo' assert connection_parameters['password'] == 'bar' + def test_connparams_no_credential_provider(self): + self.channel.connection.client.credential_provider = None + connection_parameters = self.channel._connparams() + assert 'credential_provider' not in connection_parameters + def test_connparams_client_credentials_with_credential_provider_as_kwargs(self): self.channel.connection.client.credential_provider = redis.CredentialProvider() connection_parameters = self.channel._connparams() @@ -1914,11 +1930,14 @@ min_other_sentinels=0, password=None, sentinel_kwargs=None, socket_connect_timeout=None, socket_keepalive=None, socket_keepalive_options=None, socket_timeout=None, - username=None, retry_on_timeout=None, client_name=None, credential_provider=None) + username=None, retry_on_timeout=None, client_name=None) master_for = patched.return_value.master_for master_for.assert_called() - master_for.assert_called_with('not_important', ANY) + master_for.assert_called_with( + 'not_important', ANY, + username=None, password=None + ) master_for().connection_pool.get_connection.assert_called() def test_getting_master_from_sentinel_single_node(self): @@ -1937,11 +1956,14 @@ min_other_sentinels=0, password=None, sentinel_kwargs=None, socket_connect_timeout=None, socket_keepalive=None, socket_keepalive_options=None, socket_timeout=None, - username=None, retry_on_timeout=None, client_name=None, credential_provider=None) + username=None, retry_on_timeout=None, client_name=None) master_for = patched.return_value.master_for master_for.assert_called() - master_for.assert_called_with('not_important', ANY) + master_for.assert_called_with( + 'not_important', ANY, + username=None, password=None + ) master_for().connection_pool.get_connection.assert_called() def test_getting_master_from_sentinel_with_client_name(self): @@ -1965,11 +1987,74 @@ min_other_sentinels=0, password=None, sentinel_kwargs=None, socket_connect_timeout=None, socket_keepalive=None, socket_keepalive_options=None, socket_timeout=None, - username=None, retry_on_timeout=None, client_name='kombu-worker', credential_provider=None) + username=None, retry_on_timeout=None, client_name='kombu-worker') + + master_for = patched.return_value.master_for + master_for.assert_called() + master_for.assert_called_with( + 'not_important', ANY, + username=None, password=None + ) + master_for().connection_pool.get_connection.assert_called() + + def test_getting_master_from_sentinel_with_acl_credentials(self): + with patch('redis.sentinel.Sentinel') as patched: + connection = Connection( + 'sentinel://myuser:mypassword@localhost:65532/', + transport_options={ + 'master_name': 'not_important', + }, + ) + + connection.channel() + + patched.assert_called_once_with( + [ + ('localhost', 65532), + ], + connection_class=ANY, db=0, max_connections=10, + min_other_sentinels=0, password='mypassword', + sentinel_kwargs=None, + socket_connect_timeout=None, socket_keepalive=None, + socket_keepalive_options=None, socket_timeout=None, + username='myuser', retry_on_timeout=None, client_name=None) + + master_for = patched.return_value.master_for + master_for.assert_called() + master_for.assert_called_with( + 'not_important', ANY, + username='myuser', password='mypassword' + ) + master_for().connection_pool.get_connection.assert_called() + + def test_getting_master_from_sentinel_with_password_only(self): + with patch('redis.sentinel.Sentinel') as patched: + connection = Connection( + 'sentinel://:mypassword@localhost:65532/', + transport_options={ + 'master_name': 'not_important', + }, + ) + + connection.channel() + + patched.assert_called_once_with( + [ + ('localhost', 65532), + ], + connection_class=ANY, db=0, max_connections=10, + min_other_sentinels=0, password='mypassword', + sentinel_kwargs=None, + socket_connect_timeout=None, socket_keepalive=None, + socket_keepalive_options=None, socket_timeout=None, + username=None, retry_on_timeout=None, client_name=None) master_for = patched.return_value.master_for master_for.assert_called() - master_for.assert_called_with('not_important', ANY) + master_for.assert_called_with( + 'not_important', ANY, + username=None, password='mypassword' + ) master_for().connection_pool.get_connection.assert_called() def test_can_create_connection(self):
