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
8 changes: 7 additions & 1 deletion redis/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
PatternT = _StringLikeT # Patterns matched against keys, fields etc
FieldT = EncodableT # Fields within hash tables, streams and geo commands
KeysT = Union[KeyT, Iterable[KeyT]]
ResponseT = Union[Awaitable[Any], Any]
ResponseT = Union[Awaitable[Any], Any, "PipelineCommandsProtocol"]
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

The PipelineCommandsProtocol type is added to the ResponseT union, but this creates a semantic issue. ResponseT is used as the return type for all Redis command methods (e.g., set(), get()). Adding PipelineCommandsProtocol to this union means that when calling redis_client.get("key"), the type checker will infer the return type could be a PipelineCommandsProtocol, which is incorrect - a regular Redis client should never return a Pipeline.

The underlying issue is that command methods are shared between Redis and Pipeline classes, but they should have different return types. A more appropriate solution would involve using TypeVars or Self types to properly model this polymorphism, rather than adding Pipeline to the general response type union.

Copilot uses AI. Check for mistakes.
ChannelT = _StringLikeT
GroupT = _StringLikeT # Consumer group
ConsumerT = _StringLikeT # Consumer name
Expand All @@ -53,5 +53,11 @@ class CommandsProtocol(Protocol):
def execute_command(self, *args, **options) -> ResponseT: ...


class PipelineCommandsProtocol(Protocol):
def execute_command(self, *args, **options) -> ResponseT: ...
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

The PipelineCommandsProtocol is defined but never actually used as a type constraint anywhere in the codebase. No Pipeline class declares that it implements this protocol, nor is it used in any type annotations besides being added to the ResponseT union. For this protocol to be useful, Pipeline classes should either explicitly state they implement it, or it should be used as a type bound in relevant places. Additionally, the execute_command method in this protocol returns ResponseT, which creates a circular type reference since ResponseT now includes PipelineCommandsProtocol.

Suggested change
def execute_command(self, *args, **options) -> ResponseT: ...
def execute_command(self, *args, **options) -> Any: ...

Copilot uses AI. Check for mistakes.

def pipeline_execute_command(self, *args, **options) -> "PipelineCommandsProtocol": ...


class ClusterCommandsProtocol(CommandsProtocol):
encoder: "Encoder"
Loading