From 075c81a5c9a67b95695e0a30bbfb963b6a5346a3 Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sat, 15 Aug 2026 17:49:12 +0100 Subject: [PATCH] chore: Clean up python 2 legacy Fixes #788 Remove python2 specific code Use python 3 style for constructors etc Use python3.8 techniques in a few places --- kazoo/client.py | 6 ++-- kazoo/handlers/eventlet.py | 5 ++-- kazoo/handlers/gevent.py | 3 +- kazoo/handlers/threading.py | 5 +--- kazoo/handlers/utils.py | 20 ++++--------- kazoo/protocol/connection.py | 4 +-- kazoo/recipe/barrier.py | 4 +-- kazoo/recipe/cache.py | 5 ++-- kazoo/recipe/counter.py | 2 +- kazoo/recipe/election.py | 2 +- kazoo/recipe/lease.py | 4 +-- kazoo/recipe/lock.py | 6 ++-- kazoo/recipe/party.py | 2 +- kazoo/recipe/queue.py | 10 +++---- kazoo/recipe/watchers.py | 6 ++-- kazoo/retry.py | 2 +- kazoo/security.py | 2 +- kazoo/testing/common.py | 8 +++--- kazoo/testing/harness.py | 4 +-- kazoo/tests/test_cache.py | 4 +-- kazoo/tests/test_connection.py | 6 ++-- kazoo/tests/test_election.py | 2 +- kazoo/tests/test_gevent_handler.py | 8 +++--- kazoo/tests/test_lease.py | 4 +-- kazoo/tests/test_lock.py | 14 +++++----- kazoo/tests/test_partitioner.py | 2 +- kazoo/tests/test_party.py | 4 +-- kazoo/tests/test_selectors_select.py | 42 ++++++++++++++++++---------- kazoo/tests/test_utils.py | 15 ++++++++++ kazoo/tests/test_watchers.py | 6 ++-- kazoo/tests/util.py | 4 +-- tox.ini | 3 -- 32 files changed, 111 insertions(+), 103 deletions(-) diff --git a/kazoo/client.py b/kazoo/client.py index 97bef453..3f2c3b94 100644 --- a/kazoo/client.py +++ b/kazoo/client.py @@ -142,7 +142,7 @@ class KazooRetryParams(TypedDict, total=False): interrupt: Callable[[], bool] -class KazooClient(object): +class KazooClient: """An Apache Zookeeper Python client supporting alternate callback handlers and high-level functionality. @@ -989,7 +989,7 @@ def _try_fetch() -> tuple[int, ...] | None: 1 ) try: - return tuple([int(d) for d in version_digits.split(".")]) + return tuple(int(d) for d in version_digits.split(".")) except ValueError: return None @@ -1966,7 +1966,7 @@ def reconfig_async( return async_result -class TransactionRequest(object): +class TransactionRequest: """A Zookeeper Transaction Request A Transaction provides a builder object that can be used to diff --git a/kazoo/handlers/eventlet.py b/kazoo/handlers/eventlet.py index ee8ed47d..1c60545f 100644 --- a/kazoo/handlers/eventlet.py +++ b/kazoo/handlers/eventlet.py @@ -1,7 +1,6 @@ """A eventlet based handler.""" from __future__ import annotations -from __future__ import absolute_import import atexit import contextlib @@ -59,7 +58,7 @@ class AsyncResult(utils.AsyncResult): """A one-time event that stores a value or an exception""" def __init__(self, handler: IHandler): - super(AsyncResult, self).__init__( + super().__init__( handler, green_threading.Condition, # type: ignore[attr-defined] TimeoutError, @@ -67,7 +66,7 @@ def __init__(self, handler: IHandler): # FIXME This should inherit from IHandler -class SequentialEventletHandler(object): +class SequentialEventletHandler: """Eventlet handler for sequentially executing callbacks. This handler executes callbacks in a sequential manner. A queue is diff --git a/kazoo/handlers/gevent.py b/kazoo/handlers/gevent.py index b9c8d02f..d8e1a838 100644 --- a/kazoo/handlers/gevent.py +++ b/kazoo/handlers/gevent.py @@ -1,7 +1,6 @@ """A gevent based handler.""" from __future__ import annotations -from __future__ import absolute_import import atexit import logging @@ -47,7 +46,7 @@ # CallbackQueue = gevent.queue.Queue[Callable[..., None]] -class SequentialGeventHandler(object): +class SequentialGeventHandler: """Gevent handler for sequentially executing callbacks. This handler executes callbacks in a sequential manner. A queue is diff --git a/kazoo/handlers/threading.py b/kazoo/handlers/threading.py index 829a7010..1c7a20c6 100644 --- a/kazoo/handlers/threading.py +++ b/kazoo/handlers/threading.py @@ -12,7 +12,6 @@ """ from __future__ import annotations -from __future__ import absolute_import import atexit import logging @@ -71,9 +70,7 @@ class AsyncResult(utils.AsyncResult): """A one-time event that stores a value or an exception""" def __init__(self, handler: Any) -> None: - super(AsyncResult, self).__init__( - handler, threading.Condition, KazooTimeoutError - ) + super().__init__(handler, threading.Condition, KazooTimeoutError) class SequentialThreadingHandler(IHandler): diff --git a/kazoo/handlers/utils.py b/kazoo/handlers/utils.py index 7ea5d4f8..097daf4a 100644 --- a/kazoo/handlers/utils.py +++ b/kazoo/handlers/utils.py @@ -305,21 +305,11 @@ def create_tcp_connection( # otherwise there is no timeout set and we'll call it as such sock = module.create_connection(address, timeout_at) break - except Exception as ex: - # FIXME The check for ex[0] is for compatibility with python 2 - # and should be removed. Instead we should just catch - # InterruptedError and continue. Even this is unnecessary, at - # least for 'socket', since PEP475 was adopted in python 3.5 - # but I'm not entirely sure about the gevent and eventlet - # libraries. - errnum = ( - ex.errno - if isinstance(ex, OSError) - else ex[0] # type: ignore - ) - if errnum == errno.EINTR: - continue - raise + except InterruptedError: + # Retry on an interrupted connect attempt. This is a + # standard Python 3 socket behavior and is enough for the + # supported Python versions in this project. + continue if sock is None: raise module.error diff --git a/kazoo/protocol/connection.py b/kazoo/protocol/connection.py index 62902085..33582720 100644 --- a/kazoo/protocol/connection.py +++ b/kazoo/protocol/connection.py @@ -102,7 +102,7 @@ def buffer(obj: Buffer, offset: int = 0) -> memoryview: return memoryview(obj)[offset:] -class RWPinger(object): +class RWPinger: """A Read/Write Server Pinger Iterable This object is initialized with the hosts iterator object and the @@ -180,7 +180,7 @@ class RWServerAvailable(Exception): ReturnValue = TypeVar("ReturnValue") -class ConnectionHandler(object): +class ConnectionHandler: """Zookeeper connection handler""" def __init__( diff --git a/kazoo/recipe/barrier.py b/kazoo/recipe/barrier.py index 26ffc935..b05e781a 100644 --- a/kazoo/recipe/barrier.py +++ b/kazoo/recipe/barrier.py @@ -19,7 +19,7 @@ from kazoo.client import KazooClient -class Barrier(object): +class Barrier: """Kazoo Barrier Implements a barrier to block processing of a set of nodes until @@ -83,7 +83,7 @@ def wait_for_clear(event: WatchedEvent) -> None: return cleared.is_set() -class DoubleBarrier(object): +class DoubleBarrier: """Kazoo Double Barrier Double barriers are used to synchronize the beginning and end of diff --git a/kazoo/recipe/cache.py b/kazoo/recipe/cache.py index cee96c82..1d361df8 100644 --- a/kazoo/recipe/cache.py +++ b/kazoo/recipe/cache.py @@ -12,7 +12,6 @@ """ from __future__ import annotations -from __future__ import absolute_import import contextlib import functools @@ -46,7 +45,7 @@ ReturnValue = TypeVar("ReturnValue") -class TreeCache(object): +class TreeCache: """The cache of a ZooKeeper subtree. :param client: A :class:`~kazoo.client.KazooClient` instance. @@ -274,7 +273,7 @@ def __call__(self, path: str, watch: WatchFunc | None) -> IAsyncResult: ... -class TreeNode(object): +class TreeNode: """The tree node record. :param tree: A :class:`~kazoo.recipe.cache.TreeCache` instance. diff --git a/kazoo/recipe/counter.py b/kazoo/recipe/counter.py index f8f27517..77d68cb5 100644 --- a/kazoo/recipe/counter.py +++ b/kazoo/recipe/counter.py @@ -20,7 +20,7 @@ Number = Union[int, float] -class Counter(object): +class Counter: """Kazoo Counter A shared counter of either int or float values. Changes to the diff --git a/kazoo/recipe/election.py b/kazoo/recipe/election.py index 1e28517b..4c440003 100644 --- a/kazoo/recipe/election.py +++ b/kazoo/recipe/election.py @@ -18,7 +18,7 @@ GenericArgs = ParamSpec("GenericArgs") -class Election(object): +class Election: """Kazoo Basic Leader Election Example usage with a :class:`~kazoo.client.KazooClient` instance:: diff --git a/kazoo/recipe/lease.py b/kazoo/recipe/lease.py index 1e4c9cf8..ace93183 100644 --- a/kazoo/recipe/lease.py +++ b/kazoo/recipe/lease.py @@ -25,7 +25,7 @@ class Lease(TypedDict): end: str -class NonBlockingLease(object): +class NonBlockingLease: """Exclusive lease that does not block. An exclusive lease ensures that only one client at a time owns the lease. @@ -133,7 +133,7 @@ def __bool__(self) -> bool: return self.obtained -class MultiNonBlockingLease(object): +class MultiNonBlockingLease: """Exclusive lease for multiple clients. This type of lease is useful when a limited set of hosts should run a diff --git a/kazoo/recipe/lock.py b/kazoo/recipe/lock.py index cf08e257..da30cf43 100644 --- a/kazoo/recipe/lock.py +++ b/kazoo/recipe/lock.py @@ -45,7 +45,7 @@ from kazoo.client import KazooClient -class _Watch(object): +class _Watch: def __init__(self, duration: float | None = None): self.duration = duration self.started_at: float | None = None @@ -70,7 +70,7 @@ def leftover(self) -> float | None: return max(0, self.duration - elapsed) -class Lock(object): +class Lock: """Kazoo Lock Example usage with a :class:`~kazoo.client.KazooClient` instance: @@ -503,7 +503,7 @@ class ReadLock(Lock): _EXCLUDE_NAMES = ["__lock__"] -class Semaphore(object): +class Semaphore: """A Zookeeper-based Semaphore This synchronization primitive operates in the same manner as the diff --git a/kazoo/recipe/party.py b/kazoo/recipe/party.py index 1fc1340b..a51fc2a8 100644 --- a/kazoo/recipe/party.py +++ b/kazoo/recipe/party.py @@ -19,7 +19,7 @@ from kazoo.client import KazooClient -class BaseParty(object): +class BaseParty: """Base implementation of a party.""" def __init__( diff --git a/kazoo/recipe/queue.py b/kazoo/recipe/queue.py index 85a86676..8ca31ad3 100644 --- a/kazoo/recipe/queue.py +++ b/kazoo/recipe/queue.py @@ -23,7 +23,7 @@ from kazoo.client import KazooClient -class BaseQueue(object): +class BaseQueue: """A common base class for queue implementations.""" def __init__(self, client: KazooClient, path: str): @@ -74,12 +74,12 @@ def __init__(self, client: KazooClient, path: str): :param client: A :class:`~kazoo.client.KazooClient` instance. :param path: The queue path to use in ZooKeeper. """ - super(Queue, self).__init__(client, path) + super().__init__(client, path) self._children: list[str] = [] def __len__(self) -> int: """Return queue size.""" - return super(Queue, self).__len__() + return super().__len__() def get(self) -> bytes | None: """ @@ -162,7 +162,7 @@ def __init__(self, client: KazooClient, path: str): :param client: A :class:`~kazoo.client.KazooClient` instance. :param path: The queue path to use in ZooKeeper. """ - super(LockingQueue, self).__init__(client, path) + super().__init__(client, path) self.id = uuid.uuid4().hex.encode() self.processing_element: tuple[str, bytes] | None = None self._lock_path = self.path + self.lock @@ -174,7 +174,7 @@ def __len__(self) -> int: :returns: queue size (includes locked entries count). """ - return super(LockingQueue, self).__len__() + return super().__len__() def put(self, value: bytes, priority: int = 100) -> None: """Put an entry into the queue. diff --git a/kazoo/recipe/watchers.py b/kazoo/recipe/watchers.py index 77f54547..abc92d83 100644 --- a/kazoo/recipe/watchers.py +++ b/kazoo/recipe/watchers.py @@ -66,7 +66,7 @@ def wrapper(*args: GenericArgs.args, **kwargs: GenericArgs.kwargs) -> None: ] -class DataWatch(object): +class DataWatch: """Watches a node for data updates and calls the specified function each time it changes @@ -302,7 +302,7 @@ def _session_watcher(self, state: KazooState) -> None: ] -class ChildrenWatch(object): +class ChildrenWatch: """Watches a node for children updates and calls the specified function each time it changes @@ -465,7 +465,7 @@ def _session_watcher(self, state: KazooState) -> None: self._client.handler.spawn(self._get_children) -class PatientChildrenWatch(object): +class PatientChildrenWatch: """Patient Children Watch that returns values after the children of a node don't change for a period of time diff --git a/kazoo/retry.py b/kazoo/retry.py index 9e4e0c9a..c317da38 100644 --- a/kazoo/retry.py +++ b/kazoo/retry.py @@ -31,7 +31,7 @@ class InterruptedError(RetryFailedError): function""" -class KazooRetry(object): +class KazooRetry: """Helper for retrying a method in the face of retry-able exceptions""" diff --git a/kazoo/security.py b/kazoo/security.py index 1b383795..8f4ca912 100644 --- a/kazoo/security.py +++ b/kazoo/security.py @@ -51,7 +51,7 @@ def __repr__(self) -> str: ) -class Permissions(object): +class Permissions: READ = 1 WRITE = 2 CREATE = 4 diff --git a/kazoo/testing/common.py b/kazoo/testing/common.py index 883e38b4..0da736b9 100644 --- a/kazoo/testing/common.py +++ b/kazoo/testing/common.py @@ -80,7 +80,7 @@ def to_java_compatible_path(path: str) -> str: ) -class ManagedZooKeeper(object): +class ManagedZooKeeper: """Class to manage the running of a ZooKeeper instance for testing. Note: no attempt is made to probe the ZooKeeper instance is @@ -350,13 +350,13 @@ def destroy(self) -> None: def get_logs(self, num_lines: int = 100) -> list[str]: log_path = pathlib.Path(self.working_path, "zookeeper.log") if log_path.exists(): - log_file = log_path.open("r") - lines = log_file.readlines() + with log_path.open("r") as log_file: + lines = log_file.readlines() return lines[-num_lines:] return [] -class ZookeeperCluster(object): +class ZookeeperCluster: def __init__( self, install_path: str, diff --git a/kazoo/testing/harness.py b/kazoo/testing/harness.py index 6454242b..5a3a55a0 100644 --- a/kazoo/testing/harness.py +++ b/kazoo/testing/harness.py @@ -67,7 +67,7 @@ def get_global_cluster() -> ZookeeperCluster: if "-" in ZK_VERSION_STR: # Ignore pre-release markers like -alpha ZK_VERSION_STR = ZK_VERSION_STR.split("-")[0] - ZK_VERSION = tuple([int(n) for n in ZK_VERSION_STR.split(".")]) + ZK_VERSION = tuple(int(n) for n in ZK_VERSION_STR.split(".")) ZK_OBSERVER_START_ID = int( # type: ignore[call-overload] cluster_conf.get("ZOOKEEPER_OBSERVER_START_ID") ) @@ -173,7 +173,7 @@ def test_something_else(self) -> None: DEFAULT_CLIENT_TIMEOUT = 15 def __init__(self, *args: Any, **kw: Any): - super(KazooTestHarness, self).__init__(*args, **kw) + super().__init__(*args, **kw) self._client: KazooClient | None = None self._clients: list[KazooClient] = [] diff --git a/kazoo/tests/test_cache.py b/kazoo/tests/test_cache.py index 4bb9d791..4a5441e9 100644 --- a/kazoo/tests/test_cache.py +++ b/kazoo/tests/test_cache.py @@ -63,7 +63,7 @@ def choose_an_installed_handler( class KazooTreeCacheTests(KazooAdaptiveHandlerTestCase): def setUp(self) -> None: - super(KazooTreeCacheTests, self).setUp() + super().setUp() self._event_queue: Queue[TreeEvent] = self.client.handler.queue_impl() self._error_queue = self.client.handler.queue_impl() self._path: str | None = None @@ -78,7 +78,7 @@ def tearDown(self) -> None: if self._cache is not None: self._cache.close() self._cache = None - super(KazooTreeCacheTests, self).tearDown() + super().tearDown() def make_cache(self) -> TreeCache: if self._cache is None: diff --git a/kazoo/tests/test_connection.py b/kazoo/tests/test_connection.py index 707c17bb..5439cd0b 100644 --- a/kazoo/tests/test_connection.py +++ b/kazoo/tests/test_connection.py @@ -350,7 +350,7 @@ def listen(state: KazooState) -> bool | None: class TestUnorderedXids(KazooTestCase): def setUp(self) -> None: - super(TestUnorderedXids, self).setUp() + super().setUp() self.connection = self.client._connection self.connection_routine = self.connection._connection_routine @@ -360,7 +360,7 @@ def setUp(self) -> None: def tearDown(self) -> None: self.client._pending = self._pending - super(TestUnorderedXids, self).tearDown() + super().tearDown() def _get_client(self, **kwargs: Any) -> KazooClient: # overrides for patching zk_loop @@ -406,7 +406,7 @@ def log_exception(*args: Any) -> None: ev.wait() self.client.remove_listener(listen) assert self.client.connected is False - assert self.client.state == "LOST" + assert self.client.state == KazooState.LOST assert self.client.client_state == KeeperState.CLOSED args, exc_info = error_stack[-1] diff --git a/kazoo/tests/test_election.py b/kazoo/tests/test_election.py index 8e8999c7..fda3d297 100644 --- a/kazoo/tests/test_election.py +++ b/kazoo/tests/test_election.py @@ -22,7 +22,7 @@ class UniqueError(Exception): class KazooElectionTests(KazooTestCase): def setUp(self) -> None: - super(KazooElectionTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex self.condition = threading.Condition() diff --git a/kazoo/tests/test_gevent_handler.py b/kazoo/tests/test_gevent_handler.py index c0c98d92..fb897987 100644 --- a/kazoo/tests/test_gevent_handler.py +++ b/kazoo/tests/test_gevent_handler.py @@ -8,7 +8,7 @@ from kazoo.exceptions import NoNodeError from kazoo.handlers.utils import create_tcp_socket -from kazoo.protocol.states import Callback, ZnodeStat +from kazoo.protocol.states import Callback, KazooState, ZnodeStat from kazoo.testing import KazooTestCase try: @@ -90,13 +90,13 @@ def _getEvent(self) -> Type[Event]: def test_start(self) -> None: client = self._get_client(handler=self._makeOne()) client.start() - assert client.state == "CONNECTED" + assert client.state == KazooState.CONNECTED client.stop() def test_start_stop_double(self) -> None: client = self._get_client(handler=self._makeOne()) client.start() - assert client.state == "CONNECTED" + assert client.state == KazooState.CONNECTED client.handler.start() client.handler.stop() client.stop() @@ -104,7 +104,7 @@ def test_start_stop_double(self) -> None: def test_basic_commands(self) -> None: client = self._get_client(handler=self._makeOne()) client.start() - assert client.state == "CONNECTED" + assert client.state == KazooState.CONNECTED client.create("/anode", b"fred") assert client.get("/anode")[0] == b"fred" assert client.delete("/anode") diff --git a/kazoo/tests/test_lease.py b/kazoo/tests/test_lease.py index 2b8cadb3..cef9d85a 100644 --- a/kazoo/tests/test_lease.py +++ b/kazoo/tests/test_lease.py @@ -9,7 +9,7 @@ from kazoo.testing import KazooTestCase -class MockClock(object): +class MockClock: def __init__(self, epoch: float = 0): self.epoch = epoch @@ -22,7 +22,7 @@ def __call__(self) -> datetime.datetime: class KazooLeaseTests(KazooTestCase): def setUp(self) -> None: - super(KazooLeaseTests, self).setUp() + super().setUp() self.client2 = self._get_client(timeout=0.8) self.client2.start() self.client3 = self._get_client(timeout=0.8) diff --git a/kazoo/tests/test_lock.py b/kazoo/tests/test_lock.py index e3c68add..1ba1327a 100644 --- a/kazoo/tests/test_lock.py +++ b/kazoo/tests/test_lock.py @@ -22,7 +22,7 @@ from types import TracebackType -class SleepBarrier(object): +class SleepBarrier: """A crappy spinning barrier.""" def __init__(self, wait_for: int, sleep_func: Callable[..., None]): @@ -55,11 +55,11 @@ class KazooLockTests(KazooTestCase): thread_count = 20 def __init__(self, *args: None, **kw: None): - super(KazooLockTests, self).__init__(*args, **kw) + super().__init__(*args, **kw) self.threads_made: list[threading.Thread] = [] def tearDown(self) -> None: - super(KazooLockTests, self).tearDown() + super().tearDown() while self.threads_made: t = self.threads_made.pop() t.join() @@ -83,7 +83,7 @@ def make_wait() -> test_util.Wait: return test_util.Wait() def setUp(self) -> None: - super(KazooLockTests, self).setUp() + super().setUp() self.lockpath = "/" + uuid.uuid4().hex self.condition = self.make_condition() self.released = self.make_event() @@ -556,11 +556,11 @@ def test_rw_lock(self) -> None: class TestSemaphore(KazooTestCase): def __init__(self, *args: Any, **kw: Any): - super(TestSemaphore, self).__init__(*args, **kw) + super().__init__(*args, **kw) self.threads_made: list[threading.Thread] = [] def tearDown(self) -> None: - super(TestSemaphore, self).tearDown() + super().tearDown() while self.threads_made: t = self.threads_made.pop() t.join() @@ -580,7 +580,7 @@ def make_thread(self, *args: Any, **kwargs: Any) -> threading.Thread: return t def setUp(self) -> None: - super(TestSemaphore, self).setUp() + super().setUp() self.lockpath = "/" + uuid.uuid4().hex self.condition = self.make_condition() self.released = self.make_event() diff --git a/kazoo/tests/test_partitioner.py b/kazoo/tests/test_partitioner.py index e8397f9f..35f7f484 100644 --- a/kazoo/tests/test_partitioner.py +++ b/kazoo/tests/test_partitioner.py @@ -63,7 +63,7 @@ def make_event() -> threading.Event: return threading.Event() def setUp(self) -> None: - super(KazooPartitionerTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex self.__partitioners: list[Partitioner] = [] diff --git a/kazoo/tests/test_party.py b/kazoo/tests/test_party.py index f503eb33..295f2c65 100644 --- a/kazoo/tests/test_party.py +++ b/kazoo/tests/test_party.py @@ -7,7 +7,7 @@ class KazooPartyTests(KazooTestCase): def setUp(self) -> None: - super(KazooPartyTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex def test_party(self) -> None: @@ -57,7 +57,7 @@ def test_party_vanishing_node(self) -> None: class KazooShallowPartyTests(KazooTestCase): def setUp(self) -> None: - super(KazooShallowPartyTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex def test_party(self) -> None: diff --git a/kazoo/tests/test_selectors_select.py b/kazoo/tests/test_selectors_select.py index fd30bdb3..fc345b29 100644 --- a/kazoo/tests/test_selectors_select.py +++ b/kazoo/tests/test_selectors_select.py @@ -7,6 +7,7 @@ import os import socket +import subprocess import sys import unittest @@ -58,21 +59,32 @@ def test_returned_list_identity(self) -> None: def test_select(self) -> None: cmd = "for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done" - p = os.popen(cmd, "r") - for tout in (0, 1, 2, 4, 8, 16) + (None,) * 10: - rfd, wfd, xfd = select([cast("HasFileNo", p)], [], [], tout) - if (rfd, wfd, xfd) == ([], [], []): - continue - if (rfd, wfd, xfd) == ([cast("HasFileNo", p)], [], []): - line = p.readline() - if not line: - break - continue - self.fail( - "Unexpected return values from select(): %s %s %s" - % (rfd, wfd, xfd) - ) - p.close() + with subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + text=True, + ) as process: + assert process.stdout is not None + for tout in (0, 1, 2, 4, 8, 16) + (None,) * 10: + rfd, wfd, xfd = select( + [cast("HasFileNo", process.stdout)], [], [], tout + ) + if (rfd, wfd, xfd) == ([], [], []): + continue + if (rfd, wfd, xfd) == ( + [cast("HasFileNo", process.stdout)], + [], + [], + ): + line = process.stdout.readline() + if not line: + break + continue + self.fail( + "Unexpected return values from select(): %s %s %s" + % (rfd, wfd, xfd) + ) # Issue 16230: Crash on select resized list def test_select_mutated(self) -> None: diff --git a/kazoo/tests/test_utils.py b/kazoo/tests/test_utils.py index b686cabd..50c7cbbf 100644 --- a/kazoo/tests/test_utils.py +++ b/kazoo/tests/test_utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import errno import ssl import socket import time @@ -100,6 +101,20 @@ def test_timeout_arg_eventlet(self) -> None: timeout = call_args[0][1] assert timeout >= 0, "socket timeout must be nonnegative" + def test_interrupted_error_retries(self) -> None: + with patch.object(utils, "_set_default_tcpsock_options"): + with patch.object( + socket, + "create_connection", + side_effect=[ + InterruptedError(errno.EINTR, "interrupted"), + object(), + ], + ) as create_connection: + create_tcp_connection(socket, ("127.0.0.1", 2181)) + + assert create_connection.call_count == 2 + def test_slow_connect(self) -> None: # Currently, create_tcp_connection will raise a socket timeout if it # takes longer than the specified "timeout" to create a connection. diff --git a/kazoo/tests/test_watchers.py b/kazoo/tests/test_watchers.py index e0852a18..8ce47762 100644 --- a/kazoo/tests/test_watchers.py +++ b/kazoo/tests/test_watchers.py @@ -17,7 +17,7 @@ class KazooDataWatcherTests(KazooTestCase): def setUp(self) -> None: - super(KazooDataWatcherTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex self.client.ensure_path(self.path) @@ -295,7 +295,7 @@ def changed(val: bytes | None, stat: ZnodeStat | None) -> None: class KazooChildrenWatcherTests(KazooTestCase): def setUp(self) -> None: - super(KazooChildrenWatcherTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex self.client.ensure_path(self.path) @@ -524,7 +524,7 @@ def changed(children: list[str] | None) -> None: class KazooPatientChildrenWatcherTests(KazooTestCase): def setUp(self) -> None: - super(KazooPatientChildrenWatcherTests, self).setUp() + super().setUp() self.path = "/" + uuid.uuid4().hex def _makeOne(self, *args: Any, **kwargs: Any) -> PatientChildrenWatch: diff --git a/kazoo/tests/util.py b/kazoo/tests/util.py index c6211238..81c3ed6b 100644 --- a/kazoo/tests/util.py +++ b/kazoo/tests/util.py @@ -28,7 +28,7 @@ if "-" in has_version: # Ignore pre-release markers like -alpha has_version = has_version.split("-")[0] - CI_ZK_VERSION = tuple([int(n) for n in has_version.split(".")]) + CI_ZK_VERSION = tuple(int(n) for n in has_version.split(".")) class Handler(logging.Handler): @@ -89,7 +89,7 @@ def __init__(self, *names: Any, **kw: Any): self.install() -class Wait(object): +class Wait: class TimeOutWaitingFor(Exception): "A test condition timed out" diff --git a/tox.ini b/tox.ini index 4de71a0b..ab62ae26 100644 --- a/tox.ini +++ b/tox.ini @@ -42,7 +42,6 @@ commands = [testenv:build] [testenv:pep8] -basepython = python3 extras = alldeps deps = flake8 @@ -50,7 +49,6 @@ usedevelop = True commands = flake8 {posargs} {toxinidir}/kazoo [testenv:black] -basepython = python3 extras = deps = black @@ -58,7 +56,6 @@ usedevelop = True commands = black --check {posargs: {toxinidir}/kazoo {toxinidir}/kazoo} [testenv:mypy] -basepython = python3 extras = alldeps deps = mypy