Repository: interpretml/slicer (language: python)

Issue:
Failing tests: slicing sparse matrices
The tests currently fail due to issues slicing scipy sparse matrices.

I believe the issue is here, where slicer looks up the maximum dimension of an object:

https://github.com/interpretml/slicer/blob/683fd5c5e7ee28fc5abb6d3d5bd8b41235352d92/slicer/slicer_internal.py#L593-L597

Scipy sparse matrices are identified by their `.__class__.__module__` and `.__class__.__name__`, in this lookup table:

https://github.com/interpretml/slicer/blob/683fd5c5e7ee28fc5abb6d3d5bd8b41235352d92/slicer/slicer_internal.py#L568-L569

However, scipy sparse matrices currently seems to live in the module `scipy.sparse._csc`, not `scipy.sparse.csc` . So, the objects are given a maximum dimension of 0, leading to an `IndexError`.


Discussion / hints:

Fix patch:
diff --git a/slicer/slicer_internal.py b/slicer/slicer_internal.py
index c3d1c59..51145a2 100644
--- a/slicer/slicer_internal.py
+++ b/slicer/slicer_internal.py
@@ -605,7 +605,7 @@ def default_alias(cls, o):
 
 
 def _type_name(o: object) -> Tuple[str, str]:
-    return o.__class__.__module__, o.__class__.__name__
+    return _handle_module_aliases(o.__class__.__module__), o.__class__.__name__
 
 
 def _safe_isinstance(
@@ -616,3 +616,16 @@ def _safe_isinstance(
         return o_module == module_name and o_type == type_name
     else:
         return o_module == module_name and o_type in type_name
+
+
+def _handle_module_aliases(module_name):
+    # scipy modules such as "scipy.sparse.csc" were renamed to "scipy.sparse._csc" in v1.8
+    # Standardise by removing underscores for compatibility with either name
+    # Else just pass module name unchanged
+    module_map = {
+        "scipy.sparse._csc": "scipy.sparse.csc",
+        "scipy.sparse._csr": "scipy.sparse.csr",
+        "scipy.sparse._dok": "scipy.sparse.dok",
+        "scipy.sparse._lil": "scipy.sparse.lil",
+    }
+    return module_map.get(module_name, module_name)


Test patch:
diff --git a/slicer/test_slicer.py b/slicer/test_slicer.py
index 7070aa4..0566fe2 100644
--- a/slicer/test_slicer.py
+++ b/slicer/test_slicer.py
@@ -246,6 +246,7 @@ def test_slicer_sparse():
 
     candidates = [csc_array, csr_array, dok_array, lil_array]
     for candidate in candidates:
+        print("testing:", type(candidate))
         slicer = S(candidate)
         actual = slicer[0, 0]
         assert ctr_eq(actual.o, 1)
@@ -341,7 +342,8 @@ def test_operations_1d():
     array = np.array(elements)
     torch_array = torch.tensor(elements)
     containers = [li, tup, array, torch_array, di, series]
-    for _, ctr in enumerate(containers):
+    for ctr in containers:
+        print("testing:", type(ctr))
         slicer = AtomicSlicer(ctr)
 
         assert ctr_eq(slicer[0], elements[0])
@@ -371,7 +373,8 @@ def test_operations_2d():
     sparse_lil = lil_matrix(elements)
 
     containers = [li, df, sparse_csc, sparse_csr, sparse_dok, sparse_lil]
-    for _, ctr in enumerate(containers):
+    for ctr in containers:
+        print("testing:", type(ctr))
         slicer = AtomicSlicer(ctr)
 
         assert ctr_eq(slicer[0], elements[0])
@@ -432,7 +435,8 @@ def test_operations_3d():
         list_of_multi_arrays,
         di_of_multi_arrays,
     ]
-    for _, ctr in enumerate(containers):
+    for ctr in containers:
+        print("testing:", type(ctr))
         slicer = AtomicSlicer(ctr)
 
         assert ctr_eq(slicer[0], elements[0])