From 39fb709c10461340adb5f9f852d1483607c28a6f Mon Sep 17 00:00:00 2001 From: Selwin Ong Date: Sun, 16 Aug 2020 11:23:29 +0700 Subject: [PATCH] get_redis_server_version() should handle 4 digit version numbers (#1322) --- rq/job.py | 6 ++---- rq/queue.py | 7 ++----- rq/utils.py | 16 ++++++++++++---- rq/worker.py | 7 ++----- tests/test_queue.py | 2 +- tests/test_utils.py | 25 ++++++++++++++++++++++++- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/rq/job.py b/rq/job.py index a27cf5d..6084d92 100644 --- a/rq/job.py +++ b/rq/job.py @@ -18,7 +18,7 @@ from .connections import resolve_connection from .exceptions import NoSuchJobError from .local import LocalStack from .serializers import resolve_serializer -from .utils import (enum, import_attribute, parse_timeout, str_to_date, +from .utils import (enum, get_version, import_attribute, parse_timeout, str_to_date, utcformat, utcnow) # Serialize pickle dumps using the highest pickle protocol (binary, default @@ -590,9 +590,7 @@ class Job(object): def get_redis_server_version(self): """Return Redis server version of connection""" if not self.redis_server_version: - self.redis_server_version = StrictVersion( - self.connection.info("server")["redis_version"] - ) + self.redis_server_version = get_version(self.connection) return self.redis_server_version diff --git a/rq/queue.py b/rq/queue.py index 99ef158..b1ffeb1 100644 --- a/rq/queue.py +++ b/rq/queue.py @@ -15,7 +15,7 @@ from .defaults import DEFAULT_RESULT_TTL from .exceptions import DequeueTimeout, NoSuchJobError from .job import Job, JobStatus from .serializers import resolve_serializer -from .utils import backend_class, import_attribute, parse_timeout, utcnow +from .utils import backend_class, get_version, import_attribute, parse_timeout, utcnow def compact(lst): @@ -92,10 +92,7 @@ class Queue(object): def get_redis_server_version(self): """Return Redis server version of connection""" if not self.redis_server_version: - self.redis_server_version = StrictVersion( - self.connection.info("server")["redis_version"] - ) - + self.redis_server_version = get_version(self.connection) return self.redis_server_version @property diff --git a/rq/utils.py b/rq/utils.py index 4a22880..fd78ecb 100644 --- a/rq/utils.py +++ b/rq/utils.py @@ -14,10 +14,9 @@ import importlib import logging import numbers import sys -try: - from collections.abc import Iterable -except ImportError: - from collections import Iterable + +from collections import Iterable +from distutils.version import StrictVersion from .compat import as_text, is_python_version, string_types from .exceptions import TimeoutFormatError @@ -248,3 +247,12 @@ def parse_timeout(timeout): 'such as "1h", "23m".') return timeout + + +def get_version(connection): + """ + Return StrictVersion of Redis server version. + This function also correctly handles 4 digit redis server versions. + """ + version_string = connection.info("server")["redis_version"] + return StrictVersion('.'.join(version_string.split('.')[:3])) \ No newline at end of file diff --git a/rq/worker.py b/rq/worker.py index c646970..f4de170 100644 --- a/rq/worker.py +++ b/rq/worker.py @@ -39,7 +39,7 @@ from .registry import FailedJobRegistry, StartedJobRegistry, clean_registries from .scheduler import RQScheduler from .suspension import is_suspended from .timeouts import JobTimeoutException, HorseMonitorTimeoutException, UnixSignalDeathPenalty -from .utils import (backend_class, ensure_list, enum, +from .utils import (backend_class, ensure_list, enum, get_version, make_colorizer, utcformat, utcnow, utcparse) from .version import VERSION from .worker_registration import clean_worker_registry, get_keys @@ -223,10 +223,7 @@ class Worker(object): def get_redis_server_version(self): """Return Redis server version of connection""" if not self.redis_server_version: - self.redis_server_version = StrictVersion( - self.connection.info("server")["redis_version"] - ) - + self.redis_server_version = get_version(self.connection) return self.redis_server_version def validate_queues(self): diff --git a/tests/test_queue.py b/tests/test_queue.py index d936d3f..6425c87 100644 --- a/tests/test_queue.py +++ b/tests/test_queue.py @@ -554,7 +554,7 @@ class TestQueue(RQTestCase): q = Queue() with patch('rq.queue.Job.create', new=MultipleDependencyJob.create): job = q.enqueue(say_hello, depends_on=parent_jobs[0], - _dependency_ids = [job.id for job in parent_jobs]) + _dependency_ids=[job.id for job in parent_jobs]) self.assertEqual(job.get_status(), JobStatus.DEFERRED) self.assertEqual(q.job_ids, []) self.assertEqual(job.fetch_dependencies(), parent_jobs) diff --git a/tests/test_utils.py b/tests/test_utils.py index b66237e..f76be3c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -3,8 +3,14 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) import re import datetime +import mock + +from distutils.version import StrictVersion + +from redis import Redis + from tests import RQTestCase, fixtures -from rq.utils import parse_timeout, first, is_nonstring_iterable, ensure_list, utcparse, backend_class +from rq.utils import backend_class, ensure_list, first, get_version, is_nonstring_iterable, parse_timeout, utcparse from rq.exceptions import TimeoutFormatError @@ -66,3 +72,20 @@ class TestUtils(RQTestCase): self.assertEqual(fixtures.DummyQueue, backend_class(fixtures, 'DummyQueue', override=fixtures.DummyQueue)) self.assertEqual(fixtures.DummyQueue, backend_class(fixtures, 'DummyQueue', override='tests.fixtures.DummyQueue')) + + def test_get_redis_version(self): + """Ensure get_version works properly""" + redis = Redis() + self.assertTrue(isinstance(get_version(redis), StrictVersion)) + + # Parses 3 digit version numbers correctly + class DummyRedis(Redis): + def info(*args): + return {'redis_version': '4.0.8'} + self.assertEqual(get_version(DummyRedis()), StrictVersion('4.0.8')) + + # Parses 3 digit version numbers correctly + class DummyRedis(Redis): + def info(*args): + return {'redis_version': '3.0.7.9'} + self.assertEqual(get_version(DummyRedis()), StrictVersion('3.0.7')) \ No newline at end of file