Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,14 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "pypy-3.11-v7.3.21"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "pypy-3.11-v7.3.21"]
# Friendly note: If you change the minimum zk-version here, update it in
# ensure-zookeeper-env.sh. Additionally, if you need to change the way that
# zookeeper is installed, do it THERE. Not in the 'test with tox' step here.
# That way, people trying to test changes have a reasonable chance of getting
# things to work properly before submitting a PR.
zk-version: ["3.6.4", "3.7.2", "3.8.3", "3.9.1"]
include:
- python-version: "3.9"
tox-env: py39
- python-version: "3.10"
tox-env: py310
- python-version: "3.11"
Expand Down
61 changes: 23 additions & 38 deletions kazoo/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,16 @@

from __future__ import annotations

from collections import defaultdict, deque
from functools import partial
import inspect
import logging
from os.path import split
import re
import warnings
from typing import (
cast,
overload,
Any,
Callable,
Deque,
Iterable,
Literal,
Optional,
Sequence,
Set,
TypedDict,
TYPE_CHECKING,
)
from collections import defaultdict, deque
from collections.abc import Callable, Iterable, Sequence
from functools import partial
from os.path import split
from typing import TYPE_CHECKING, Any, Literal, TypedDict, cast, overload

from typing_extensions import ParamSpec, Unpack, deprecated

from kazoo.exceptions import (
Expand All @@ -31,8 +20,8 @@
ConnectionClosedError,
ConnectionLoss,
KazooException,
NoNodeError,
NodeExistsError,
NoNodeError,
SessionExpiredError,
WriterNotClosedException,
)
Expand All @@ -50,12 +39,12 @@
Create2,
Delete,
Exists,
GetACL,
GetChildren,
GetChildren2,
GetACL,
SetACL,
GetData,
Reconfig,
SetACL,
SetData,
Sync,
Transaction,
Expand All @@ -67,25 +56,26 @@
KeeperState,
WatchedEvent,
)
from kazoo.retry import KazooRetry
from kazoo.security import ACL, OPEN_ACL_UNSAFE

# convenience API
from kazoo.recipe.barrier import Barrier, DoubleBarrier
from kazoo.recipe.counter import Counter
from kazoo.recipe.election import Election
from kazoo.recipe.lease import NonBlockingLease, MultiNonBlockingLease
from kazoo.recipe.lock import Lock, ReadLock, WriteLock, Semaphore
from kazoo.recipe.lease import MultiNonBlockingLease, NonBlockingLease
from kazoo.recipe.lock import Lock, ReadLock, Semaphore, WriteLock
from kazoo.recipe.partitioner import SetPartitioner
from kazoo.recipe.party import Party, ShallowParty
from kazoo.recipe.queue import Queue, LockingQueue
from kazoo.recipe.queue import LockingQueue, Queue
from kazoo.recipe.watchers import ChildrenWatch, DataWatch
from kazoo.retry import KazooRetry
from kazoo.security import ACL, OPEN_ACL_UNSAFE

if TYPE_CHECKING:
from types import TracebackType

from kazoo.handlers.gevent import SequentialGeventHandler
from kazoo.interfaces import Event, IAsyncResult, IHandler
from kazoo.protocol.states import ZnodeStat
from kazoo.handlers.gevent import SequentialGeventHandler


CLOSED_STATES = (
Expand Down Expand Up @@ -121,10 +111,10 @@ class LegacyRetryParams(TypedDict, total=False):


# Signature for functions called by add_listener
ListenerFunc = Callable[[KazooState], Optional[bool]]
ListenerFunc = Callable[[KazooState], bool | None]

# Signatures for get, get_children and exists watches
WatchFunc = Callable[[WatchedEvent], Optional[bool]]
WatchFunc = Callable[[WatchedEvent], bool | None]

GenericArgs = ParamSpec("GenericArgs")

Expand Down Expand Up @@ -369,10 +359,10 @@ def __init__(
self._state: KeeperState = KeeperState.CLOSED
self.state: KazooState = KazooState.LOST
self.state_listeners: set[ListenerFunc] = set()
self._child_watchers: defaultdict[str, Set[WatchFunc]] = defaultdict(
self._child_watchers: defaultdict[str, set[WatchFunc]] = defaultdict(
set
)
self._data_watchers: defaultdict[str, Set[WatchFunc]] = defaultdict(
self._data_watchers: defaultdict[str, set[WatchFunc]] = defaultdict(
set
)
self._reset()
Expand Down Expand Up @@ -551,8 +541,8 @@ def _retry(

def _reset(self) -> None:
"""Resets a variety of client states for a new connection."""
self._queue: Deque[tuple[Any, IAsyncResult]] = deque()
self._pending: Deque[tuple[Any, IAsyncResult, int]] = deque()
self._queue: deque[tuple[Any, IAsyncResult]] = deque()
self._pending: deque[tuple[Any, IAsyncResult, int]] = deque()

self._reset_watchers()
self._reset_session()
Expand Down Expand Up @@ -1274,12 +1264,7 @@ def do_create() -> None:
result = self._create_async_inner(
path,
value,
# The way acl is constructed ends up confusing mypy, which
# thinks that acl can be None here, even though the code
# above ensures that if acl is None, it gets set to
# OPEN_ACL_UNSAFE, so we ignore the type error here.
# behaves differently in python3.8 and python3.14, sigh.
acl, # type: ignore[arg-type]
acl,
flags,
trailing=sequence,
include_data=include_data,
Expand Down
10 changes: 5 additions & 5 deletions kazoo/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from collections import defaultdict
from typing import Callable, Type
from collections.abc import Callable


class KazooException(Exception):
Expand Down Expand Up @@ -54,19 +54,19 @@ class SASLException(KazooException):
"""


def _invalid_error_code() -> Type[ZookeeperError]:
def _invalid_error_code() -> type[ZookeeperError]:
raise RuntimeError("Invalid error code")


EXCEPTIONS: defaultdict[int, Type[ZookeeperError]] = defaultdict(
EXCEPTIONS: defaultdict[int, type[ZookeeperError]] = defaultdict(
_invalid_error_code
)


def _zookeeper_exception(
code: int,
) -> Callable[[Type[ZookeeperError]], Type[ZookeeperError]]:
def decorator(klass: Type[ZookeeperError]) -> Type[ZookeeperError]:
) -> Callable[[type[ZookeeperError]], type[ZookeeperError]]:
def decorator(klass: type[ZookeeperError]) -> type[ZookeeperError]:
EXCEPTIONS[code] = klass
# Unfortunately there is currently no good of doing the assignment here
# in a way that type checkers would allow. It's a known problem (see
Expand Down
19 changes: 8 additions & 11 deletions kazoo/handlers/eventlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
import atexit
import contextlib
import logging

from typing import cast, Any, Generator, TYPE_CHECKING
from collections.abc import Generator
from typing import TYPE_CHECKING, Any, cast

import eventlet
from eventlet import queue as green_queue
from eventlet.green import selectors as green_selectors
from eventlet.green import socket as green_socket
from eventlet.green import time as green_time
from eventlet.green import threading as green_threading
from eventlet.green import selectors as green_selectors
from eventlet import queue as green_queue
from eventlet.green import time as green_time

from kazoo.handlers import utils
from kazoo.handlers.utils import selector_select
Expand Down Expand Up @@ -107,11 +107,8 @@ def __init__(self) -> None:
self.completion_queue = (
self.queue_impl() # type: ignore[no-untyped-call]
)
self._workers: list[ # type: ignore[name-defined]
tuple[
eventlet.GreenThread,
green_queue.LightQueue,
]
self._workers: list[
tuple[eventlet.greenthread.GreenThread, green_queue.LightQueue]
] = []
self._started = False

Expand Down Expand Up @@ -177,7 +174,7 @@ def stop(self) -> None:
while self._workers:
w, q = self._workers.pop()
q.put(_STOP) # type: ignore[no-untyped-call]
w.wait()
w.wait() # type: ignore[no-untyped-call]
self._started = False
atexit.unregister(self.stop)

Expand Down
27 changes: 13 additions & 14 deletions kazoo/handlers/gevent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,29 @@

import atexit
import logging

from typing import Any, Callable, Iterable, TYPE_CHECKING, cast


from kazoo.handlers.utils import selector_select
from kazoo.handlers import utils
from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING, Any, cast

# FIXME This is messy.
# We don't want to force the user to install gevent, so we need to handle the
# case where it's not available, but there should be a cleaner we of doing this
# than by importing all of gevent and ignoring all the import errors.
import gevent # type: ignore[import]
from gevent import socket # type: ignore[import]
import gevent.event # type: ignore[import]
import gevent.queue # type: ignore[import]
import gevent
import gevent.event
import gevent.queue
import gevent.selectors
import gevent.thread
from gevent import socket
from gevent.lock import RLock, Semaphore

import gevent.thread # type: ignore[import]
import gevent.selectors # type: ignore[import]
from gevent.lock import Semaphore, RLock # type: ignore[import]
from kazoo.handlers import utils
from kazoo.handlers.utils import selector_select

if TYPE_CHECKING:
from gevent import Greenlet

from kazoo.interfaces import FdLike, Lockable, Socket
from kazoo.protocol.states import Callback
from gevent import Greenlet

_using_libevent = gevent.__version__.startswith("0.")

Expand Down
4 changes: 2 additions & 2 deletions kazoo/handlers/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import socket
import threading
import time

from typing import Any, Callable, Iterable, TYPE_CHECKING, cast
from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING, Any, cast

from kazoo.handlers import utils
from kazoo.handlers.utils import selector_select
Expand Down
13 changes: 8 additions & 5 deletions kazoo/handlers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@

from __future__ import annotations

from collections import defaultdict
import errno
import functools
import select
import selectors
import ssl
import socket
import ssl
import time
from typing import Any, Callable, Iterable, TypeVar, TYPE_CHECKING
from collections import defaultdict
from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING, Any, TypeVar

from typing_extensions import ParamSpec

from kazoo.interfaces import IAsyncResult, FdLike
from kazoo.interfaces import FdLike, IAsyncResult

if TYPE_CHECKING:
from types import ModuleType

from kazoo.interfaces import Socket

HAS_FNCTL = True
Expand Down Expand Up @@ -50,7 +53,7 @@ def __init__(
self._condition = condition_factory()
self._callbacks: list[CallbackFunc] = []
self._timeout_factory = timeout_factory
self.value = None
self.value: Any = None

def ready(self) -> bool:
"""Return true if and only if it holds a value or an
Expand Down
18 changes: 6 additions & 12 deletions kazoo/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,13 @@

from __future__ import annotations


from typing import (
Any,
Callable,
Iterable,
Protocol,
Union,
TYPE_CHECKING,
)
from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING, Any, Protocol

if TYPE_CHECKING:
from types import TracebackType
import queue
from types import TracebackType

from kazoo.protocol.states import Callback

# public API
Expand All @@ -34,7 +28,7 @@ class HasFileNo(Protocol):
def fileno(self) -> int: ...


FdLike = Union[int, HasFileNo]
FdLike = int | HasFileNo


class Socket(HasFileNo, Protocol):
Expand Down Expand Up @@ -70,7 +64,7 @@ def shutdown(self, flag: int) -> None: ...
class Lockable(Protocol):
"""This is what threading.Lock implements.

In python 3.9+ it's available natively. Though given it has some
In python 3.10+ it's available natively. Though given it has some
very odd typing, I wouldn't put money on it.
"""

Expand Down
Loading
Loading