Skip to content
Open
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
40 changes: 35 additions & 5 deletions redis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
Optional,
Set,
Type,
TypeVar,
Union,
overload,
)

from redis._parsers.encoders import Encoder
Expand Down Expand Up @@ -97,6 +99,9 @@
logger = logging.getLogger(__name__)


T = TypeVar('T')


def is_debug_log_enabled():
return logger.isEnabledFor(logging.DEBUG)

Expand Down Expand Up @@ -545,17 +550,42 @@ def pipeline(self, transaction=True, shard_hint=None) -> "Pipeline":
self.connection_pool, self.response_callbacks, transaction, shard_hint
)

@overload
def transaction(
self,
func: Callable[["Pipeline"], T],
*watches: str | None,
shard_hint: Any = None,
value_from_callable: Literal[False] = False,
watch_delay: int | None = None,
**kwargs: Any,
) -> List[Any]: ...

@overload
def transaction(
self,
func: Callable[["Pipeline"], T],
*watches: str | None,
shard_hint: Any = None,
value_from_callable: Literal[True] = ...,
watch_delay: int | None = None,
**kwargs: Any,
) -> T: ...

def transaction(
self, func: Callable[["Pipeline"], None], *watches, **kwargs
) -> Union[List[Any], Any, None]:
self,
func: Callable[["Pipeline"], T],
*watches: str | None,
shard_hint: Any = None,
value_from_callable: bool = False,
watch_delay: int | None = None,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

watch_delay type too narrow compared to async counterpart

Medium Severity

The watch_delay parameter is typed as int | None in all three signatures (both overloads and the implementation), but the async version of this same method in redis/asyncio/client.py correctly types it as Optional[float]. Since time.sleep() accepts float values, the int annotation is too restrictive and would cause type checkers to reject valid fractional-second delays like 0.5. This needs to be float | None to match the async counterpart and the actual runtime behavior.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0a429bd. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd actually spotted and fixed this locally (albeit I went with int | float | None) as part of a larger series but I hadn't pushed it since I wasn't sure this was going to be merged.

@petyaslavova it looks like you're doing most of the type work here. Would you like to take ownership of this and fix as necessary? Or would you rather I push the fix? Also, I have a larger patch to make many of the *Commands classes and make them subclass Generic[AnyStr] since they accept and return both str and bytes. Do you want that or are you planning to fix that yourself?

**kwargs: Any,
) -> Union[List[Any], T]:
"""
Convenience method for executing the callable `func` as a transaction
while watching all keys specified in `watches`. The 'func' callable
should expect a single argument which is a Pipeline object.
"""
shard_hint = kwargs.pop("shard_hint", None)
value_from_callable = kwargs.pop("value_from_callable", False)
watch_delay = kwargs.pop("watch_delay", None)
with self.pipeline(True, shard_hint) as pipe:
while True:
try:
Expand Down
Loading