Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-kazoo for openSUSE:Factory checked in at 2026-03-23 17:15:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-kazoo (Old) and /work/SRC/openSUSE:Factory/.python-kazoo.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-kazoo" Mon Mar 23 17:15:05 2026 rev:19 rq:1341999 version:2.11.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-kazoo/python-kazoo.changes 2025-06-30 13:07:21.564075969 +0200 +++ /work/SRC/openSUSE:Factory/.python-kazoo.new.8177/python-kazoo.changes 2026-03-23 17:17:18.503506752 +0100 @@ -1,0 +2,20 @@ +Mon Mar 23 10:09:13 UTC 2026 - Dirk Müller <[email protected]> + +- update to 2.11.0: + * bump deps for Python > 3.8 + * add Python 3.13 & 3.14 + * be a little more verbose about ZK download URL + * removing tiny remaining bits of Python2 hybridation + * add support for SNI + * Proper retry count in KazooRetry + * Revert "Fix possible endless wait in stop() after AUTH_FAILED + error (#688)" + * prefer use of `time.monotonic` (b00d88ff, closes #722) + * Add missing Zookeeper exceptions codes + * fix spelling + * **test:** avoid racy reader vs writer contender in + `test_rw_lock` + * **testing:** follow redirect when downloading ZK and use + https + +------------------------------------------------------------------- Old: ---- kazoo-2.10.0.tar.gz New: ---- kazoo-2.11.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-kazoo.spec ++++++ --- /var/tmp/diff_new_pack.DJvr3v/_old 2026-03-23 17:17:19.231537030 +0100 +++ /var/tmp/diff_new_pack.DJvr3v/_new 2026-03-23 17:17:19.231537030 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-kazoo # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,23 +18,21 @@ %{?sle15_python_module_pythons} Name: python-kazoo -Version: 2.10.0 +Version: 2.11.0 Release: 0 Summary: Higher Level Zookeeper Client License: Apache-2.0 URL: https://github.com/python-zk/kazoo Source: https://files.pythonhosted.org/packages/source/k/kazoo/kazoo-%{version}.tar.gz BuildRequires: %{python_module pip} -BuildRequires: %{python_module setuptools} +BuildRequires: %{python_module setuptools >= 46.4.0} BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros -Suggests: python-pure-sasl +Suggests: python-eventlet >= 0.17.1 +Suggests: python-gevent >= 1.2 +Suggests: python-pure-sasl >= 0.5.1 BuildArch: noarch -%ifpython2 -Requires: python-eventlet >= 0.17.1 -Requires: python-gevent >= 1.2 -%endif %python_subpackages %description ++++++ kazoo-2.10.0.tar.gz -> kazoo-2.11.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/CHANGES.md new/kazoo-2.11.0/CHANGES.md --- old/kazoo-2.10.0/CHANGES.md 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/CHANGES.md 2026-03-21 20:08:44.000000000 +0100 @@ -1,3 +1,29 @@ +<a name="2.11.0"></a> +## 2.11.0 (2026-03-21) + + +#### Features + +* **testing:** + * bump deps for Python > 3.8 ([43e6f068](https://github.com/python-zk/kazoo/commit/43e6f0682d12893e983213db3bb7927f448ae03d)) + * add Python 3.13 & 3.14 ([b385289e](https://github.com/python-zk/kazoo/commit/b385289ed68bf791824379733e9dc80bf26ba5a9)) + * be a little more verbose about ZK download URL ([4ed8a304](https://github.com/python-zk/kazoo/commit/4ed8a304118c98cfe6594e441bf9fa09b575a186)) +* **core:** + * removing tiny remaining bits of Python2 hybridation ([0751174](https://github.com/python-zk/kazoo/commit/0751174)) + * add support for SNI ([273bd56](https://github.com/python-zk/kazoo/commit/273bd56)) + +#### Bug Fixes + +* **core:** + * Proper retry count in KazooRetry ([73309b2d](https://github.com/python-zk/kazoo/commit/73309b2d456c8e64f4ceb079f98903fc9e45f3b6)) + * Revert "Fix possible endless wait in stop() after AUTH_FAILED error (#688)" ([2fb93a87](https://github.com/python-zk/kazoo/commit/2fb93a87d3648e2dece5698cb64b059da5134a57)) + * prefer use of `time.monotonic` ([b00d88ff](https://github.com/python-zk/kazoo/commit/b00d88ff1485f1cb175565c49955bf5d7ce96fef), closes [#722](https://github.com/python-zk/kazoo/issues/722)) + * Add missing Zookeeper exceptions codes ([4c6bad82](https://github.com/python-zk/kazoo/commit/4c6bad82ebe347b9e51abbf33cef443057dc1c45)) + * fix spelling ([686d770](https://github.com/python-zk/kazoo/commit/686d770)) + +* **test:** avoid racy reader vs writer contender in `test_rw_lock` ([6540c932](https://github.com/python-zk/kazoo/commit/6540c932505a988ccae3c77c023113d4c4c01947)) +* **testing:** follow redirect when downloading ZK and use https ([b4155ea0](https://github.com/python-zk/kazoo/commit/b4155ea07ba671ce98bb63cebb8dfcd42748efd3)) + <a name="2.10.0"></a> ## 2.10.0 (2024-01-28) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/PKG-INFO new/kazoo-2.11.0/PKG-INFO --- old/kazoo-2.10.0/PKG-INFO 2024-01-28 21:01:53.313537000 +0100 +++ new/kazoo-2.11.0/PKG-INFO 2026-03-21 20:08:49.019431400 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: kazoo -Version: 2.10.0 +Version: 2.11.0 Summary: "Higher Level Zookeeper Client" Home-page: https://kazoo.readthedocs.io Author: Kazoo team @@ -23,6 +23,8 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Communications @@ -36,6 +38,7 @@ Requires-Dist: objgraph; extra == "test" Requires-Dist: pytest; extra == "test" Requires-Dist: pytest-cov; extra == "test" +Requires-Dist: pytest-timeout; extra == "test" Requires-Dist: gevent>=1.2; implementation_name != "pypy" and extra == "test" Requires-Dist: eventlet>=0.17.1; implementation_name != "pypy" and extra == "test" Requires-Dist: pyjks; extra == "test" @@ -59,6 +62,7 @@ Requires-Dist: Sphinx>=1.2.2; extra == "alldeps" Requires-Dist: sphinx-autodoc-typehints>=1; extra == "alldeps" Requires-Dist: mypy>=0.991; extra == "alldeps" +Dynamic: license-file Kazoo ===== @@ -68,7 +72,7 @@ [](https://houndci.com) `kazoo` implements a higher level API to [Apache -Zookeeper](http://zookeeper.apache.org/) for Python clients. +ZooKeeper](http://zookeeper.apache.org/) for Python clients. See [the full docs](http://kazoo.rtfd.org/) for more information. @@ -87,6 +91,32 @@ Corporation](http://zope.com/). It has since gathered an active community of over one hundred contributors. +<a name="2.11.0"></a> +## 2.11.0 (2026-03-21) + + +#### Features + +* **testing:** + * bump deps for Python > 3.8 ([43e6f068](https://github.com/python-zk/kazoo/commit/43e6f0682d12893e983213db3bb7927f448ae03d)) + * add Python 3.13 & 3.14 ([b385289e](https://github.com/python-zk/kazoo/commit/b385289ed68bf791824379733e9dc80bf26ba5a9)) + * be a little more verbose about ZK download URL ([4ed8a304](https://github.com/python-zk/kazoo/commit/4ed8a304118c98cfe6594e441bf9fa09b575a186)) +* **core:** + * removing tiny remaining bits of Python2 hybridation ([0751174](https://github.com/python-zk/kazoo/commit/0751174)) + * add support for SNI ([273bd56](https://github.com/python-zk/kazoo/commit/273bd56)) + +#### Bug Fixes + +* **core:** + * Proper retry count in KazooRetry ([73309b2d](https://github.com/python-zk/kazoo/commit/73309b2d456c8e64f4ceb079f98903fc9e45f3b6)) + * Revert "Fix possible endless wait in stop() after AUTH_FAILED error (#688)" ([2fb93a87](https://github.com/python-zk/kazoo/commit/2fb93a87d3648e2dece5698cb64b059da5134a57)) + * prefer use of `time.monotonic` ([b00d88ff](https://github.com/python-zk/kazoo/commit/b00d88ff1485f1cb175565c49955bf5d7ce96fef), closes [#722](https://github.com/python-zk/kazoo/issues/722)) + * Add missing Zookeeper exceptions codes ([4c6bad82](https://github.com/python-zk/kazoo/commit/4c6bad82ebe347b9e51abbf33cef443057dc1c45)) + * fix spelling ([686d770](https://github.com/python-zk/kazoo/commit/686d770)) + +* **test:** avoid racy reader vs writer contender in `test_rw_lock` ([6540c932](https://github.com/python-zk/kazoo/commit/6540c932505a988ccae3c77c023113d4c4c01947)) +* **testing:** follow redirect when downloading ZK and use https ([b4155ea0](https://github.com/python-zk/kazoo/commit/b4155ea07ba671ce98bb63cebb8dfcd42748efd3)) + <a name="2.10.0"></a> ## 2.10.0 (2024-01-28) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/README.md new/kazoo-2.11.0/README.md --- old/kazoo-2.10.0/README.md 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/README.md 2026-03-21 20:08:44.000000000 +0100 @@ -6,7 +6,7 @@ [](https://houndci.com) `kazoo` implements a higher level API to [Apache -Zookeeper](http://zookeeper.apache.org/) for Python clients. +ZooKeeper](http://zookeeper.apache.org/) for Python clients. See [the full docs](http://kazoo.rtfd.org/) for more information. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/client.py new/kazoo-2.11.0/kazoo/client.py --- old/kazoo-2.10.0/kazoo/client.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/client.py 2026-03-21 20:08:44.000000000 +0100 @@ -120,6 +120,7 @@ ca=None, use_ssl=False, verify_certs=True, + check_hostname=False, **kwargs, ): """Create a :class:`KazooClient` instance. All time arguments @@ -143,7 +144,7 @@ Should be a dict of SASL options passed to the underlying `pure-sasl <https://pypi.org/project/pure-sasl>`_ library. - For example using the DIGEST-MD5 mechnism: + For example using the DIGEST-MD5 mechanism: .. code-block:: python @@ -182,6 +183,8 @@ :param use_ssl: argument to control whether SSL is used or not :param verify_certs: when using SSL, argument to bypass certs verification + :param check_hostname: when using SSL, check the hostname + against the hostname in the cert Basic Example: @@ -237,6 +240,7 @@ self.use_ssl = use_ssl self.verify_certs = verify_certs + self.check_hostname = check_hostname self.certfile = certfile self.keyfile = keyfile self.keyfile_password = keyfile_password @@ -758,8 +762,10 @@ raise ConnectionLoss("No connection to server") peer = self._connection._socket.getpeername()[:2] + peer_host = self._connection._socket.getpeername()[1] sock = self.handler.create_connection( peer, + hostname=peer_host, timeout=self._session_timeout / 1000.0, use_ssl=self.use_ssl, ca=self.ca, @@ -767,6 +773,7 @@ keyfile=self.keyfile, keyfile_password=self.keyfile_password, verify_certs=self.verify_certs, + check_hostname=self.check_hostname, ) sock.sendall(cmd) result = sock.recv(8192) @@ -1599,7 +1606,7 @@ :exc:`~kazoo.exceptions.NewConfigNoQuorumError` if no quorum of new config is connected and up-to-date with the leader of last - commmitted config - try invoking reconfiguration after new servers + committed config - try invoking reconfiguration after new servers are connected and synced. :exc:`~kazoo.exceptions.ReconfigInProcessError` if another diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/exceptions.py new/kazoo-2.11.0/kazoo/exceptions.py --- old/kazoo-2.10.0/kazoo/exceptions.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/exceptions.py 2026-03-21 20:08:44.000000000 +0100 @@ -1,4 +1,5 @@ """Kazoo Exceptions""" + from collections import defaultdict @@ -66,6 +67,10 @@ return decorator +# Pulled from zookeeper-server/src/main/java/org/apache/zookeeper/ +# KeeperException.java in the Java Zookeeper server source code. + + @_zookeeper_exception(0) class RolledBackError(ZookeeperError): pass @@ -73,123 +78,183 @@ @_zookeeper_exception(-1) class SystemZookeeperError(ZookeeperError): - pass + """System and server-side errors. + This is never thrown by the server, it shouldn't be used other than to + indicate a range. Specifically error codes greater than this value, but + lesser than APIError, are system errors. + """ @_zookeeper_exception(-2) class RuntimeInconsistency(ZookeeperError): - pass + """A runtime inconsistency was found.""" @_zookeeper_exception(-3) class DataInconsistency(ZookeeperError): - pass + """A data inconsistency was found.""" @_zookeeper_exception(-4) class ConnectionLoss(ZookeeperError): - pass + """Connection to the server has been lost.""" @_zookeeper_exception(-5) class MarshallingError(ZookeeperError): - pass + """Error while marshalling or unmarshalling data.""" @_zookeeper_exception(-6) class UnimplementedError(ZookeeperError): - pass + """Operation is unimplemented.""" @_zookeeper_exception(-7) class OperationTimeoutError(ZookeeperError): - pass + """Operation timeout.""" @_zookeeper_exception(-8) class BadArgumentsError(ZookeeperError): - pass + """Invalid arguments.""" + + +@_zookeeper_exception(-12) +class UnknownSessionError(ZookeeperError): + """Unknown session (internal server use only).""" @_zookeeper_exception(-13) class NewConfigNoQuorumError(ZookeeperError): - pass + """No quorum of new config is connected and up-to-date with the leader of + last committed config - try invoking reconfiguration after new servers are + connected and synced. + """ @_zookeeper_exception(-14) class ReconfigInProcessError(ZookeeperError): - pass + """Another reconfiguration is in progress -- concurrent reconfigs not + supported (yet). + """ @_zookeeper_exception(-100) class APIError(ZookeeperError): - pass + """API errors. + This is never thrown by the server, it shouldn't be used other than to + indicate a range. Specifically error codes greater than this value are API + errors (while values less than this indicate a system error. + """ @_zookeeper_exception(-101) class NoNodeError(ZookeeperError): - pass + """Node does not exist.""" @_zookeeper_exception(-102) class NoAuthError(ZookeeperError): - pass + """Not authenticated.""" @_zookeeper_exception(-103) class BadVersionError(ZookeeperError): - pass + """Version conflict. In case of reconfiguration: reconfig requested from + config version X but last seen config has a different version Y. + """ @_zookeeper_exception(-108) class NoChildrenForEphemeralsError(ZookeeperError): - pass + """Ephemeral nodes may not have children.""" @_zookeeper_exception(-110) class NodeExistsError(ZookeeperError): - pass + """The node already exists.""" @_zookeeper_exception(-111) class NotEmptyError(ZookeeperError): - pass + """The node has children.""" @_zookeeper_exception(-112) class SessionExpiredError(ZookeeperError): - pass + """The session has been expired by the server.""" @_zookeeper_exception(-113) class InvalidCallbackError(ZookeeperError): - pass + """Invalid callback specified.""" @_zookeeper_exception(-114) class InvalidACLError(ZookeeperError): - pass + """Invalid ACL specified""" @_zookeeper_exception(-115) class AuthFailedError(ZookeeperError): - pass + """Client authentication failed.""" @_zookeeper_exception(-118) class SessionMovedError(ZookeeperError): - pass + """Session moved to another server, so operation is ignored.""" @_zookeeper_exception(-119) class NotReadOnlyCallError(ZookeeperError): - """An API call that is not read-only was used while connected to - a read-only server""" + """An API call that is not read-only was used while connected to a + read-only server. + """ + + +@_zookeeper_exception(-120) +class EphemeralOnLocalSessionError(ZookeeperError): + """Attempt to create ephemeral node on a local session.""" + + +@_zookeeper_exception(-121) +class NoWatcherError(ZookeeperError): + """Attempts to remove a non-existing watcher.""" + + +@_zookeeper_exception(-122) +class RequestTimeoutError(ZookeeperError): + """Request not completed within max allowed time.""" + + +@_zookeeper_exception(-123) +class ReconfigDisabledError(ZookeeperError): + """Attempts to perform a reconfiguration operation when reconfiguration + feature is disabled. + """ + + +@_zookeeper_exception(-124) +class SessionClosedRequireSaslError(ZookeeperError): + """The session has been closed by server because server requires client to + do authentication with configured authentication scheme at the server, but + client is not configured with required authentication scheme or configured + but authentication failed (i.e. wrong credential used.). + """ @_zookeeper_exception(-125) class QuotaExceededError(ZookeeperError): - """Exceeded the quota that was set on the path""" + """Exceeded the quota that was set on the path.""" + + +@_zookeeper_exception(-127) +class ThrottledOpError(ZookeeperError): + """Operation was throttled and not executed at all. This error code + indicates that zookeeper server is under heavy load and can't process + incoming requests at full speed; please retry with back off. + """ class ConnectionClosedError(SessionExpiredError): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/handlers/utils.py new/kazoo-2.11.0/kazoo/handlers/utils.py --- old/kazoo-2.10.0/kazoo/handlers/utils.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/handlers/utils.py 2026-03-21 20:08:44.000000000 +0100 @@ -196,6 +196,7 @@ def create_tcp_connection( module, address, + hostname=None, timeout=None, use_ssl=False, ca=None, @@ -203,6 +204,7 @@ keyfile=None, keyfile_password=None, verify_certs=True, + check_hostname=False, options=None, ciphers=None, ): @@ -212,11 +214,11 @@ # this ugliness... timeout = module.getdefaulttimeout() if timeout is not None: - end = time.time() + timeout + end = time.monotonic() + timeout sock = None while True: - timeout_at = end if end is None else end - time.time() + timeout_at = end if end is None else end - time.monotonic() # The condition is not '< 0' here because socket.settimeout treats 0 as # a special case to put the socket in non-blocking mode. if timeout_at is not None and timeout_at <= 0: @@ -237,11 +239,14 @@ # Load default CA certs context.load_default_certs(ssl.Purpose.SERVER_AUTH) + if check_hostname and not verify_certs: + raise ValueError( + "verify_certs must be True when" + + " check_hostname is True" + ) # We must set check_hostname to False prior to setting # verify_mode to CERT_NONE. - # TODO: Make hostname verification configurable as some users may - # elect to use it. - context.check_hostname = False + context.check_hostname = check_hostname context.verify_mode = ( ssl.CERT_REQUIRED if verify_certs else ssl.CERT_NONE ) @@ -258,7 +263,9 @@ addrs = socket.getaddrinfo( address[0], address[1], 0, socket.SOCK_STREAM ) - conn = context.wrap_socket(module.socket(addrs[0][0])) + conn = context.wrap_socket( + module.socket(addrs[0][0]), server_hostname=hostname + ) conn.settimeout(timeout_at) conn.connect(address) sock = conn diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/protocol/connection.py new/kazoo-2.11.0/kazoo/protocol/connection.py --- old/kazoo-2.10.0/kazoo/protocol/connection.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/protocol/connection.py 2026-03-21 20:08:44.000000000 +0100 @@ -7,7 +7,6 @@ import select import socket import ssl -import sys import time from kazoo.exceptions import ( @@ -75,16 +74,10 @@ CLOSE_RESPONSE = Close.type -if sys.version_info > (3,): # pragma: nocover - def buffer(obj, offset=0): - return memoryview(obj)[offset:] - - advance_iterator = next -else: # pragma: nocover - - def advance_iterator(it): - return it.next() +# removed from Python3+ +def buffer(obj, offset=0): + return memoryview(obj)[offset:] class RWPinger(object): @@ -109,19 +102,19 @@ def __iter__(self): if not self.last_attempt: - self.last_attempt = time.time() + self.last_attempt = time.monotonic() delay = 0.5 while True: yield self._next_server(delay) def _next_server(self, delay): jitter = random.randint(0, 100) / 100.0 - while time.time() < self.last_attempt + delay + jitter: + while time.monotonic() < self.last_attempt + delay + jitter: # Skip rw ping checks if its too soon return False for host, port in self.hosts: log.debug("Pinging server for r/w: %s:%s", host, port) - self.last_attempt = time.time() + self.last_attempt = time.monotonic() try: with self.socket_handling(): sock = self.connection((host, port)) @@ -136,7 +129,7 @@ return False # Add some jitter between host pings - while time.time() < self.last_attempt + jitter: + while time.monotonic() < self.last_attempt + jitter: return False delay *= 2 @@ -526,7 +519,7 @@ # Determine if we need to check for a r/w server if self._ro_mode: - result = advance_iterator(self._ro_mode) + result = next(self._ro_mode) if result: self._rw_server = result raise RWServerAvailable() @@ -617,14 +610,14 @@ connect_timeout = connect_timeout / 1000.0 retry.reset() self.ping_outstanding.clear() - last_send = time.time() + last_send = time.monotonic() with self._socket_error_handling(): - while not self.client._stopped.is_set(): + while True: # Watch for something to read or send jitter_time = random.randint(1, 40) / 100.0 deadline = last_send + read_timeout / 2.0 - jitter_time # Ensure our timeout is positive - timeout = max([deadline - time.time(), jitter_time]) + timeout = max([deadline - time.monotonic(), jitter_time]) s = self.handler.select( [self._socket, self._read_sock], [], [], timeout )[0] @@ -646,12 +639,12 @@ if self._read_sock in s: self._send_request(read_timeout, connect_timeout) # Requests act as implicit pings. - last_send = time.time() + last_send = time.monotonic() continue - if time.time() >= deadline: + if time.monotonic() >= deadline: self._send_ping(connect_timeout) - last_send = time.time() + last_send = time.monotonic() self.logger.info("Closing connection to %s:%s", host, port) client._session_callback(KeeperState.CLOSED) return STOP_CONNECTING @@ -703,6 +696,7 @@ with self._socket_error_handling(): self._socket = self.handler.create_connection( address=(hostip, port), + hostname=host, timeout=client._session_timeout / 1000.0, use_ssl=self.client.use_ssl, keyfile=self.client.keyfile, @@ -710,6 +704,7 @@ ca=self.client.ca, keyfile_password=self.client.keyfile_password, verify_certs=self.client.verify_certs, + check_hostname=self.client.check_hostname, ) self._socket.setblocking(0) @@ -795,7 +790,7 @@ host=host, **self.sasl_options ) - # Inititalize the process with an empty challenge token + # Initialize the process with an empty challenge token challenge = None xid = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/recipe/lock.py new/kazoo-2.11.0/kazoo/recipe/lock.py --- old/kazoo-2.10.0/kazoo/recipe/lock.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/recipe/lock.py 2026-03-21 20:08:44.000000000 +0100 @@ -171,7 +171,7 @@ retry.deadline = timeout # Ensure we are locked so that we avoid multiple threads in - # this acquistion routine at the same time... + # this acquisition routine at the same time... method_locked = self._acquire_method_lock.acquire( blocking=blocking, timeout=timeout if timeout is not None else -1 ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/recipe/watchers.py new/kazoo-2.11.0/kazoo/recipe/watchers.py --- old/kazoo-2.10.0/kazoo/recipe/watchers.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/recipe/watchers.py 2026-03-21 20:08:44.000000000 +0100 @@ -449,4 +449,4 @@ def _children_watcher(self, async_result, event): self.children_changed.set() - async_result.set(time.time()) + async_result.set(time.monotonic()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/retry.py new/kazoo-2.11.0/kazoo/retry.py --- old/kazoo-2.10.0/kazoo/retry.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/retry.py 2026-03-21 20:08:44.000000000 +0100 @@ -128,15 +128,15 @@ while True: try: if self.deadline is not None and self._cur_stoptime is None: - self._cur_stoptime = time.time() + self.deadline + self._cur_stoptime = time.monotonic() + self.deadline return func(*args, **kwargs) except ConnectionClosedError: raise except self.retry_exceptions: + self._attempts += 1 # Note: max_tries == -1 means infinite tries. if self._attempts == self.max_tries: raise RetryFailedError("Too many retry attempts") - self._attempts += 1 jitter = random.uniform( 1.0 - self.max_jitter, 1.0 + self.max_jitter ) @@ -144,7 +144,7 @@ if ( self._cur_stoptime is not None - and time.time() + sleeptime >= self._cur_stoptime + and time.monotonic() + sleeptime >= self._cur_stoptime ): raise RetryFailedError("Exceeded retry deadline") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/testing/common.py new/kazoo-2.11.0/kazoo/testing/common.py --- old/kazoo-2.10.0/kazoo/testing/common.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/testing/common.py 2026-03-21 20:08:44.000000000 +0100 @@ -49,7 +49,7 @@ d.update(frame.f_locals) i = code.InteractiveConsole(d) - message = "Signal recieved : entering python shell.\nTraceback:\n" + message = "Signal received : entering python shell.\nTraceback:\n" message += "".join(traceback.format_stack(frame)) i.interact(message) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_client.py new/kazoo-2.11.0/kazoo/tests/test_client.py --- old/kazoo-2.10.0/kazoo/tests/test_client.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_client.py 2026-03-21 20:08:44.000000000 +0100 @@ -1,6 +1,5 @@ import os import socket -import sys import tempfile import threading import time @@ -30,17 +29,6 @@ from kazoo.tests.util import CI_ZK_VERSION -if sys.version_info > (3,): # pragma: nocover - - def u(s): - return s - -else: # pragma: nocover - - def u(s): - return unicode(s, "unicode_escape") # noqa - - class TestClientTransitions(KazooTestCase): @staticmethod def make_event(): @@ -197,8 +185,8 @@ client.close() def test_unicode_auth(self): - username = u(r"xe4/\hm") - password = u(r"/\xe4hm") + username = r"xe4/\hm" + password = r"/\xe4hm" digest_auth = "%s:%s" % (username, password) acl = self._makeAuth(username, password, all=True) @@ -258,8 +246,6 @@ with pytest.raises(AuthFailedError): client.add_auth("unknown-scheme", digest_auth) - client.stop() - def test_add_auth_on_reconnect(self): client = self._get_client() client.start() @@ -545,10 +531,10 @@ def test_create_unicode_path(self): client = self.client - path = client.create(u("/ascii")) - assert path == u("/ascii") - path = client.create(u("/\xe4hm")) - assert path == u("/\xe4hm") + path = client.create("/ascii") + assert path == "/ascii" + path = client.create("/\xe4hm") + assert path == "/\xe4hm" def test_create_async_returns_unchrooted_path(self): client = self.client @@ -595,7 +581,7 @@ def test_create_unicode_value(self): client = self.client with pytest.raises(TypeError): - client.create("/1", u("\xe4hm")) + client.create("/1", "\xe4hm") def test_create_large_value(self): client = self.client diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_eventlet_handler.py new/kazoo-2.11.0/kazoo/tests/test_eventlet_handler.py --- old/kazoo-2.10.0/kazoo/tests/test_eventlet_handler.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_eventlet_handler.py 2026-03-21 20:08:44.000000000 +0100 @@ -141,7 +141,7 @@ try: resource.setrlimit(resource.RLIMIT_NOFILE, (4096, 4096)) except (ValueError, resource.error): - self.skipTest("couldnt raise fd limit high enough") + self.skipTest("couldn't raise fd limit high enough") fd = 0 socks = [] while fd < 4000: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_gevent_handler.py new/kazoo-2.11.0/kazoo/tests/test_gevent_handler.py --- old/kazoo-2.10.0/kazoo/tests/test_gevent_handler.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_gevent_handler.py 2026-03-21 20:08:44.000000000 +0100 @@ -153,7 +153,7 @@ try: resource.setrlimit(resource.RLIMIT_NOFILE, (4096, 4096)) except (ValueError, resource.error): - self.skipTest("couldnt raise fd limit high enough") + self.skipTest("couldn't raise fd limit high enough") fd = 0 socks = [] while fd < 4000: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_lock.py new/kazoo-2.11.0/kazoo/tests/test_lock.py --- old/kazoo-2.10.0/kazoo/tests/test_lock.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_lock.py 2026-03-21 20:08:44.000000000 +0100 @@ -487,27 +487,29 @@ lock = self.client.WriteLock(self.lockpath, "test") lock.acquire() + wait = self.make_wait() reader_thread.start() + # make sure reader_thread is a contender before writer_thread + wait(lambda: len(lock.contenders()) == 2) writer_thread.start() # wait for everyone to line up on the lock - wait = self.make_wait() wait(lambda: len(lock.contenders()) == 3) contenders = lock.contenders() assert contenders[0] == "test" remaining = contenders[1:] - # release the lock and contenders should claim it in order - lock.release() - contender_bits = { "reader": (reader_thread, reader_event), "writer": (writer_thread, writer_event), } - for contender in ("reader", "writer"): - thread, event = contender_bits[contender] + # release the lock and contenders should claim it in order + lock.release() + + for contender, contender_bits in contender_bits.items(): + _, event = contender_bits with self.condition: while not self.active_thread: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_paths.py new/kazoo-2.11.0/kazoo/tests/test_paths.py --- old/kazoo-2.10.0/kazoo/tests/test_paths.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_paths.py 2026-03-21 20:08:44.000000000 +0100 @@ -1,4 +1,3 @@ -import sys from unittest import TestCase import pytest @@ -6,17 +5,6 @@ from kazoo.protocol import paths -if sys.version_info > (3,): # pragma: nocover - - def u(s): - return s - -else: # pragma: nocover - - def u(s): - return unicode(s, "unicode_escape") # noqa - - class NormPathTestCase(TestCase): def test_normpath(self): assert paths.normpath("/a/b") == "/a/b" @@ -25,7 +13,7 @@ assert paths.normpath("") == "" def test_normpath_unicode(self): - assert paths.normpath(u("/\xe4/b")) == u("/\xe4/b") + assert paths.normpath("/\xe4/b") == "/\xe4/b" def test_normpath_dots(self): assert paths.normpath("/a./b../c") == "/a./b../c" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_retry.py new/kazoo-2.11.0/kazoo/tests/test_retry.py --- old/kazoo-2.10.0/kazoo/tests/test_retry.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_retry.py 2026-03-21 20:08:44.000000000 +0100 @@ -1,89 +1,103 @@ -import unittest +from unittest import mock import pytest +from kazoo import exceptions as ke +from kazoo import retry as kr -class TestRetrySleeper(unittest.TestCase): - def _pass(self): - pass - - def _fail(self, times=1): - from kazoo.retry import ForceRetryError - - scope = dict(times=0) - - def inner(): - if scope["times"] >= times: - pass - else: - scope["times"] += 1 - raise ForceRetryError("Failed!") - - return inner - - def _makeOne(self, *args, **kwargs): - from kazoo.retry import KazooRetry - - return KazooRetry(*args, **kwargs) - - def test_reset(self): - retry = self._makeOne(delay=0, max_tries=2) - retry(self._fail()) - assert retry._attempts == 1 - retry.reset() - assert retry._attempts == 0 - - def test_too_many_tries(self): - from kazoo.retry import RetryFailedError - retry = self._makeOne(delay=0) - with pytest.raises(RetryFailedError): - retry(self._fail(times=999)) - assert retry._attempts == 1 +def _make_retry(*args, **kwargs): + """Return a KazooRetry instance with a dummy sleep function.""" - def test_maximum_delay(self): - def sleep_func(_time): - pass - - retry = self._makeOne(delay=10, max_tries=100, sleep_func=sleep_func) - retry(self._fail(times=10)) - assert retry._cur_delay < 4000 - # gevent's sleep function is picky about the type - assert type(retry._cur_delay) == float - - def test_copy(self): - def _sleep(t): - return None - - retry = self._makeOne(sleep_func=_sleep) - rcopy = retry.copy() - assert rcopy.sleep_func is _sleep - - -class TestKazooRetry(unittest.TestCase): - def _makeOne(self, **kw): - from kazoo.retry import KazooRetry - - return KazooRetry(**kw) - - def test_connection_closed(self): - from kazoo.exceptions import ConnectionClosedError - - retry = self._makeOne() + def _sleep_func(_time): + pass - def testit(): - raise ConnectionClosedError() + return kr.KazooRetry(*args, sleep_func=_sleep_func, **kwargs) - with pytest.raises(ConnectionClosedError): - retry(testit) - def test_session_expired(self): - from kazoo.exceptions import SessionExpiredError +def _make_try_func(times=1): + """Returns a function that raises ForceRetryError `times` time before + returning None. + """ + callmock = mock.Mock( + side_effect=[kr.ForceRetryError("Failed!")] * times + [None], + ) + return callmock + + +def test_call(): + retry = _make_retry(delay=0, max_tries=2) + func = _make_try_func() + retry(func, "foo", bar="baz") + assert func.call_args_list == [ + mock.call("foo", bar="baz"), + mock.call("foo", bar="baz"), + ] + + +def test_reset(): + retry = _make_retry(delay=0, max_tries=2) + func = _make_try_func() + retry(func) + assert ( + func.call_count == retry._attempts + 1 == 2 + ), "Called 2 times, failed _attempts 1, succeeded 1" + retry.reset() + assert retry._attempts == 0 + + +def test_too_many_tries(): + retry = _make_retry(delay=0, max_tries=10) + func = _make_try_func(times=999) + with pytest.raises(kr.RetryFailedError): + retry(func) + assert ( + func.call_count == retry._attempts == 10 + ), "Called 10 times, failed _attempts 10" + + +def test_maximum_delay(): + retry = _make_retry(delay=10, max_tries=100, max_jitter=0) + func = _make_try_func(times=2) + retry(func) + assert func.call_count == 3, "Called 3 times, 2 failed _attempts" + assert retry._cur_delay == 10 * 2**2, "Normal exponential backoff" + retry.reset() + func = _make_try_func(times=10) + retry(func) + assert func.call_count == 11, "Called 11 times, 10 failed _attempts" + assert retry._cur_delay == 60, "Delay capped by maximum" + # gevent's sleep function is picky about the type + assert isinstance(retry._cur_delay, float) + + +def test_copy(): + retry = _make_retry() + rcopy = retry.copy() + assert rcopy is not retry + assert rcopy.sleep_func is retry.sleep_func + + +def test_connection_closed(): + retry = _make_retry() + + def testit(): + raise ke.ConnectionClosedError + + with pytest.raises(ke.ConnectionClosedError): + retry(testit) + + +def test_session_expired(): + retry = _make_retry(max_tries=1) + + def testit(): + raise ke.SessionExpiredError - retry = self._makeOne(max_tries=1) + with pytest.raises(kr.RetryFailedError): + retry(testit) - def testit(): - raise SessionExpiredError() + retry = _make_retry(max_tries=1, ignore_expire=False) - with pytest.raises(Exception): - retry(testit) + with pytest.raises(ke.SessionExpiredError): + retry(testit) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_threading_handler.py new/kazoo-2.11.0/kazoo/tests/test_threading_handler.py --- old/kazoo-2.10.0/kazoo/tests/test_threading_handler.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_threading_handler.py 2026-03-21 20:08:44.000000000 +0100 @@ -55,7 +55,7 @@ try: resource.setrlimit(resource.RLIMIT_NOFILE, (4096, 4096)) except (ValueError, resource.error): - self.skipTest("couldnt raise fd limit high enough") + self.skipTest("couldn't raise fd limit high enough") fd = 0 socks = [] while fd < 4000: @@ -106,7 +106,7 @@ mock_handler.completion_queue = Mock() async_result = self._makeOne(mock_handler) async_result.rawlink(lambda a: a) - async_result.set_exception(ImportError("Error occured")) + async_result.set_exception(ImportError("Error occurred")) assert isinstance(async_result.exception, ImportError) assert mock_handler.completion_queue.put.called diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/test_utils.py new/kazoo-2.11.0/kazoo/tests/test_utils.py --- old/kazoo-2.10.0/kazoo/tests/test_utils.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/test_utils.py 2026-03-21 20:08:44.000000000 +0100 @@ -30,6 +30,59 @@ timeout = call_args[0][1] assert timeout >= 0, "socket timeout must be nonnegative" + def test_ssl_server_hostname(self): + from kazoo.handlers import utils + from kazoo.handlers.utils import create_tcp_connection, socket, ssl + + with patch.object(utils, "_set_default_tcpsock_options"): + with patch.object(ssl.SSLContext, "wrap_socket") as wrap_socket: + create_tcp_connection( + socket, + ("127.0.0.1", 2181), + timeout=1.5, + hostname="fakehostname", + use_ssl=True, + ) + + for call_args in wrap_socket.call_args_list: + server_hostname = call_args[1]["server_hostname"] + assert server_hostname == "fakehostname" + + def test_ssl_server_check_hostname(self): + from kazoo.handlers import utils + from kazoo.handlers.utils import create_tcp_connection, socket, ssl + + with patch.object(utils, "_set_default_tcpsock_options"): + with patch.object( + ssl.SSLContext, "wrap_socket", autospec=True + ) as wrap_socket: + create_tcp_connection( + socket, + ("127.0.0.1", 2181), + timeout=1.5, + hostname="fakehostname", + use_ssl=True, + check_hostname=True, + ) + + for call_args in wrap_socket.call_args_list: + ssl_context = call_args[0][0] + assert ssl_context.check_hostname + + def test_ssl_server_check_hostname_config_validation(self): + from kazoo.handlers.utils import create_tcp_connection, socket + + with pytest.raises(ValueError): + create_tcp_connection( + socket, + ("127.0.0.1", 2181), + timeout=1.5, + hostname="fakehostname", + use_ssl=True, + verify_certs=False, + check_hostname=True, + ) + def test_timeout_arg_eventlet(self): if not EVENTLET_HANDLER_AVAILABLE: pytest.skip("eventlet handler not available.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/tests/util.py new/kazoo-2.11.0/kazoo/tests/util.py --- old/kazoo-2.10.0/kazoo/tests/util.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/tests/util.py 2026-03-21 20:08:44.000000000 +0100 @@ -95,7 +95,7 @@ timeout=None, wait=None, exception=None, - getnow=(lambda: time.time), + getnow=(lambda: time.monotonic), getsleep=(lambda: time.sleep), ): if timeout is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo/version.py new/kazoo-2.11.0/kazoo/version.py --- old/kazoo-2.10.0/kazoo/version.py 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/kazoo/version.py 2026-03-21 20:08:44.000000000 +0100 @@ -1 +1 @@ -__version__ = "2.10.0" +__version__ = "2.11.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo.egg-info/PKG-INFO new/kazoo-2.11.0/kazoo.egg-info/PKG-INFO --- old/kazoo-2.10.0/kazoo.egg-info/PKG-INFO 2024-01-28 21:01:53.000000000 +0100 +++ new/kazoo-2.11.0/kazoo.egg-info/PKG-INFO 2026-03-21 20:08:48.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: kazoo -Version: 2.10.0 +Version: 2.11.0 Summary: "Higher Level Zookeeper Client" Home-page: https://kazoo.readthedocs.io Author: Kazoo team @@ -23,6 +23,8 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Communications @@ -36,6 +38,7 @@ Requires-Dist: objgraph; extra == "test" Requires-Dist: pytest; extra == "test" Requires-Dist: pytest-cov; extra == "test" +Requires-Dist: pytest-timeout; extra == "test" Requires-Dist: gevent>=1.2; implementation_name != "pypy" and extra == "test" Requires-Dist: eventlet>=0.17.1; implementation_name != "pypy" and extra == "test" Requires-Dist: pyjks; extra == "test" @@ -59,6 +62,7 @@ Requires-Dist: Sphinx>=1.2.2; extra == "alldeps" Requires-Dist: sphinx-autodoc-typehints>=1; extra == "alldeps" Requires-Dist: mypy>=0.991; extra == "alldeps" +Dynamic: license-file Kazoo ===== @@ -68,7 +72,7 @@ [](https://houndci.com) `kazoo` implements a higher level API to [Apache -Zookeeper](http://zookeeper.apache.org/) for Python clients. +ZooKeeper](http://zookeeper.apache.org/) for Python clients. See [the full docs](http://kazoo.rtfd.org/) for more information. @@ -87,6 +91,32 @@ Corporation](http://zope.com/). It has since gathered an active community of over one hundred contributors. +<a name="2.11.0"></a> +## 2.11.0 (2026-03-21) + + +#### Features + +* **testing:** + * bump deps for Python > 3.8 ([43e6f068](https://github.com/python-zk/kazoo/commit/43e6f0682d12893e983213db3bb7927f448ae03d)) + * add Python 3.13 & 3.14 ([b385289e](https://github.com/python-zk/kazoo/commit/b385289ed68bf791824379733e9dc80bf26ba5a9)) + * be a little more verbose about ZK download URL ([4ed8a304](https://github.com/python-zk/kazoo/commit/4ed8a304118c98cfe6594e441bf9fa09b575a186)) +* **core:** + * removing tiny remaining bits of Python2 hybridation ([0751174](https://github.com/python-zk/kazoo/commit/0751174)) + * add support for SNI ([273bd56](https://github.com/python-zk/kazoo/commit/273bd56)) + +#### Bug Fixes + +* **core:** + * Proper retry count in KazooRetry ([73309b2d](https://github.com/python-zk/kazoo/commit/73309b2d456c8e64f4ceb079f98903fc9e45f3b6)) + * Revert "Fix possible endless wait in stop() after AUTH_FAILED error (#688)" ([2fb93a87](https://github.com/python-zk/kazoo/commit/2fb93a87d3648e2dece5698cb64b059da5134a57)) + * prefer use of `time.monotonic` ([b00d88ff](https://github.com/python-zk/kazoo/commit/b00d88ff1485f1cb175565c49955bf5d7ce96fef), closes [#722](https://github.com/python-zk/kazoo/issues/722)) + * Add missing Zookeeper exceptions codes ([4c6bad82](https://github.com/python-zk/kazoo/commit/4c6bad82ebe347b9e51abbf33cef443057dc1c45)) + * fix spelling ([686d770](https://github.com/python-zk/kazoo/commit/686d770)) + +* **test:** avoid racy reader vs writer contender in `test_rw_lock` ([6540c932](https://github.com/python-zk/kazoo/commit/6540c932505a988ccae3c77c023113d4c4c01947)) +* **testing:** follow redirect when downloading ZK and use https ([b4155ea0](https://github.com/python-zk/kazoo/commit/b4155ea07ba671ce98bb63cebb8dfcd42748efd3)) + <a name="2.10.0"></a> ## 2.10.0 (2024-01-28) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/kazoo.egg-info/requires.txt new/kazoo-2.11.0/kazoo.egg-info/requires.txt --- old/kazoo-2.10.0/kazoo.egg-info/requires.txt 2024-01-28 21:01:53.000000000 +0100 +++ new/kazoo-2.11.0/kazoo.egg-info/requires.txt 2026-03-21 20:08:48.000000000 +0100 @@ -28,6 +28,7 @@ objgraph pytest pytest-cov +pytest-timeout pyjks pyopenssl diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/pyproject.toml new/kazoo-2.11.0/pyproject.toml --- old/kazoo-2.10.0/pyproject.toml 2024-01-28 21:01:45.000000000 +0100 +++ new/kazoo-2.11.0/pyproject.toml 2026-03-21 20:08:44.000000000 +0100 @@ -20,11 +20,13 @@ ''' [tool.pytest.ini_options] -addopts = "-ra -v" +addopts = "-ra -v --color=yes" log_cli = true log_cli_date_format = "%Y-%m-%d %H:%M:%S" log_cli_format = "%(asctime)s %(levelname)s %(message)s" log_cli_level = "INFO" +# Per-test timeout in seconds +timeout = 180 [tool.mypy] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kazoo-2.10.0/setup.cfg new/kazoo-2.11.0/setup.cfg --- old/kazoo-2.10.0/setup.cfg 2024-01-28 21:01:53.313537000 +0100 +++ new/kazoo-2.11.0/setup.cfg 2026-03-21 20:08:49.020750500 +0100 @@ -24,6 +24,8 @@ Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 + Programming Language :: Python :: 3.14 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy Topic :: Communications @@ -57,6 +59,7 @@ objgraph pytest pytest-cov + pytest-timeout gevent>=1.2 ; implementation_name!='pypy' eventlet>=0.17.1 ; implementation_name!='pypy' pyjks
