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 2025-12-10 15:32:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-kombu (Old) and /work/SRC/openSUSE:Factory/.python-kombu.new.1939 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-kombu" Wed Dec 10 15:32:42 2025 rev:91 rq:1321794 version:5.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-kombu/python-kombu.changes 2025-11-05 16:21:57.847308094 +0100 +++ /work/SRC/openSUSE:Factory/.python-kombu.new.1939/python-kombu.changes 2025-12-10 15:33:09.632906130 +0100 @@ -1,0 +2,9 @@ +Tue Dec 9 11:44:27 UTC 2025 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 5.6.1 + * fix: ensure hub close does also remove global event loop reference (#2404) + * fix: default value for SQS’s receive message (#2405) + * Feat: add support for credential_provider to redis broker (#2408) + * Prepare for release: v5.6.1 (#2416) + +------------------------------------------------------------------- Old: ---- kombu-5.6.0.tar.gz New: ---- kombu-5.6.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-kombu.spec ++++++ --- /var/tmp/diff_new_pack.zAUHhH/_old 2025-12-10 15:33:10.632948293 +0100 +++ /var/tmp/diff_new_pack.zAUHhH/_new 2025-12-10 15:33:10.632948293 +0100 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-kombu -Version: 5.6.0 +Version: 5.6.1 Release: 0 Summary: AMQP Messaging Framework for Python License: BSD-3-Clause ++++++ kombu-5.6.0.tar.gz -> kombu-5.6.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/PKG-INFO new/kombu-5.6.1/PKG-INFO --- old/kombu-5.6.0/PKG-INFO 2025-11-01 16:28:41.543010200 +0100 +++ new/kombu-5.6.1/PKG-INFO 2025-11-25 12:07:23.611209400 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: kombu -Version: 5.6.0 +Version: 5.6.1 Summary: Messaging library for Python. Home-page: https://kombu.readthedocs.io Author: Ask Solem diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/README.rst new/kombu-5.6.1/README.rst --- old/kombu-5.6.0/README.rst 2025-11-01 16:28:03.000000000 +0100 +++ new/kombu-5.6.1/README.rst 2025-11-25 12:06:56.000000000 +0100 @@ -4,7 +4,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| |downloads| -:Version: 5.6.0 +:Version: 5.6.1 :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.0/docs/includes/introduction.txt new/kombu-5.6.1/docs/includes/introduction.txt --- old/kombu-5.6.0/docs/includes/introduction.txt 2025-11-01 16:28:03.000000000 +0100 +++ new/kombu-5.6.1/docs/includes/introduction.txt 2025-11-25 12:06:56.000000000 +0100 @@ -1,4 +1,4 @@ -:Version: 5.6.0 +:Version: 5.6.1 :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.0/kombu/__init__.py new/kombu-5.6.1/kombu/__init__.py --- old/kombu-5.6.0/kombu/__init__.py 2025-11-01 16:28:03.000000000 +0100 +++ new/kombu-5.6.1/kombu/__init__.py 2025-11-25 12:06:56.000000000 +0100 @@ -8,7 +8,7 @@ from collections import namedtuple from typing import Any, cast -__version__ = '5.6.0' +__version__ = '5.6.1' __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.0/kombu/asynchronous/hub.py new/kombu-5.6.1/kombu/asynchronous/hub.py --- old/kombu-5.6.0/kombu/asynchronous/hub.py 2024-01-08 16:56:44.000000000 +0100 +++ new/kombu-5.6.1/kombu/asynchronous/hub.py 2025-11-24 19:12:10.000000000 +0100 @@ -274,6 +274,10 @@ for item in todos: item() + # Clear global event loop variable if this hub is the current loop + if _current_loop is self: + set_event_loop(None) + def _discard(self, fd): fd = fileno(fd) self.readers.pop(fd, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/kombu/connection.py new/kombu-5.6.1/kombu/connection.py --- old/kombu-5.6.0/kombu/connection.py 2025-03-15 00:21:49.000000000 +0100 +++ new/kombu-5.6.1/kombu/connection.py 2025-11-24 19:12:10.000000000 +0100 @@ -171,7 +171,7 @@ ssl=False, transport=None, connect_timeout=5, transport_options=None, login_method=None, uri_prefix=None, heartbeat=0, failover_strategy='round-robin', - alternates=None, **kwargs): + alternates=None, credential_provider=None, **kwargs): alt = [] if alternates is None else alternates # have to spell the args out, just to get nice docstrings :( params = self._initial_params = { @@ -179,7 +179,8 @@ 'password': password, 'virtual_host': virtual_host, 'port': port, 'insist': insist, 'ssl': ssl, 'transport': transport, 'connect_timeout': connect_timeout, - 'login_method': login_method, 'heartbeat': heartbeat + 'login_method': login_method, 'heartbeat': heartbeat, + 'credential_provider': credential_provider } if hostname and not isinstance(hostname, str): @@ -260,7 +261,7 @@ def _init_params(self, hostname, userid, password, virtual_host, port, insist, ssl, transport, connect_timeout, - login_method, heartbeat): + login_method, heartbeat, credential_provider): transport = transport or 'amqp' if transport == 'amqp' and supports_librabbitmq(): transport = 'librabbitmq' @@ -281,6 +282,7 @@ self.ssl = ssl self.transport_cls = transport self.heartbeat = heartbeat and float(heartbeat) + self.credential_provider = credential_provider def register_with_event_loop(self, loop): self.transport.register_with_event_loop(self.connection, loop) @@ -692,6 +694,7 @@ ('heartbeat', self.heartbeat), ('failover_strategy', self._failover_strategy), ('alternates', self.alt), + ('credential_provider', self.credential_provider), ) return info diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/kombu/transport/SQS.py new/kombu-5.6.1/kombu/transport/SQS.py --- old/kombu-5.6.0/kombu/transport/SQS.py 2025-09-15 01:12:19.000000000 +0200 +++ new/kombu-5.6.1/kombu/transport/SQS.py 2025-11-24 19:12:10.000000000 +0100 @@ -545,9 +545,10 @@ client = self.sqs(queue=queue) message_system_attribute_names = self.get_message_attributes.get( - 'MessageSystemAttributeNames') + 'MessageSystemAttributeNames') or [] + message_attribute_names = self.get_message_attributes.get( - 'MessageAttributeNames') + 'MessageAttributeNames') or [] params: dict[str, Any] = { 'QueueUrl': q_url, @@ -964,7 +965,7 @@ if fetch is None or isinstance(fetch, str): return { - 'MessageAttributeNames': None, + 'MessageAttributeNames': [], 'MessageSystemAttributeNames': [APPROXIMATE_RECEIVE_COUNT], } @@ -988,7 +989,7 @@ ) return { - 'MessageAttributeNames': sorted(message_attrs) if message_attrs else None, + 'MessageAttributeNames': sorted(message_attrs) if message_attrs else [], 'MessageSystemAttributeNames': ( sorted(message_system_attrs) if message_system_attrs else [APPROXIMATE_RECEIVE_COUNT] ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/kombu/transport/redis.py new/kombu-5.6.1/kombu/transport/redis.py --- old/kombu-5.6.0/kombu/transport/redis.py 2025-09-28 16:17:48.000000000 +0200 +++ new/kombu-5.6.1/kombu/transport/redis.py 2025-11-24 19:12:10.000000000 +0100 @@ -69,6 +69,7 @@ from kombu.exceptions import InconsistencyError, VersionMismatch from kombu.log import get_logger +from kombu.utils import symbol_by_name from kombu.utils.compat import register_after_fork from kombu.utils.encoding import bytes_to_str from kombu.utils.eventio import ERR, READ, poll @@ -88,9 +89,10 @@ _REDIS_GET_CONNECTION_WITHOUT_ARGS = None try: - from redis import sentinel + from redis import CredentialProvider, sentinel except ImportError: # pragma: no cover sentinel = None + CredentialProvider = None logger = get_logger('kombu.transport.redis') @@ -1148,6 +1150,22 @@ socket_keepalive_options=None, **params): return params + def _process_credential_provider(self, credential_provider, connparams): + if credential_provider: + if isinstance(credential_provider, str): + credential_provider_cls = symbol_by_name(credential_provider) + credential_provider = credential_provider_cls() + + if not isinstance(credential_provider, CredentialProvider): + raise ValueError( + "Credential provider is not an instance of a redis.CredentialProvider or a subclass" + ) + + connparams['credential_provider'] = credential_provider + # drop username and password if credential provider is configured + connparams.pop("username", None) + connparams.pop("password", None) + def _connparams(self, asynchronous=False): conninfo = self.connection.client connparams = { @@ -1156,6 +1174,7 @@ '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, @@ -1166,6 +1185,8 @@ 'client_name': self.client_name, } + self._process_credential_provider(conninfo.credential_provider, connparams) + conn_class = self.connection_class # If the connection class does not support the `health_check_interval` @@ -1205,6 +1226,10 @@ connparams['username'] = username connparams['password'] = password + # credential provider as query string + credential_provider = query.pop("credential_provider", None) + self._process_credential_provider(credential_provider, connparams) + connparams.pop('host', None) connparams.pop('port', None) connparams['db'] = self._prepare_virtual_host( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/kombu.egg-info/PKG-INFO new/kombu-5.6.1/kombu.egg-info/PKG-INFO --- old/kombu-5.6.0/kombu.egg-info/PKG-INFO 2025-11-01 16:28:41.000000000 +0100 +++ new/kombu-5.6.1/kombu.egg-info/PKG-INFO 2025-11-25 12:07:23.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: kombu -Version: 5.6.0 +Version: 5.6.1 Summary: Messaging library for Python. Home-page: https://kombu.readthedocs.io Author: Ask Solem diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/t/unit/asynchronous/test_hub.py new/kombu-5.6.1/t/unit/asynchronous/test_hub.py --- old/kombu-5.6.0/t/unit/asynchronous/test_hub.py 2024-03-05 11:08:52.000000000 +0100 +++ new/kombu-5.6.1/t/unit/asynchronous/test_hub.py 2025-11-24 19:12:10.000000000 +0100 @@ -586,3 +586,30 @@ with patch.object(self.hub, '_ready_lock', autospec=True) as lock: self.hub._pop_ready() lock.__enter__.assert_called_once() + + def test_close_clears_global_event_loop(self): + # Test that closing a hub clears the global event loop if it's the current one + prev_loop = get_event_loop() + try: + hub = Hub() + set_event_loop(hub) + assert get_event_loop() is hub + hub.close() + assert get_event_loop() is None + finally: + set_event_loop(prev_loop) + + def test_close_does_not_clear_other_event_loop(self): + # Test that closing a hub doesn't clear the global event loop if it's a different one + prev_loop = get_event_loop() + try: + hub1 = Hub() + hub2 = Hub() + set_event_loop(hub1) + assert get_event_loop() is hub1 + hub2.close() + # hub1 should still be the current loop + assert get_event_loop() is hub1 + hub1.close() + finally: + set_event_loop(prev_loop) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/t/unit/transport/test_SQS.py new/kombu-5.6.1/t/unit/transport/test_SQS.py --- old/kombu-5.6.0/t/unit/transport/test_SQS.py 2025-09-15 01:12:19.000000000 +0200 +++ new/kombu-5.6.1/t/unit/transport/test_SQS.py 2025-11-24 19:12:10.000000000 +0100 @@ -125,9 +125,11 @@ QueueUrl=None, MaxNumberOfMessages=1, WaitTimeSeconds=10, - MessageAttributeNames=None, - MessageSystemAttributeNames=None + MessageAttributeNames=[], + MessageSystemAttributeNames=[], ): + assert isinstance(MessageAttributeNames, (list, tuple)) + assert isinstance(MessageSystemAttributeNames, (list, tuple)) self._receive_messages_calls += 1 for q in self._queues.values(): if q.url == QueueUrl: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kombu-5.6.0/t/unit/transport/test_redis.py new/kombu-5.6.1/t/unit/transport/test_redis.py --- old/kombu-5.6.0/t/unit/transport/test_redis.py 2025-09-28 16:17:48.000000000 +0200 +++ new/kombu-5.6.1/t/unit/transport/test_redis.py 2025-11-24 19:12:10.000000000 +0100 @@ -436,7 +436,7 @@ client=Mock( transport_options={}, hostname="127.0.0.1", - virtual_host=None))) + virtual_host=None, credential_provider=None))) # create the _connparams with overridden connection_class connparams = chan._connparams(asynchronous=True) # create redis.Connection @@ -965,6 +965,27 @@ self.channel.connection.client.virtual_host = 'dwqeq' self.channel._connparams() + def test_process_credential_provider(self): + connparams = { + "username": "test", + "password": "test" + } + credential_provider = "redis.CredentialProvider" + self.channel._process_credential_provider(credential_provider, connparams) + assert "username" not in connparams + assert "password" not in connparams + assert "credential_provider" in connparams + + # test with nonexistent provider + credential_provider = "nonExist.CredentialProvider" + with pytest.raises(ImportError): + self.channel._process_credential_provider(credential_provider, connparams) + + # check for ValueError when credential provider is not a subclass of CredentialProvider + credential_provider = "abc.ABC" + with pytest.raises(ValueError): + self.channel._process_credential_provider(credential_provider, connparams) + def test_connparams_allows_slash_in_db(self): self.channel.connection.client.virtual_host = '/123' assert self.channel._connparams()['db'] == 123 @@ -995,6 +1016,47 @@ assert connection_parameters['username'] == 'foo' assert connection_parameters['password'] == 'bar' + def test_connparams_client_credentials_with_credential_provider_as_kwargs(self): + self.channel.connection.client.credential_provider = redis.CredentialProvider() + connection_parameters = self.channel._connparams() + assert 'username' not in connection_parameters + assert 'password' not in connection_parameters + assert 'credential_provider' in connection_parameters + + # test for non existent cred provider + self.channel.connection.client.credential_provider = "not_exist.CredentialProvider" + with pytest.raises(ImportError): + self.channel._connparams() + + # check for ValueError when credential provider is not a subclass of CredentialProvider + class NonCredentialProvider: + pass + self.channel.connection.client.credential_provider = NonCredentialProvider() + with pytest.raises(ValueError): + self.channel._connparams() + + def test_connparams_client_credentials_with_credential_provider_as_query_param(self): + self.channel.connection.client.hostname = \ + 'redis://foo:[email protected]:6379/0?credential_provider=redis.CredentialProvider' + connection_parameters = self.channel._connparams() + + assert 'username' not in connection_parameters + assert 'password' not in connection_parameters + assert 'credential_provider' in connection_parameters + + self.channel.connection.client.hostname = \ + 'redis://foo:[email protected]:6379/0?credential_provider=nonexit.CredentialProvider' + + with pytest.raises(ImportError): + self.channel._connparams() + + # check for ValueError when credential provider is not a subclass of CredentialProvider + self.channel.connection.client.hostname = \ + 'redis://foo:[email protected]:6379/0?credential_provider=abc.ABC' + + with pytest.raises(ValueError): + self.channel._connparams() + def test_connparams_password_for_unix_socket(self): self.channel.connection.client.hostname = \ 'socket://:foo@/var/run/redis.sock' @@ -1852,7 +1914,7 @@ 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) + username=None, retry_on_timeout=None, client_name=None, credential_provider=None) master_for = patched.return_value.master_for master_for.assert_called() @@ -1875,7 +1937,7 @@ 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) + username=None, retry_on_timeout=None, client_name=None, credential_provider=None) master_for = patched.return_value.master_for master_for.assert_called() @@ -1903,7 +1965,7 @@ 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') + username=None, retry_on_timeout=None, client_name='kombu-worker', credential_provider=None) master_for = patched.return_value.master_for master_for.assert_called()
