Repository: projecteru/redis-trib.py (language: python)

Issue:
Problem slicing in function _add_slots() in pypy 7.0.0 (Python 2.7.13)
Stumbled on this yesterday and took some time to find as the code looked fine and required debugging to see the issue.  Basically it seems like pypy converts uses of **range** to **xrange** in the background.  This surfaces as an issue in the function **_add_slots** which is attempts to slice the list of slots provided to it by the **_add_slots_range** function supply a **range** as the **slots_list** parameter, yet pypy silently overriding this with **xrange** blows up as you can slice a generator.

Note: this is using redistrib version 0.6.1 installed via pip in virtualenv on Ubuntu 19.04

Attached two images to make it clear, along with my monkey patch hack to fix the issue quickly - though I'm sure someone else can do better.
![Problem](https://user-images.githubusercontent.com/6218707/66801575-894ea700-eee7-11e9-8a9e-8243d51eef4d.png)
![Solution](https://user-images.githubusercontent.com/6218707/66801580-91a6e200-eee7-11e9-812d-e2d12bd98887.png)




Discussion / hints:
Thanks for reporting. Let me have a look

Fix patch:
diff --git a/README.md b/README.md
index 724e175..f62fc01 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 Redis cluster CLI tools and libraries in Python. It supports Python 2.7 and 3.5 or higher. It supports Redis 3.x and 4.x cluster mode.
 
+Note: version 0.6.x is the last releases that support Python 2.7.
+
 # Installation
 
     pip install redis-trib
diff --git a/redistrib/__init__.py b/redistrib/__init__.py
index def3610..5ec4cff 100644
--- a/redistrib/__init__.py
+++ b/redistrib/__init__.py
@@ -1,2 +1,2 @@
-__version__ = '0.6.1'
+__version__ = '0.6.2'
 REPO = 'https://github.com/projecteru/redis-trib.py'
diff --git a/redistrib/command.py b/redistrib/command.py
index 7e8aabe..66d932c 100644
--- a/redistrib/command.py
+++ b/redistrib/command.py
@@ -77,7 +77,12 @@ def addslots(slots_chunk):
 
     # split list to evenly sized chunks
     for i in range(0, len(slots_list), max_slots):
-        addslots(slots_list[i:i + max_slots])
+        try:
+            slots = slots_list[i: i + max_slots]
+        except TypeError:
+            # TODO in Python2 six.moves.range does not support slicing
+            slots = list(slots_list)[i: i + max_slots]
+        addslots(slots)
 
 
 def _add_slots_range(conn, begin, end, max_slots):


Test patch:
diff --git a/test/basic_api.py b/test/basic_api.py
index c57ae5d..fe4a99f 100644
--- a/test/basic_api.py
+++ b/test/basic_api.py
@@ -139,10 +139,19 @@ def test_start_multi(self):
         comm.start_cluster_on_multi([('127.0.0.1', 7100), ('127.0.0.1', 7101),
                                      ('127.0.0.1', 7102)])
         nodes = base.list_nodes('127.0.0.1', 7100)
+
+        possible_slots_number = (5461, 5462)
+        ports = (7100, 7101, 7102)
+
         self.assertEqual(3, len(nodes))
-        self.assertEqual(5462, len(nodes[('127.0.0.1', 7100)].assigned_slots))
-        self.assertEqual(5461, len(nodes[('127.0.0.1', 7101)].assigned_slots))
-        self.assertEqual(5461, len(nodes[('127.0.0.1', 7102)].assigned_slots))
+        for port in ports:
+            self.assertIn(len(nodes[('127.0.0.1', port)].assigned_slots),
+                          possible_slots_number,
+                          msg='port=%s' % port)
+        self.assertEqual(
+            sum(len(nodes[('127.0.0.1', port)].assigned_slots)
+                for port in ports),
+            16384)
         comm.quit_cluster('127.0.0.1', 7100)
         comm.quit_cluster('127.0.0.1', 7101)
         comm.shutdown_cluster('127.0.0.1', 7102)
@@ -150,10 +159,17 @@ def test_start_multi(self):
         comm.start_cluster_on_multi([('127.0.0.1', 7100), ('127.0.0.1', 7101),
                                      ('127.0.0.1', 7100), ('127.0.0.1', 7102)])
         nodes = base.list_nodes('127.0.0.1', 7100)
+
         self.assertEqual(3, len(nodes))
-        self.assertEqual(5462, len(nodes[('127.0.0.1', 7100)].assigned_slots))
-        self.assertEqual(5461, len(nodes[('127.0.0.1', 7101)].assigned_slots))
-        self.assertEqual(5461, len(nodes[('127.0.0.1', 7102)].assigned_slots))
+        for port in ports:
+            self.assertIn(len(nodes[('127.0.0.1', port)].assigned_slots),
+                          possible_slots_number,
+                          msg='port=%s' % port)
+        self.assertEqual(
+            sum(len(nodes[('127.0.0.1', port)].assigned_slots)
+                for port in ports),
+            16384)
+
         comm.quit_cluster('127.0.0.1', 7100)
         comm.quit_cluster('127.0.0.1', 7101)
         comm.shutdown_cluster('127.0.0.1', 7102)