From 8cbc62757559046639b0d0e24e0850a9d4c78e22 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 09:41:22 -0700 Subject: [PATCH 01/13] [IP-6943] move to Redis 7.2 and redis-py 5.0.x --- .circleci/config.yml | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f0315e5..85202a2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ jobs: install-and-test: docker: - image: cimg/python:3.11 - - image: circleci/redis:5.0.0 + - image: cimg/redis:7.2 steps: - checkout - run: pip install -r requirements.txt diff --git a/requirements.txt b/requirements.txt index 3fc0632..7e2608c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -redis==3.5.3 +redis==5.0.7 From 2aeada91a12278a120b1ca692f51982475487a25 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 09:43:55 -0700 Subject: [PATCH 02/13] [IP-6943] bump version up to align with redis-py dependency --- README.md | 1 + redis_namespace/_version.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c76354..a0fc24c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Supported list | redis-py | redis-namespace | | --- | --- | +| 5.0.7 | 5.0.7.1 | | 3.5.3 | 3.5.3.1 | | 3.0.1 | 3.0.1.1 | | 2.10.6 | 2.10.6.1 | diff --git a/redis_namespace/_version.py b/redis_namespace/_version.py index e8fa884..943a82e 100644 --- a/redis_namespace/_version.py +++ b/redis_namespace/_version.py @@ -1,3 +1,3 @@ """Version information.""" -__version__ = "3.5.3.1" +__version__ = "5.0.7.1" From 324eb4bacb4826322ff63d8474b8f0f274b13e33 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 09:57:39 -0700 Subject: [PATCH 03/13] [IP-6943] replace redis._compat with equivalents for Py3 --- redis_namespace/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/redis_namespace/__init__.py b/redis_namespace/__init__.py index 5ef8598..e42815c 100644 --- a/redis_namespace/__init__.py +++ b/redis_namespace/__init__.py @@ -12,7 +12,9 @@ from redis.client import Pipeline as _Pipeline, PubSub as _PubSub, EMPTY_RESPONSE from redis.connection import ConnectionPool from redis.exceptions import ResponseError -from redis._compat import nativestr, basestring + + +nativestr = lambda x: x if isinstance(x, str) else x.decode('utf-8', 'replace') NAMESPACED_COMMANDS = { @@ -252,7 +254,7 @@ def args_with_namespace(ns, *original_args): is_custom_match = False for i, a in enumerate(args): if ( - isinstance(a, basestring) and str(a).lower() == 'match' + isinstance(a, str) and str(a).lower() == 'match' or isinstance(a, bytes) and a.decode('utf-8').lower() == 'match' ): args[i+1] = add_namespace(ns, args[i + 1]) @@ -286,7 +288,7 @@ def add_namespace(ns, key): return [add_namespace(ns, k) for k in key] elif isinstance(key, dict): return {add_namespace(ns, k): v for k, v in key.items()} - elif isinstance(key, basestring): + elif isinstance(key, str): return '{}{}'.format(ns, key) elif isinstance(key, bytes): return '{}{}'.format(ns, nativestr(key)) @@ -300,7 +302,7 @@ def rm_namespace(ns, key): return [rm_namespace(ns, k) for k in key] elif isinstance(key, dict): return {rm_namespace(ns, k): v for k, v in key.items()} - elif isinstance(key, (basestring, bytes)): + elif isinstance(key, (str, bytes)): return key[len(ns):] return key @@ -348,7 +350,7 @@ def sort(self, name, start=None, num=None, by=None, get=None, args = [name, by, store] name, by, store = add_namespace(self._namespace, args) if get: - if isinstance(get, (basestring, bytes)): + if isinstance(get, (str, bytes)): get = add_namespace(self._namespace, get) elif isinstance(get, (list, tuple)): get = [add_namespace(self._namespace, i) if i != '#' else i for i in get] From a22d780048615c69f8b9bd44dd61f0ae9cf144d8 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 09:57:59 -0700 Subject: [PATCH 04/13] [IP-6943] remove need for redis._compat from test_commands --- tests/test_commands.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index 0238fa0..3c1e898 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from string import ascii_letters import binascii import datetime import pytest @@ -6,8 +7,6 @@ import redis import time -from redis._compat import (unichr, ascii_letters, iteritems, iterkeys, - itervalues, long) from redis.client import parse_info from redis import exceptions @@ -161,7 +160,7 @@ def test_ping(self, r): def test_slowlog_get(self, r, slowlog, ns): assert r.slowlog_reset() - unicode_string = unichr(3456) + 'abcd' + unichr(3421) + unicode_string = chr(3456) + 'abcd' + chr(3421) r.get(unicode_string) slowlog = r.slowlog_get() assert isinstance(slowlog, list) @@ -398,7 +397,7 @@ def test_get_and_set(self, r): assert r.get('a') is None byte_string = b'value' integer = 5 - unicode_string = unichr(3456) + 'abcd' + unichr(3421) + unicode_string = chr(3456) + 'abcd' + chr(3421) assert r.set('byte_string', byte_string) assert r.set('integer', 5) assert r.set('unicode_string', unicode_string) @@ -485,7 +484,7 @@ def test_mget(self, r): def test_mset(self, r): d = {'a': b'1', 'b': b'2', 'c': b'3'} assert r.mset(d) - for k, v in iteritems(d): + for k, v in d.items(): assert r[k] == v def test_msetnx(self, r): @@ -493,7 +492,7 @@ def test_msetnx(self, r): assert r.msetnx(d) d2 = {'a': b'x', 'd': b'4'} assert not r.msetnx(d2) - for k, v in iteritems(d): + for k, v in d.items(): assert r[k] == v assert r.get('d') is None @@ -1369,7 +1368,7 @@ def test_hincrbyfloat(self, r): def test_hkeys(self, r): h = {b'a1': b'1', b'a2': b'2', b'a3': b'3'} r.hmset('a', h) - local_keys = list(iterkeys(h)) + local_keys = list(h.keys()) remote_keys = r.hkeys('a') assert (sorted(local_keys) == sorted(remote_keys)) @@ -1396,7 +1395,7 @@ def test_hsetnx(self, r): def test_hvals(self, r): h = {b'a1': b'1', b'a2': b'2', b'a3': b'3'} r.hmset('a', h) - local_vals = list(itervalues(h)) + local_vals = list(h.values()) remote_vals = r.hvals('a') assert sorted(local_vals) == sorted(remote_vals) @@ -1949,8 +1948,8 @@ def test_xinfo_consumers(self, r): ] # we can't determine the idle time, so just make sure it's an int - assert isinstance(info[0].pop('idle'), (int, long)) - assert isinstance(info[1].pop('idle'), (int, long)) + assert isinstance(info[0].pop('idle'), int) + assert isinstance(info[1].pop('idle'), int) assert info == expected @skip_if_server_version_lt('5.0.0') @@ -2297,14 +2296,14 @@ def test_binary_lists(self, r): b'foo\tbar\x07': [b'7', b'8', b'9'], } # fill in lists - for key, value in iteritems(mapping): + for key, value in mapping.items(): r.rpush(key, *value) # check that KEYS returns all the keys as they are - assert sorted(r.keys('*')) == sorted(list(iterkeys(mapping))) + assert sorted(r.keys('*')) == sorted(list(mapping.keys())) # check that it is possible to get list content by key name - for key, value in iteritems(mapping): + for key, value in mapping.items(): assert r.lrange(key, 0, -1) == value def test_22_info(self, r): From 287c93a25dbd1c01114fedf15037d18880a3825d Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 09:59:18 -0700 Subject: [PATCH 05/13] [IP-6943] remove need for redis._compat from test_encoding --- tests/test_encoding.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_encoding.py b/tests/test_encoding.py index dd9d516..525a43d 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -3,7 +3,6 @@ import redis import redis_namespace -from redis._compat import unichr, unicode from .conftest import _get_client @@ -13,14 +12,14 @@ def r(self, request): return _get_client(redis_namespace.Redis, request=request, decode_responses=True) def test_simple_encoding(self, r): - unicode_string = unichr(3456) + 'abcd' + unichr(3421) + unicode_string = chr(3456) + 'abcd' + chr(3421) r['unicode-string'] = unicode_string cached_val = r['unicode-string'] - assert isinstance(cached_val, unicode) + assert isinstance(cached_val, str) assert unicode_string == cached_val def test_list_encoding(self, r): - unicode_string = unichr(3456) + 'abcd' + unichr(3421) + unicode_string = chr(3456) + 'abcd' + chr(3421) result = [unicode_string, unicode_string, unicode_string] r.rpush('a', *result) assert r.lrange('a', 0, -1) == result From 9669807fe0949b25dda361f73d48454e2c918e8f Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:00:25 -0700 Subject: [PATCH 06/13] [IP-6943] remove need for redis._compat from test_pipeline --- tests/test_pipeline.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 06abb9f..16af827 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -2,7 +2,6 @@ import pytest import redis -from redis._compat import unichr, unicode class TestPipeline(object): @@ -111,7 +110,7 @@ def test_exec_error_raised(self, r, ns): pipe.set('a', 1).set('b', 2).lpush('c', 3).set('d', 4) with pytest.raises(redis.ResponseError) as ex: pipe.execute() - assert unicode(ex.value).startswith('Command # 3 (LPUSH %sc 3) of ' + assert str(ex.value).startswith('Command # 3 (LPUSH %sc 3) of ' 'pipeline caused error: ' % ns) # make sure the pipe was restored to a working state @@ -153,7 +152,7 @@ def test_parse_error_raised(self, r, ns): with pytest.raises(redis.ResponseError) as ex: pipe.execute() - assert unicode(ex.value).startswith('Command # 2 (ZREM %sb) of ' + assert str(ex.value).startswith('Command # 2 (ZREM %sb) of ' 'pipeline caused error: ' % ns) # make sure the pipe was restored to a working state @@ -236,13 +235,13 @@ def test_exec_error_in_no_transaction_pipeline(self, r, ns): with pytest.raises(redis.ResponseError) as ex: pipe.execute() - assert unicode(ex.value).startswith('Command # 1 (LLEN %sa) of ' + assert str(ex.value).startswith('Command # 1 (LLEN %sa) of ' 'pipeline caused error: ' % ns) assert r['a'] == b'1' def test_exec_error_in_no_transaction_pipeline_unicode_command(self, r, ns): - key = unichr(3456) + 'abcd' + unichr(3421) + key = chr(3456) + 'abcd' + chr(3421) r[key] = 1 with r.pipeline(transaction=False) as pipe: pipe.llen(key) @@ -251,9 +250,9 @@ def test_exec_error_in_no_transaction_pipeline_unicode_command(self, r, ns): with pytest.raises(redis.ResponseError) as ex: pipe.execute() - expected = unicode('Command # 1 (LLEN %s%s) of pipeline caused ' + expected = str('Command # 1 (LLEN %s%s) of pipeline caused ' 'error: ') % (ns, key) - assert unicode(ex.value).startswith(expected) + assert str(ex.value).startswith(expected) assert r[key] == b'1' From 37c190be8d19ede5e63d020d0dbd3fe538c64120 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:01:20 -0700 Subject: [PATCH 07/13] [IP-6943] remove need for redis._compat from test_pubsub --- tests/test_pubsub.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index 6e1bc2a..f9c5ac5 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -4,7 +4,6 @@ import redis from redis.exceptions import ConnectionError -from redis._compat import basestring, unichr import redis_namespace from .conftest import _get_client @@ -29,7 +28,7 @@ def make_message(type, channel, data, pattern=None): 'type': type, 'pattern': pattern and pattern.encode('utf-8') or None, 'channel': channel and channel.encode('utf-8') or None, - 'data': data.encode('utf-8') if isinstance(data, basestring) else data + 'data': data.encode('utf-8') if isinstance(data, str) else data } @@ -41,7 +40,7 @@ def make_subscribe_test_data(pubsub, type): 'unsub_type': 'unsubscribe', 'sub_func': pubsub.subscribe, 'unsub_func': pubsub.unsubscribe, - 'keys': ['foo', 'bar', 'uni' + unichr(4456) + 'code'] + 'keys': ['foo', 'bar', 'uni' + chr(4456) + 'code'] } elif type == 'pattern': return { @@ -50,7 +49,7 @@ def make_subscribe_test_data(pubsub, type): 'unsub_type': 'punsubscribe', 'sub_func': pubsub.psubscribe, 'unsub_func': pubsub.punsubscribe, - 'keys': ['f*', 'b*', 'uni' + unichr(4456) + '*'] + 'keys': ['f*', 'b*', 'uni' + chr(4456) + '*'] } assert False, 'invalid subscribe type: %s' % type @@ -268,7 +267,7 @@ def test_pattern_message_handler(self, r): def test_unicode_channel_message_handler(self, r): p = r.pubsub(ignore_subscribe_messages=True) - channel = 'uni' + unichr(4456) + 'code' + channel = 'uni' + chr(4456) + 'code' channels = {channel: self.message_handler} p.subscribe(**channels) assert r.publish(channel, 'test message') == 1 @@ -277,8 +276,8 @@ def test_unicode_channel_message_handler(self, r): def test_unicode_pattern_message_handler(self, r): p = r.pubsub(ignore_subscribe_messages=True) - pattern = 'uni' + unichr(4456) + '*' - channel = 'uni' + unichr(4456) + 'code' + pattern = 'uni' + chr(4456) + '*' + channel = 'uni' + chr(4456) + 'code' p.psubscribe(**{pattern: self.message_handler}) assert r.publish(channel, 'test message') == 1 assert wait_for_message(p) is None @@ -297,9 +296,9 @@ def test_get_message_without_subscribe(self, r): class TestPubSubAutoDecoding(object): "These tests only validate that we get unicode values back" - channel = 'uni' + unichr(4456) + 'code' - pattern = 'uni' + unichr(4456) + '*' - data = 'abc' + unichr(4458) + '123' + channel = 'uni' + chr(4456) + 'code' + pattern = 'uni' + chr(4456) + '*' + data = 'abc' + chr(4458) + '123' def make_message(self, type, channel, data, pattern=None): return { From c9866a50e52e026ecce6ed0c228465d07bb4ea25 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:02:35 -0700 Subject: [PATCH 08/13] [IP-6943] remove need for redis._compat from test_sentinel --- tests/test_sentinel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_sentinel.py b/tests/test_sentinel.py index 1081e2b..b2c35fc 100644 --- a/tests/test_sentinel.py +++ b/tests/test_sentinel.py @@ -3,7 +3,6 @@ from redis import exceptions from redis.sentinel import (Sentinel, SentinelConnectionPool, MasterNotFoundError, SlaveNotFoundError) -from redis._compat import next import redis.sentinel From 7eee2ff747b82a6e8167be46665f2f745e5d1083 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:05:47 -0700 Subject: [PATCH 09/13] [IP-6943] use capitalized SSL_AVAILABLE --- tests/test_connection_pool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_connection_pool.py b/tests/test_connection_pool.py index 6076ce6..b925068 100644 --- a/tests/test_connection_pool.py +++ b/tests/test_connection_pool.py @@ -6,7 +6,7 @@ import redis_namespace from threading import Thread -from redis.connection import ssl_available, to_bool +from redis.connection import SSL_AVAILABLE, to_bool from .conftest import skip_if_server_version_lt @@ -410,7 +410,7 @@ def test_extra_querystring_options(self): class TestSSLConnectionURLParsing(object): - @pytest.mark.skipif(not ssl_available, reason="SSL not installed") + @pytest.mark.skipif(not SSL_AVAILABLE, reason="SSL not installed") def test_defaults(self): pool = redis.ConnectionPool.from_url('rediss://localhost') assert pool.connection_class == redis.SSLConnection @@ -424,7 +424,7 @@ def test_defaults(self): # TODO: these urls are hanging in redis-py 3.5+, look into changes to URLs that would affect this test @pytest.mark.skip - @pytest.mark.skipif(not ssl_available, reason="SSL not installed") + @pytest.mark.skipif(not SSL_AVAILABLE, reason="SSL not installed") def test_cert_reqs_options(self): import ssl pool = redis.ConnectionPool.from_url('rediss://?ssl_cert_reqs=none') From 90a81a05e740aeff555e6884f95ba86618491819 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:12:47 -0700 Subject: [PATCH 10/13] [IP-6943] get parse_info from new place --- tests/test_commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index 3c1e898..e9a0041 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -7,8 +7,8 @@ import redis import time -from redis.client import parse_info from redis import exceptions +from redis._parsers.helpers import parse_info from .conftest import skip_if_server_version_lt, skip_if_server_version_gte, with_bns From 32ca694bbf278d0be674a39d63687e5b65b49ec7 Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:21:12 -0700 Subject: [PATCH 11/13] [IP-6943] downgrade to 4.5.5 --- .circleci/config.yml | 2 +- README.md | 16 ++++++++-------- redis_namespace/_version.py | 2 +- requirements.txt | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 85202a2..947c2ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ jobs: install-and-test: docker: - image: cimg/python:3.11 - - image: cimg/redis:7.2 + - image: cimg/redis:5.0 steps: - checkout - run: pip install -r requirements.txt diff --git a/README.md b/README.md index a0fc24c..e43190d 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,14 @@ redis_connection.get('ns:foo') Supported list -| redis-py | redis-namespace | -| --- | --- | -| 5.0.7 | 5.0.7.1 | -| 3.5.3 | 3.5.3.1 | -| 3.0.1 | 3.0.1.1 | -| 2.10.6 | 2.10.6.1 | -| 2.10.5 | 2.10.5.2 | -| 2.10.3 | 2.10.3.1 | +| redis-py | redis-namespace | +|----------|-----------------| +| 4.5.5 | 4.5.5.1 | +| 3.5.3 | 3.5.3.1 | +| 3.0.1 | 3.0.1.1 | +| 2.10.6 | 2.10.6.1 | +| 2.10.5 | 2.10.5.2 | +| 2.10.3 | 2.10.3.1 | [travis-url]: https://travis-ci.org/guokr/redis-namespace diff --git a/redis_namespace/_version.py b/redis_namespace/_version.py index 943a82e..7c63057 100644 --- a/redis_namespace/_version.py +++ b/redis_namespace/_version.py @@ -1,3 +1,3 @@ """Version information.""" -__version__ = "5.0.7.1" +__version__ = "4.5.5.1" diff --git a/requirements.txt b/requirements.txt index 7e2608c..54a7b14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -redis==5.0.7 +redis==4.5.5 From fd7e8996d7f9b51403b99ed61f503ffdf8062f2d Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:22:21 -0700 Subject: [PATCH 12/13] [IP-6943] back to lower ssl_available --- tests/test_connection_pool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_connection_pool.py b/tests/test_connection_pool.py index b925068..6076ce6 100644 --- a/tests/test_connection_pool.py +++ b/tests/test_connection_pool.py @@ -6,7 +6,7 @@ import redis_namespace from threading import Thread -from redis.connection import SSL_AVAILABLE, to_bool +from redis.connection import ssl_available, to_bool from .conftest import skip_if_server_version_lt @@ -410,7 +410,7 @@ def test_extra_querystring_options(self): class TestSSLConnectionURLParsing(object): - @pytest.mark.skipif(not SSL_AVAILABLE, reason="SSL not installed") + @pytest.mark.skipif(not ssl_available, reason="SSL not installed") def test_defaults(self): pool = redis.ConnectionPool.from_url('rediss://localhost') assert pool.connection_class == redis.SSLConnection @@ -424,7 +424,7 @@ def test_defaults(self): # TODO: these urls are hanging in redis-py 3.5+, look into changes to URLs that would affect this test @pytest.mark.skip - @pytest.mark.skipif(not SSL_AVAILABLE, reason="SSL not installed") + @pytest.mark.skipif(not ssl_available, reason="SSL not installed") def test_cert_reqs_options(self): import ssl pool = redis.ConnectionPool.from_url('rediss://?ssl_cert_reqs=none') From 9bf425152902119958aeb2536ba628fa2298c04a Mon Sep 17 00:00:00 2001 From: Russell Bevers Date: Tue, 23 Jul 2024 10:23:48 -0700 Subject: [PATCH 13/13] [IP-6943] back to redis.client for parse_info --- tests/test_commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index e9a0041..e145d42 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -8,7 +8,7 @@ import time from redis import exceptions -from redis._parsers.helpers import parse_info +from redis.client import parse_info from .conftest import skip_if_server_version_lt, skip_if_server_version_gte, with_bns