From 3d09db85f185eb2379cea3b50ec4e6e7b513b34d Mon Sep 17 00:00:00 2001 From: Dan Walters Date: Mon, 22 Jun 2026 19:30:29 -0500 Subject: [PATCH 1/2] fix: distutils is not present in py3.12+ --- python/ciqueue/_pytest/test_queue.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/ciqueue/_pytest/test_queue.py b/python/ciqueue/_pytest/test_queue.py index e994ace7..409ab4c6 100644 --- a/python/ciqueue/_pytest/test_queue.py +++ b/python/ciqueue/_pytest/test_queue.py @@ -1,4 +1,3 @@ -from distutils import util # pylint: disable=no-name-in-module, import-modules-only from future.moves.urllib import parse as urlparse import ciqueue import ciqueue.distributed @@ -6,6 +5,14 @@ import uritools +def strtobool(val): + if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'): + return True + if val.lower() in ('n', 'no', 'f', 'false', 'off', '0'): + return False + raise ValueError(f"invalid truth value {val!r}") + + class InvalidRedisUrl(Exception): pass @@ -51,7 +58,7 @@ def parse_redis_args(spec): if 'socket_connect_timeout' in query: result['socket_connect_timeout'] = int(query['socket_connect_timeout'][0]) if 'retry_on_timeout' in query: - result['retry_on_timeout'] = bool(util.strtobool(query['retry_on_timeout'][0] or 'false')) + result['retry_on_timeout'] = strtobool(query['retry_on_timeout'][0] or 'false') if spec.scheme == "rediss": result['ssl'] = True From 42bb381feaa3e739625fbb9f0e7993070c5d821b Mon Sep 17 00:00:00 2001 From: Dan Walters Date: Mon, 22 Jun 2026 19:42:03 -0500 Subject: [PATCH 2/2] fix: support username and password in redis uri --- python/ciqueue/_pytest/test_queue.py | 11 ++++++++++- python/tests/test_test_queue.py | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/python/ciqueue/_pytest/test_queue.py b/python/ciqueue/_pytest/test_queue.py index 409ab4c6..e8579737 100644 --- a/python/ciqueue/_pytest/test_queue.py +++ b/python/ciqueue/_pytest/test_queue.py @@ -48,9 +48,18 @@ def parse_worker_args(query_string, tests_index): def parse_redis_args(spec): query = urlparse.parse_qs(spec.query) - result = {'host': spec.authority.split(':')[0], + result = {'host': spec.host, 'db': int(spec.path[1:] or 0)} + if spec.userinfo: + parts = spec.userinfo.split(':', 1) + if len(parts) == 2: + if parts[0]: + result['username'] = parts[0] + result['password'] = parts[1] + else: + result['password'] = parts[0] + if spec.port: result['port'] = spec.port if 'socket_timeout' in query: diff --git a/python/tests/test_test_queue.py b/python/tests/test_test_queue.py index 2b85741d..51c38e76 100644 --- a/python/tests/test_test_queue.py +++ b/python/tests/test_test_queue.py @@ -1,3 +1,4 @@ +import uritools import ciqueue.distributed from ciqueue._pytest import test_queue @@ -12,3 +13,22 @@ def test_initialise_from_rediss_uri(self): queue = test_queue.build_queue('rediss://localhost:6379/0?worker=1&build=12345', None) assert isinstance(queue, ciqueue.distributed.Supervisor) assert queue.redis is not None + + def test_parse_redis_args_with_username_and_password(self): + spec = uritools.urisplit('redis://user:secret@localhost:6379/0') + args = test_queue.parse_redis_args(spec) + assert args['username'] == 'user' + assert args['password'] == 'secret' + assert args['host'] == 'localhost' + + def test_parse_redis_args_with_password_only(self): + spec = uritools.urisplit('redis://:secret@localhost:6379/0') + args = test_queue.parse_redis_args(spec) + assert 'username' not in args + assert args['password'] == 'secret' + + def test_parse_redis_args_without_credentials(self): + spec = uritools.urisplit('redis://localhost:6379/0') + args = test_queue.parse_redis_args(spec) + assert 'username' not in args + assert 'password' not in args