@@ -850,22 +850,29 @@ def _format_command(self, args: tuple) -> str:
850850 return " " .join (parts )
851851
852852 def _get_pipeline_commands (self , pipeline : Any ) -> list :
853- """Extract commands from pipeline."""
853+ """Extract commands from pipeline.
854+
855+ ClusterPipeline has an always-empty ``command_stack`` attribute while
856+ the real commands live in ``_execution_strategy._command_queue``, so we
857+ check ``_execution_strategy`` first to avoid returning the empty list.
858+ """
854859 try :
855- if hasattr (pipeline , "command_stack" ):
856- return pipeline .command_stack
857- elif hasattr (pipeline , "_command_stack" ):
858- return pipeline ._command_stack
859- # ClusterPipeline stores commands in _execution_strategy._command_queue
860- elif hasattr (pipeline , "_execution_strategy" ):
860+ # ClusterPipeline stores commands in _execution_strategy._command_queue.
861+ # Must be checked before command_stack because ClusterPipeline also
862+ # has a command_stack attr that is always empty (redis-py #3703).
863+ if hasattr (pipeline , "_execution_strategy" ):
861864 strategy = pipeline ._execution_strategy
862865 if hasattr (strategy , "_command_queue" ):
863866 return strategy ._command_queue
864- elif hasattr (strategy , "command_queue" ):
867+ if hasattr (strategy , "command_queue" ):
865868 return strategy .command_queue
866869 # Async ClusterPipeline stores commands in _command_queue directly
867- elif hasattr (pipeline , "_command_queue" ):
870+ if hasattr (pipeline , "_command_queue" ):
868871 return pipeline ._command_queue
872+ if hasattr (pipeline , "command_stack" ):
873+ return pipeline .command_stack
874+ if hasattr (pipeline , "_command_stack" ):
875+ return pipeline ._command_stack
869876 except AttributeError :
870877 pass
871878 return []
0 commit comments