From b8a28ebf168f8ee7cf19293d10187ac164df5867 Mon Sep 17 00:00:00 2001 From: Petya Slavova Date: Fri, 23 May 2025 16:42:01 +0300 Subject: [PATCH 1/3] Dropping Python 3.8 support as it has reached end of life --- .github/workflows/hiredis-py-integration.yaml | 4 ++-- .github/workflows/integration.yaml | 8 ++++---- README.md | 2 +- pyproject.toml | 5 ++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/hiredis-py-integration.yaml b/.github/workflows/hiredis-py-integration.yaml index 947a0df05b..d81b9977b1 100644 --- a/.github/workflows/hiredis-py-integration.yaml +++ b/.github/workflows/hiredis-py-integration.yaml @@ -34,7 +34,7 @@ jobs: steps: - name: Compute outputs run: | - echo "CURRENT=${{ env.CURRENT_REDIS_VERSION }}" >> $GITHUB_OUTPUT + echo "CURRENT=${{ env.CURRENT_REDIS_VERSION }}" >> $GITHUB_OUTPUT hiredis-tests: runs-on: ubuntu-latest @@ -45,7 +45,7 @@ jobs: fail-fast: false matrix: redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] - python-version: [ '3.8', '3.13'] + python-version: [ '3.9', '3.13'] parser-backend: [ 'hiredis' ] hiredis-version: [ 'unstable' ] event-loop: [ 'asyncio' ] diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 7d0402e9d5..ba746189ad 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -75,7 +75,7 @@ jobs: fail-fast: false matrix: redis-version: ['8.0.1-pre', '${{ needs.redis_version.outputs.CURRENT }}', '7.2.7', '6.2.17'] - python-version: ['3.8', '3.13'] + python-version: ['3.9', '3.13'] parser-backend: ['plain'] event-loop: ['asyncio'] env: @@ -123,7 +123,7 @@ jobs: fail-fast: false matrix: redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] - python-version: [ '3.8', '3.13'] + python-version: [ '3.9', '3.13'] parser-backend: [ 'hiredis' ] hiredis-version: [ '>=3.2.0', '<3.0.0' ] event-loop: [ 'asyncio' ] @@ -149,7 +149,7 @@ jobs: fail-fast: false matrix: redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] - python-version: [ '3.8', '3.13' ] + python-version: [ '3.9', '3.13' ] parser-backend: [ 'plain' ] event-loop: [ 'uvloop' ] env: @@ -191,7 +191,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', 'pypy-3.9', 'pypy-3.10'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', 'pypy-3.9', 'pypy-3.10'] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/README.md b/README.md index 177f78feeb..414a0cf79e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Python interface to the Redis key-value store. --------------------------------------------- **Note:** redis-py 5.0 will be the last version of redis-py to support Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 will support Python 3.8+. - +**Note:** redis-py 6.1.0 will be the last version of redis-py to support Python 3.8, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 6.2.0 will support Python 3.9+. --------------------------------------------- ## How do I Redis? diff --git a/pyproject.toml b/pyproject.toml index ac692ef9d1..ee061953c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dynamic = ["version"] description = "Python client for Redis database and key-value store" readme = "README.md" license = "MIT" -requires-python = ">=3.8" +requires-python = ">=3.9" authors = [{ name = "Redis Inc.", email = "oss@redis.com" }] keywords = ["Redis", "database", "key-value-store"] classifiers = [ @@ -20,7 +20,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -83,7 +82,7 @@ filterwarnings = [ ] [tool.ruff] -target-version = "py38" +target-version = "py39" line-length = 88 exclude = [ "*.egg-info", From cb5068c196290a3d6c69f229a15ea8d3acafda22 Mon Sep 17 00:00:00 2001 From: Petya Slavova Date: Tue, 27 May 2025 10:32:17 +0300 Subject: [PATCH 2/3] Fix linter errors. --- tests/test_asyncio/test_pubsub.py | 8 +++++--- tests/test_cluster_transaction.py | 18 ++++++++++++------ tests/test_pubsub.py | 8 +++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/test_asyncio/test_pubsub.py b/tests/test_asyncio/test_pubsub.py index 5ea89a0b8b..d193cc9f2d 100644 --- a/tests/test_asyncio/test_pubsub.py +++ b/tests/test_asyncio/test_pubsub.py @@ -1048,9 +1048,11 @@ async def get_msg(): assert msg is not None # timeout waiting for another message which never arrives assert pubsub.connection.is_connected - with patch("redis._parsers._AsyncRESP2Parser.read_response") as mock1, patch( - "redis._parsers._AsyncHiredisParser.read_response" - ) as mock2, patch("redis._parsers._AsyncRESP3Parser.read_response") as mock3: + with ( + patch("redis._parsers._AsyncRESP2Parser.read_response") as mock1, + patch("redis._parsers._AsyncHiredisParser.read_response") as mock2, + patch("redis._parsers._AsyncRESP3Parser.read_response") as mock3, + ): mock1.side_effect = BaseException("boom") mock2.side_effect = BaseException("boom") mock3.side_effect = BaseException("boom") diff --git a/tests/test_cluster_transaction.py b/tests/test_cluster_transaction.py index 0eb7a4f256..cd43441f4c 100644 --- a/tests/test_cluster_transaction.py +++ b/tests/test_cluster_transaction.py @@ -124,9 +124,12 @@ def test_retry_transaction_during_unfinished_slot_migration(self, r): slot = r.keyslot(key) node_migrating, node_importing = _find_source_and_target_node_for_slot(r, slot) - with patch.object(Redis, "parse_response") as parse_response, patch.object( - NodesManager, "_update_moved_slots" - ) as manager_update_moved_slots: + with ( + patch.object(Redis, "parse_response") as parse_response, + patch.object( + NodesManager, "_update_moved_slots" + ) as manager_update_moved_slots, + ): def ask_redirect_effect(connection, *args, **options): if "MULTI" in args: @@ -161,9 +164,12 @@ def test_retry_transaction_during_slot_migration_successful(self, r): slot = r.keyslot(key) node_migrating, node_importing = _find_source_and_target_node_for_slot(r, slot) - with patch.object(Redis, "parse_response") as parse_response, patch.object( - NodesManager, "_update_moved_slots" - ) as manager_update_moved_slots: + with ( + patch.object(Redis, "parse_response") as parse_response, + patch.object( + NodesManager, "_update_moved_slots" + ) as manager_update_moved_slots, + ): def ask_redirect_effect(conn, *args, **options): # first call should go here, we trigger an AskError diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index ac6965a188..3dc07caf51 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -1138,9 +1138,11 @@ def get_msg(): assert msg is not None # timeout waiting for another message which never arrives assert is_connected() - with patch("redis._parsers._RESP2Parser.read_response") as mock1, patch( - "redis._parsers._HiredisParser.read_response" - ) as mock2, patch("redis._parsers._RESP3Parser.read_response") as mock3: + with ( + patch("redis._parsers._RESP2Parser.read_response") as mock1, + patch("redis._parsers._HiredisParser.read_response") as mock2, + patch("redis._parsers._RESP3Parser.read_response") as mock3, + ): mock1.side_effect = BaseException("boom") mock2.side_effect = BaseException("boom") mock3.side_effect = BaseException("boom") From bd7b18e1c80fc9bc146e78d8a371bdbb6bc8a550 Mon Sep 17 00:00:00 2001 From: Petya Slavova Date: Tue, 27 May 2025 12:02:51 +0300 Subject: [PATCH 3/3] Adding one more file with fixed linter errors. --- .../test_asyncio/test_cluster_transaction.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/test_asyncio/test_cluster_transaction.py b/tests/test_asyncio/test_cluster_transaction.py index e6d66a50ed..5e540eae5e 100644 --- a/tests/test_asyncio/test_cluster_transaction.py +++ b/tests/test_asyncio/test_cluster_transaction.py @@ -125,11 +125,12 @@ async def test_retry_transaction_during_unfinished_slot_migration(self, r): slot = r.keyslot(key) node_migrating, node_importing = _find_source_and_target_node_for_slot(r, slot) - with patch.object( - ClusterNode, "parse_response" - ) as parse_response, patch.object( - NodesManager, "_update_moved_slots" - ) as manager_update_moved_slots: + with ( + patch.object(ClusterNode, "parse_response") as parse_response, + patch.object( + NodesManager, "_update_moved_slots" + ) as manager_update_moved_slots, + ): def ask_redirect_effect(connection, *args, **options): if "MULTI" in args: @@ -167,11 +168,12 @@ async def test_retry_transaction_during_slot_migration_successful( slot = r.keyslot(key) node_migrating, node_importing = _find_source_and_target_node_for_slot(r, slot) - with patch.object( - ClusterNode, "parse_response" - ) as parse_response, patch.object( - NodesManager, "_update_moved_slots" - ) as manager_update_moved_slots: + with ( + patch.object(ClusterNode, "parse_response") as parse_response, + patch.object( + NodesManager, "_update_moved_slots" + ) as manager_update_moved_slots, + ): def ask_redirect_effect(conn, *args, **options): # first call should go here, we trigger an AskError