Skip to content

Commit 5e0b5c3

Browse files
committed
docs: add types to recipe.lock
1 parent a1d6451 commit 5e0b5c3

File tree

4 files changed

+99
-48
lines changed

4 files changed

+99
-48
lines changed

kazoo/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ def create(
922922
sequence=False,
923923
makepath=False,
924924
include_data=False,
925-
):
925+
) -> str:
926926
"""Create a node with the given value as its data. Optionally
927927
set an ACL on the node.
928928

kazoo/protocol/states.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Kazoo State and Event objects"""
22
from collections import namedtuple
3+
from enum import Enum
34

45

5-
class KazooState(object):
6+
class KazooState(str, Enum):
67
"""High level connection state values
78
89
States inspired by Netflix Curator.

kazoo/recipe/lock.py

Lines changed: 94 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,26 @@
1515
1616
"""
1717
import re
18+
import uuid
1819
import sys
1920

2021
try:
2122
from time import monotonic as now
2223
except ImportError:
2324
from time import time as now
24-
import uuid
2525

2626
import six
27+
from typing import (
28+
TYPE_CHECKING,
29+
Any,
30+
ContextManager,
31+
List,
32+
Optional,
33+
Sequence,
34+
Type,
35+
Union,
36+
cast,
37+
)
2738

2839
from kazoo.exceptions import (
2940
CancelledError,
@@ -38,24 +49,28 @@
3849
RetryFailedError,
3950
)
4051

52+
if TYPE_CHECKING:
53+
from kazoo.client import KazooClient
54+
from typing_extensions import Literal
55+
4156

4257
class _Watch(object):
43-
def __init__(self, duration=None):
58+
def __init__(self, duration: Optional[float] = None):
4459
self.duration = duration
45-
self.started_at = None
60+
self.started_at: Optional[float] = None
4661

47-
def start(self):
62+
def start(self) -> None:
4863
self.started_at = now()
4964

50-
def leftover(self):
65+
def leftover(self) -> Optional[float]:
5166
if self.duration is None:
5267
return None
5368
else:
54-
elapsed = now() - self.started_at
69+
elapsed = now() - cast(float, self.started_at)
5570
return max(0, self.duration - elapsed)
5671

5772

58-
class Lock(object):
73+
class Lock(ContextManager[None]):
5974
"""Kazoo Lock
6075
6176
Example usage with a :class:`~kazoo.client.KazooClient` instance:
@@ -84,7 +99,13 @@ class Lock(object):
8499
# sequence number. Involved in read/write locks.
85100
_EXCLUDE_NAMES = ["__lock__"]
86101

87-
def __init__(self, client, path, identifier=None, extra_lock_patterns=()):
102+
def __init__(
103+
self,
104+
client: KazooClient,
105+
path: str,
106+
identifier: Optional[str] = None,
107+
extra_lock_patterns: Sequence[str] = (),
108+
):
88109
"""Create a Kazoo lock.
89110
90111
:param client: A :class:`~kazoo.client.KazooClient` instance.
@@ -116,7 +137,7 @@ def __init__(self, client, path, identifier=None, extra_lock_patterns=()):
116137
# some data is written to the node. this can be queried via
117138
# contenders() to see who is contending for the lock
118139
self.data = str(identifier or "").encode("utf-8")
119-
self.node = None
140+
self.node: Optional[str] = None
120141

121142
self.wake_event = client.handler.event_object()
122143

@@ -132,20 +153,25 @@ def __init__(self, client, path, identifier=None, extra_lock_patterns=()):
132153
self.assured_path = False
133154
self.cancelled = False
134155
self._retry = KazooRetry(
135-
max_tries=None, sleep_func=client.handler.sleep_func
156+
max_tries=-1, sleep_func=client.handler.sleep_func
136157
)
137158
self._acquire_method_lock = client.handler.lock_object()
138159

139-
def _ensure_path(self):
160+
def _ensure_path(self) -> None:
140161
self.client.ensure_path(self.path)
141162
self.assured_path = True
142163

143-
def cancel(self):
164+
def cancel(self) -> None:
144165
"""Cancel a pending lock acquire."""
145166
self.cancelled = True
146167
self.wake_event.set()
147168

148-
def acquire(self, blocking=True, timeout=None, ephemeral=True):
169+
def acquire(
170+
self,
171+
blocking: bool = True,
172+
timeout: Optional[float] = None,
173+
ephemeral: bool = True,
174+
) -> bool:
149175
"""
150176
Acquire the lock. By defaults blocks and waits forever.
151177
@@ -212,11 +238,13 @@ def acquire(self, blocking=True, timeout=None, ephemeral=True):
212238
finally:
213239
self._acquire_method_lock.release()
214240

215-
def _watch_session(self, state):
241+
def _watch_session(self, state: KazooState) -> bool:
216242
self.wake_event.set()
217243
return True
218244

219-
def _inner_acquire(self, blocking, timeout, ephemeral=True):
245+
def _inner_acquire(
246+
self, blocking: bool, timeout: Optional[float], ephemeral: bool = True
247+
) -> bool:
220248

221249
# wait until it's our chance to get it..
222250
if self.is_acquired:
@@ -274,10 +302,10 @@ def _inner_acquire(self, blocking, timeout, ephemeral=True):
274302
finally:
275303
self.client.remove_listener(self._watch_session)
276304

277-
def _watch_predecessor(self, event):
305+
def _watch_predecessor(self, event: WatchedEvent) -> None:
278306
self.wake_event.set()
279307

280-
def _get_predecessor(self, node):
308+
def _get_predecessor(self, node: str) -> Optional[str]:
281309
"""returns `node`'s predecessor or None
282310
283311
Note: This handle the case where the current lock is not a contender
@@ -286,7 +314,7 @@ def _get_predecessor(self, node):
286314
"""
287315
node_sequence = node[len(self.prefix) :]
288316
children = self.client.get_children(self.path)
289-
found_self = False
317+
found_self: Union[Literal[False], re.Match[bytes]] = False
290318
# Filter out the contenders using the computed regex
291319
contender_matches = []
292320
for child in children:
@@ -301,7 +329,7 @@ def _get_predecessor(self, node):
301329
if child == node:
302330
# Remember the node's match object so we can short circuit
303331
# below.
304-
found_self = match
332+
found_self = cast(re.Match[bytes], match)
305333

306334
if found_self is False: # pragma: nocover
307335
# somehow we aren't in the childrens -- probably we are
@@ -317,42 +345,42 @@ def _get_predecessor(self, node):
317345
sorted_matches = sorted(contender_matches, key=lambda m: m.groups())
318346
return sorted_matches[-1].string
319347

320-
def _find_node(self):
348+
def _find_node(self) -> Optional[str]:
321349
children = self.client.get_children(self.path)
322350
for child in children:
323351
if child.startswith(self.prefix):
324352
return child
325353
return None
326354

327-
def _delete_node(self, node):
355+
def _delete_node(self, node: str) -> None:
328356
self.client.delete(self.path + "/" + node)
329357

330-
def _best_effort_cleanup(self):
358+
def _best_effort_cleanup(self) -> None:
331359
try:
332360
node = self.node or self._find_node()
333361
if node:
334362
self._delete_node(node)
335363
except KazooException: # pragma: nocover
336364
pass
337365

338-
def release(self):
366+
def release(self) -> bool:
339367
"""Release the lock immediately."""
340368
return self.client.retry(self._inner_release)
341369

342-
def _inner_release(self):
370+
def _inner_release(self) -> bool:
343371
if not self.is_acquired:
344372
return False
345373

346374
try:
347-
self._delete_node(self.node)
375+
self._delete_node(cast(str, self.node))
348376
except NoNodeError: # pragma: nocover
349377
pass
350378

351379
self.is_acquired = False
352380
self.node = None
353381
return True
354382

355-
def contenders(self):
383+
def contenders(self) -> List[str]:
356384
"""Return an ordered list of the current contenders for the
357385
lock.
358386
@@ -388,7 +416,7 @@ def contenders(self):
388416
for match in sorted(contender_matches, key=lambda m: m.groups())
389417
]
390418
# Retrieve all the contender nodes data (preserving order).
391-
contenders = []
419+
contenders: List[str] = []
392420
for node in contender_nodes:
393421
try:
394422
data, stat = self.client.get(self.path + "/" + node)
@@ -399,10 +427,15 @@ def contenders(self):
399427

400428
return contenders
401429

402-
def __enter__(self):
430+
def __enter__(self) -> None:
403431
self.acquire()
404432

405-
def __exit__(self, exc_type, exc_value, traceback):
433+
def __exit__(
434+
self,
435+
exc_type: Optional[Type[BaseException]],
436+
exc_value: Optional[BaseException],
437+
traceback: Any,
438+
) -> None:
406439
self.release()
407440

408441

@@ -466,7 +499,7 @@ class ReadLock(Lock):
466499
_EXCLUDE_NAMES = ["__lock__"]
467500

468501

469-
class Semaphore(object):
502+
class Semaphore(ContextManager[None]):
470503
"""A Zookeeper-based Semaphore
471504
472505
This synchronization primitive operates in the same manner as the
@@ -501,7 +534,13 @@ class Semaphore(object):
501534
502535
"""
503536

504-
def __init__(self, client, path, identifier=None, max_leases=1):
537+
def __init__(
538+
self,
539+
client: KazooClient,
540+
path: str,
541+
identifier: Optional[str] = None,
542+
max_leases: int = 1,
543+
):
505544
"""Create a Kazoo Lock
506545
507546
:param client: A :class:`~kazoo.client.KazooClient` instance.
@@ -537,7 +576,7 @@ def __init__(self, client, path, identifier=None, max_leases=1):
537576
self.cancelled = False
538577
self._session_expired = False
539578

540-
def _ensure_path(self):
579+
def _ensure_path(self) -> None:
541580
result = self.client.ensure_path(self.path)
542581
self.assured_path = True
543582
if result is True:
@@ -558,12 +597,14 @@ def _ensure_path(self):
558597
else:
559598
self.client.set(self.path, str(self.max_leases).encode("utf-8"))
560599

561-
def cancel(self):
600+
def cancel(self) -> None:
562601
"""Cancel a pending semaphore acquire."""
563602
self.cancelled = True
564603
self.wake_event.set()
565604

566-
def acquire(self, blocking=True, timeout=None):
605+
def acquire(
606+
self, blocking: bool = True, timeout: Optional[float] = None
607+
) -> bool:
567608
"""Acquire the semaphore. By defaults blocks and waits forever.
568609
569610
:param blocking: Block until semaphore is obtained or
@@ -601,7 +642,9 @@ def acquire(self, blocking=True, timeout=None):
601642

602643
return self.is_acquired
603644

604-
def _inner_acquire(self, blocking, timeout=None):
645+
def _inner_acquire(
646+
self, blocking: bool, timeout: Optional[float] = None
647+
) -> bool:
605648
"""Inner loop that runs from the top anytime a command hits a
606649
retryable Zookeeper exception."""
607650
self._session_expired = False
@@ -642,10 +685,10 @@ def _inner_acquire(self, blocking, timeout=None):
642685
finally:
643686
lock.release()
644687

645-
def _watch_lease_change(self, event):
688+
def _watch_lease_change(self, event: WatchedEvent) -> None:
646689
self.wake_event.set()
647690

648-
def _get_lease(self, data=None):
691+
def _get_lease(self) -> bool:
649692
# Make sure the session is still valid
650693
if self._session_expired:
651694
raise ForceRetryError("Retry on session loss at top")
@@ -674,25 +717,26 @@ def _get_lease(self, data=None):
674717
# Return current state
675718
return self.is_acquired
676719

677-
def _watch_session(self, state):
720+
def _watch_session(self, state: KazooState) -> Optional[Literal[True]]:
678721
if state == KazooState.LOST:
679722
self._session_expired = True
680723
self.wake_event.set()
681724

682725
# Return true to de-register
683726
return True
727+
return None
684728

685-
def _best_effort_cleanup(self):
729+
def _best_effort_cleanup(self) -> None:
686730
try:
687731
self.client.delete(self.create_path)
688732
except KazooException: # pragma: nocover
689733
pass
690734

691-
def release(self):
735+
def release(self) -> bool:
692736
"""Release the lease immediately."""
693737
return self.client.retry(self._inner_release)
694738

695-
def _inner_release(self):
739+
def _inner_release(self) -> bool:
696740
if not self.is_acquired:
697741
return False
698742
try:
@@ -702,7 +746,7 @@ def _inner_release(self):
702746
self.is_acquired = False
703747
return True
704748

705-
def lease_holders(self):
749+
def lease_holders(self) -> List[str]:
706750
"""Return an unordered list of the current lease holders.
707751
708752
.. note::
@@ -716,7 +760,7 @@ def lease_holders(self):
716760

717761
children = self.client.get_children(self.path)
718762

719-
lease_holders = []
763+
lease_holders: List[str] = []
720764
for child in children:
721765
try:
722766
data, stat = self.client.get(self.path + "/" + child)
@@ -725,8 +769,13 @@ def lease_holders(self):
725769
pass
726770
return lease_holders
727771

728-
def __enter__(self):
772+
def __enter__(self) -> None:
729773
self.acquire()
730774

731-
def __exit__(self, exc_type, exc_value, traceback):
775+
def __exit__(
776+
self,
777+
exc_type: Optional[Type[BaseException]],
778+
exc_value: Optional[BaseException],
779+
traceback: Any,
780+
) -> None:
732781
self.release()

0 commit comments

Comments
 (0)