From 5a3445171e01ea6b267f82497a339a4529a79b48 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 27 Jul 2022 15:02:16 +0300 Subject: [PATCH] Drop python 3.6 support --- .github/workflows/integration.yaml | 4 ++-- CONTRIBUTING.md | 2 +- redis/asyncio/cluster.py | 6 ++--- redis/asyncio/connection.py | 25 +++++++------------- redis/asyncio/lock.py | 10 ++------ setup.py | 3 +-- tests/test_asyncio/conftest.py | 27 ++++------------------ tests/test_asyncio/test_bloom.py | 5 ---- tests/test_asyncio/test_cluster.py | 14 +++-------- tests/test_asyncio/test_commands.py | 9 +------- tests/test_asyncio/test_connection.py | 4 ---- tests/test_asyncio/test_connection_pool.py | 9 +------- tests/test_asyncio/test_encoding.py | 10 +------- tests/test_asyncio/test_lock.py | 9 +------- tests/test_asyncio/test_monitor.py | 5 ---- tests/test_asyncio/test_pipeline.py | 5 ---- tests/test_asyncio/test_pubsub.py | 9 +------- tests/test_asyncio/test_scripting.py | 10 +------- tests/test_asyncio/test_search.py | 5 ---- tests/test_asyncio/test_sentinel.py | 9 +------- tests/test_asyncio/test_timeseries.py | 4 ---- tox.ini | 4 ++-- 22 files changed, 32 insertions(+), 156 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 1cce9f3659..5876c08738 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -39,7 +39,7 @@ jobs: strategy: max-parallel: 15 matrix: - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', 'pypy-3.7', 'pypy-3.8'] + python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.7', 'pypy-3.8'] test-type: ['standalone', 'cluster'] connection-type: ['hiredis', 'plain'] env: @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', 'pypy-3.7'] + python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.7'] steps: - uses: actions/checkout@v2 - name: install python ${{ matrix.python-version }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 827a25f9c4..e31ec3491e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -126,7 +126,7 @@ this, instead of using make test, you need to pass Our test suite uses `pytest`. You can run a specific test suite against a specific Python version like this: -`$ docker-compose run test tox -e py36 -- --redis-url=redis://master:6379/9 tests/test_commands.py` +`$ docker-compose run test tox -e py37 -- --redis-url=redis://master:6379/9 tests/test_commands.py` ### Troubleshooting diff --git a/redis/asyncio/cluster.py b/redis/asyncio/cluster.py index df0c17d49c..1a33563781 100644 --- a/redis/asyncio/cluster.py +++ b/redis/asyncio/cluster.py @@ -377,8 +377,7 @@ def __del__(self) -> None: warnings.warn(f"{self._DEL_MESSAGE} {self!r}", ResourceWarning, source=self) try: context = {"client": self, "message": self._DEL_MESSAGE} - # TODO: Change to get_running_loop() when dropping support for py3.6 - asyncio.get_event_loop().call_exception_handler(context) + asyncio.get_running_loop().call_exception_handler(context) except RuntimeError: ... @@ -834,8 +833,7 @@ def __del__(self) -> None: ) try: context = {"client": self, "message": self._DEL_MESSAGE} - # TODO: Change to get_running_loop() when dropping support for py3.6 - asyncio.get_event_loop().call_exception_handler(context) + asyncio.get_running_loop().call_exception_handler(context) except RuntimeError: ... break diff --git a/redis/asyncio/connection.py b/redis/asyncio/connection.py index 4c75d2f1df..6823dcb853 100644 --- a/redis/asyncio/connection.py +++ b/redis/asyncio/connection.py @@ -7,7 +7,6 @@ import os import socket import ssl -import sys import threading import weakref from itertools import chain @@ -864,12 +863,10 @@ async def _ping_failed(self, error): async def check_health(self): """Check the health of the connection with a PING/PONG""" - if sys.version_info[0:2] == (3, 6): - func = asyncio.get_event_loop - else: - func = asyncio.get_running_loop - - if self.health_check_interval and func().time() > self.next_health_check: + if ( + self.health_check_interval + and asyncio.get_running_loop().time() > self.next_health_check + ): await self.retry.call_with_retry(self._send_ping, self._ping_failed) async def _send_packed_command(self, command: Iterable[bytes]) -> None: @@ -957,11 +954,8 @@ async def read_response(self, disable_decoding: bool = False): raise if self.health_check_interval: - if sys.version_info[0:2] == (3, 6): - func = asyncio.get_event_loop - else: - func = asyncio.get_running_loop - self.next_health_check = func().time() + self.health_check_interval + next_time = asyncio.get_running_loop().time() + self.health_check_interval + self.next_health_check = next_time if isinstance(response, ResponseError): raise response from None @@ -992,11 +986,8 @@ async def read_response_without_lock(self, disable_decoding: bool = False): raise if self.health_check_interval: - if sys.version_info[0:2] == (3, 6): - func = asyncio.get_event_loop - else: - func = asyncio.get_running_loop - self.next_health_check = func().time() + self.health_check_interval + next_time = asyncio.get_running_loop().time() + self.health_check_interval + self.next_health_check = next_time if isinstance(response, ResponseError): raise response from None diff --git a/redis/asyncio/lock.py b/redis/asyncio/lock.py index fc7df373f1..8ede59b146 100644 --- a/redis/asyncio/lock.py +++ b/redis/asyncio/lock.py @@ -1,5 +1,4 @@ import asyncio -import sys import threading import uuid from types import SimpleNamespace @@ -186,11 +185,6 @@ async def acquire( object with the default encoding. If a token isn't specified, a UUID will be generated. """ - if sys.version_info[0:2] != (3, 6): - loop = asyncio.get_running_loop() - else: - loop = asyncio.get_event_loop() - sleep = self.sleep if token is None: token = uuid.uuid1().hex.encode() @@ -203,14 +197,14 @@ async def acquire( blocking_timeout = self.blocking_timeout stop_trying_at = None if blocking_timeout is not None: - stop_trying_at = loop.time() + blocking_timeout + stop_trying_at = asyncio.get_event_loop().time() + blocking_timeout while True: if await self.do_acquire(token): self.local.token = token return True if not blocking: return False - next_try_at = loop.time() + sleep + next_try_at = asyncio.get_event_loop().time() + sleep if stop_trying_at is not None and next_try_at > stop_trying_at: return False await asyncio.sleep(sleep) diff --git a/setup.py b/setup.py index 87649c596f..c513b40ce4 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ }, author="Redis Inc.", author_email="oss@redis.com", - python_requires=">=3.6", + python_requires=">=3.7", install_requires=[ "deprecated>=1.2.3", "packaging>=20.4", @@ -47,7 +47,6 @@ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", diff --git a/tests/test_asyncio/conftest.py b/tests/test_asyncio/conftest.py index 04fbf62cf7..6982cc840a 100644 --- a/tests/test_asyncio/conftest.py +++ b/tests/test_asyncio/conftest.py @@ -1,10 +1,10 @@ -import functools import random -import sys +from contextlib import asynccontextmanager as _asynccontextmanager from typing import Union from urllib.parse import urlparse import pytest +import pytest_asyncio from packaging.version import Version import redis.asyncio as redis @@ -21,13 +21,6 @@ from .compat import mock -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio - async def _get_info(redis_url): client = redis.Redis.from_url(redis_url) @@ -268,17 +261,5 @@ async def __aexit__(self, exc_type, exc_inst, tb): raise RuntimeError("More pickles") -if sys.version_info[0:2] == (3, 6): - - def asynccontextmanager(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - return AsyncContextManager(func(*args, **kwargs)) - - return wrapper - -else: - from contextlib import asynccontextmanager as _asynccontextmanager - - def asynccontextmanager(func): - return _asynccontextmanager(func) +def asynccontextmanager(func): + return _asynccontextmanager(func) diff --git a/tests/test_asyncio/test_bloom.py b/tests/test_asyncio/test_bloom.py index 2bf4e030e6..2c3617f9ab 100644 --- a/tests/test_asyncio/test_bloom.py +++ b/tests/test_asyncio/test_bloom.py @@ -1,14 +1,9 @@ -import sys - import pytest import redis.asyncio as redis from redis.exceptions import ModuleError, RedisError from redis.utils import HIREDIS_AVAILABLE -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - def intlist(obj): return [int(v) for v in obj] diff --git a/tests/test_asyncio/test_cluster.py b/tests/test_asyncio/test_cluster.py index 1365e4daff..e299395554 100644 --- a/tests/test_asyncio/test_cluster.py +++ b/tests/test_asyncio/test_cluster.py @@ -2,22 +2,12 @@ import binascii import datetime import os -import sys import warnings from typing import Any, Awaitable, Callable, Dict, List, Optional, Type, Union from urllib.parse import urlparse import pytest - -from .compat import mock - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio - +import pytest_asyncio from _pytest.fixtures import FixtureRequest from redis.asyncio.cluster import ClusterNode, NodesManager, RedisCluster @@ -44,6 +34,8 @@ skip_unless_arch_bits, ) +from .compat import mock + pytestmark = pytest.mark.onlycluster diff --git a/tests/test_asyncio/test_commands.py b/tests/test_asyncio/test_commands.py index 913f05b3fe..eaae185f31 100644 --- a/tests/test_asyncio/test_commands.py +++ b/tests/test_asyncio/test_commands.py @@ -4,18 +4,11 @@ import binascii import datetime import re -import sys import time from string import ascii_letters import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio import redis from redis import exceptions diff --git a/tests/test_asyncio/test_connection.py b/tests/test_asyncio/test_connection.py index 8030f7e628..419c8a7642 100644 --- a/tests/test_asyncio/test_connection.py +++ b/tests/test_asyncio/test_connection.py @@ -1,6 +1,5 @@ import asyncio import socket -import sys import types from unittest.mock import patch @@ -19,9 +18,6 @@ from .compat import mock -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - @pytest.mark.onlynoncluster @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") diff --git a/tests/test_asyncio/test_connection_pool.py b/tests/test_asyncio/test_connection_pool.py index c8eb918e28..d281608e51 100644 --- a/tests/test_asyncio/test_connection_pool.py +++ b/tests/test_asyncio/test_connection_pool.py @@ -1,16 +1,9 @@ import asyncio import os import re -import sys import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio import redis.asyncio as redis from redis.asyncio.connection import Connection, to_bool diff --git a/tests/test_asyncio/test_encoding.py b/tests/test_asyncio/test_encoding.py index 5db7187c84..3efcf69e5b 100644 --- a/tests/test_asyncio/test_encoding.py +++ b/tests/test_asyncio/test_encoding.py @@ -1,13 +1,5 @@ -import sys - import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio import redis.asyncio as redis from redis.exceptions import DataError diff --git a/tests/test_asyncio/test_lock.py b/tests/test_asyncio/test_lock.py index 86a8d62f71..09aec75194 100644 --- a/tests/test_asyncio/test_lock.py +++ b/tests/test_asyncio/test_lock.py @@ -1,14 +1,7 @@ import asyncio -import sys import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio from redis.asyncio.lock import Lock from redis.exceptions import LockError, LockNotOwnedError diff --git a/tests/test_asyncio/test_monitor.py b/tests/test_asyncio/test_monitor.py index 9185bcd2ee..3551579ec0 100644 --- a/tests/test_asyncio/test_monitor.py +++ b/tests/test_asyncio/test_monitor.py @@ -1,14 +1,9 @@ -import sys - import pytest from tests.conftest import skip_if_redis_enterprise, skip_ifnot_redis_enterprise from .conftest import wait_for_command -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - @pytest.mark.onlynoncluster class TestMonitor: diff --git a/tests/test_asyncio/test_pipeline.py b/tests/test_asyncio/test_pipeline.py index 33391d019d..d613f490a5 100644 --- a/tests/test_asyncio/test_pipeline.py +++ b/tests/test_asyncio/test_pipeline.py @@ -1,5 +1,3 @@ -import sys - import pytest import redis @@ -7,9 +5,6 @@ from .conftest import wait_for_command -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - class TestPipeline: @pytest.mark.onlynoncluster diff --git a/tests/test_asyncio/test_pubsub.py b/tests/test_asyncio/test_pubsub.py index d6a817a61b..0c6026715e 100644 --- a/tests/test_asyncio/test_pubsub.py +++ b/tests/test_asyncio/test_pubsub.py @@ -1,17 +1,10 @@ import asyncio import functools -import sys from typing import Optional import async_timeout import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio(forbid_global_loop=True) -else: - import pytest_asyncio +import pytest_asyncio import redis.asyncio as redis from redis.exceptions import ConnectionError diff --git a/tests/test_asyncio/test_scripting.py b/tests/test_asyncio/test_scripting.py index 406ab208e2..3776d12cb7 100644 --- a/tests/test_asyncio/test_scripting.py +++ b/tests/test_asyncio/test_scripting.py @@ -1,13 +1,5 @@ -import sys - import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio from redis import exceptions from tests.conftest import skip_if_server_version_lt diff --git a/tests/test_asyncio/test_search.py b/tests/test_asyncio/test_search.py index bc3a212ac9..aa52602588 100644 --- a/tests/test_asyncio/test_search.py +++ b/tests/test_asyncio/test_search.py @@ -1,7 +1,6 @@ import bz2 import csv import os -import sys import time from io import TextIOWrapper @@ -19,10 +18,6 @@ from redis.commands.search.suggestion import Suggestion from tests.conftest import skip_ifmodversion_lt -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - - WILL_PLAY_TEXT = os.path.abspath( os.path.join(os.path.dirname(__file__), "testdata", "will_play_text.csv.bz2") ) diff --git a/tests/test_asyncio/test_sentinel.py b/tests/test_asyncio/test_sentinel.py index e77e07f98e..5a0533ba05 100644 --- a/tests/test_asyncio/test_sentinel.py +++ b/tests/test_asyncio/test_sentinel.py @@ -1,14 +1,7 @@ import socket -import sys import pytest - -if sys.version_info[0:2] == (3, 6): - import pytest as pytest_asyncio - - pytestmark = pytest.mark.asyncio -else: - import pytest_asyncio +import pytest_asyncio import redis.asyncio.sentinel from redis import exceptions diff --git a/tests/test_asyncio/test_timeseries.py b/tests/test_asyncio/test_timeseries.py index 0e57c4f049..182f6b5f3f 100644 --- a/tests/test_asyncio/test_timeseries.py +++ b/tests/test_asyncio/test_timeseries.py @@ -1,4 +1,3 @@ -import sys import time from time import sleep @@ -7,9 +6,6 @@ import redis.asyncio as redis from tests.conftest import skip_ifmodversion_lt -if sys.version_info[0:2] == (3, 6): - pytestmark = pytest.mark.asyncio - @pytest.mark.redismod async def test_create(modclient: redis.Redis): diff --git a/tox.ini b/tox.ini index d1aeb02ade..2642aeaecb 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ asyncio_mode = auto [tox] minversion = 3.2.0 requires = tox-docker -envlist = {standalone,cluster}-{plain,hiredis,ocsp}-{uvloop,asyncio}-{py36,py37,py38,py39,pypy3},linters,docs +envlist = {standalone,cluster}-{plain,hiredis,ocsp}-{uvloop,asyncio}-{py37,py38,py39,pypy3},linters,docs [docker:master] name = master @@ -344,7 +344,7 @@ deps_files = dev_requirements.txt docker = commands = flake8 - black --target-version py36 --check --diff . + black --target-version py37 --check --diff . isort --check-only --diff . vulture redis whitelist.py --min-confidence 80 flynt --fail-on-change --dry-run .