1414from  ngio .utils  import  NgioValueError 
1515
1616SlicingInputType : TypeAlias  =  slice  |  Sequence [int ] |  int  |  None 
17- SlicingType : TypeAlias  =  slice  |  tuple [int , ... ] |  int 
17+ SlicingType : TypeAlias  =  slice  |  list [int ] |  int 
1818
1919############################################################## 
2020# 
@@ -60,7 +60,7 @@ def _slicing_tuple_boundary_check(
6060        elif  isinstance (sl , int ):
6161            _int_boundary_check (sl , shape = sh )
6262            out_slicing_tuple .append (sl )
63-         elif  isinstance (sl , tuple ):
63+         elif  isinstance (sl , list ):
6464            [_int_boundary_check (i , shape = sh ) for  i  in  sl ]
6565            out_slicing_tuple .append (sl )
6666        else :
@@ -115,32 +115,31 @@ def get(self, ax_name: str, normalize: bool = False) -> SlicingType:
115115        return  slicing_tuple [ax_index ]
116116
117117
118- def  _check_tuple_in_slicing_tuple (
118+ def  _check_list_in_slicing_tuple (
119119    slicing_tuple : tuple [SlicingType , ...],
120- ) ->  tuple [None , None ] |  tuple [int , tuple [int , ... ]]:
121-     """Check if there are any tuple  in the slicing tuple. 
120+ ) ->  tuple [None , None ] |  tuple [int , list [int ]]:
121+     """Check if there are any lists  in the slicing tuple. 
122122
123-     The zarr python api only supports int or slices, not tuples. 
124-     Ngio support a single tuple in the slicing tuple to allow non-contiguous 
123+     Dask regions when setting data do not support non-contiguous 
124+     selections natively. 
125+     Ngio support a single list in the slicing tuple to allow non-contiguous 
125126    selection (main use case: selecting multiple channels). 
126127    """ 
127-     # Find if the is any tuple  in the slicing tuple 
128+     # Find if the is any list  in the slicing tuple 
128129    # If there is one we need to handle it differently 
129-     tuple_in_slice  =  [
130-         (i , s ) for  i , s  in  enumerate (slicing_tuple ) if  isinstance (s , tuple )
131-     ]
132-     if  not  tuple_in_slice :
133-         # No tuple in the slicing tuple 
130+     list_in_slice  =  [(i , s ) for  i , s  in  enumerate (slicing_tuple ) if  isinstance (s , list )]
131+     if  not  list_in_slice :
132+         # No list in the slicing tuple 
134133        return  None , None 
135134
136-     if  len (tuple_in_slice ) >  1 :
135+     if  len (list_in_slice ) >  1 :
137136        raise  NotImplementedError (
138137            "Slicing with multiple non-contiguous tuples/lists " 
139138            "is not supported yet in Ngio. Use directly the " 
140139            "zarr.Array api to get the correct array slice." 
141140        )
142141    # Complex case, we have exactly one tuple in the slicing tuple 
143-     ax , first_tuple  =  tuple_in_slice [0 ]
142+     ax , first_tuple  =  list_in_slice [0 ]
144143    if  len (first_tuple ) >  100 :
145144        warn (
146145            "Performance warning: " 
@@ -164,38 +163,14 @@ def get_slice_as_numpy(zarr_array: zarr.Array, slicing_ops: SlicingOps) -> np.nd
164163    slicing_tuple  =  slicing_ops .normalized_slicing_tuple 
165164    # Find if the is any tuple in the slicing tuple 
166165    # If there is one we need to handle it differently 
167-     ax , first_tuple  =  _check_tuple_in_slicing_tuple (slicing_tuple )
168-     if  ax  is  None :
169-         # Simple case, no tuple in the slicing tuple 
170-         return  zarr_array [slicing_tuple ]
171- 
172-     assert  first_tuple  is  not   None 
173-     slices  =  [
174-         zarr_array [(* slicing_tuple [:ax ], idx , * slicing_tuple [ax  +  1  :])]
175-         for  idx  in  first_tuple 
176-     ]
177-     out_array  =  np .stack (slices , axis = ax )
178-     return  out_array 
166+     return  zarr_array [slicing_tuple ]
179167
180168
181169def  get_slice_as_dask (zarr_array : zarr .Array , slicing_ops : SlicingOps ) ->  da .Array :
182170    """Get a slice of a zarr array as a dask array.""" 
183171    da_array  =  da .from_zarr (zarr_array )
184172    slicing_tuple  =  slicing_ops .normalized_slicing_tuple 
185-     # Find if the is any tuple in the slicing tuple 
186-     # If there is one we need to handle it differently 
187-     ax , first_tuple  =  _check_tuple_in_slicing_tuple (slicing_tuple )
188-     if  ax  is  None :
189-         # Base case, no tuple in the slicing tuple 
190-         return  da_array [slicing_tuple ]
191- 
192-     assert  first_tuple  is  not   None 
193-     slices  =  [
194-         da_array [(* slicing_tuple [:ax ], idx , * slicing_tuple [ax  +  1  :])]
195-         for  idx  in  first_tuple 
196-     ]
197-     out_array  =  da .stack (slices , axis = ax )
198-     return  out_array 
173+     return  da_array [slicing_tuple ]
199174
200175
201176def  set_slice_as_numpy (
@@ -204,17 +179,7 @@ def set_slice_as_numpy(
204179    slicing_ops : SlicingOps ,
205180) ->  None :
206181    slice_tuple  =  slicing_ops .normalized_slicing_tuple 
207-     ax , first_tuple  =  _check_tuple_in_slicing_tuple (slice_tuple )
208-     if  ax  is  None :
209-         # Base case, no tuple in the slicing tuple 
210-         zarr_array [slice_tuple ] =  patch 
211-         return 
212- 
213-     # Complex case, we have exactly one tuple in the slicing tuple 
214-     assert  first_tuple  is  not   None 
215-     for  i , idx  in  enumerate (first_tuple ):
216-         _sub_slice  =  (* slice_tuple [:ax ], idx , * slice_tuple [ax  +  1  :])
217-         zarr_array [_sub_slice ] =  np .take (patch , indices = i , axis = ax )
182+     zarr_array [slice_tuple ] =  patch 
218183
219184
220185def  handle_int_set_as_dask (
@@ -237,7 +202,7 @@ def set_slice_as_dask(
237202    zarr_array : zarr .Array , patch : da .Array , slicing_ops : SlicingOps 
238203) ->  None :
239204    slice_tuple  =  slicing_ops .normalized_slicing_tuple 
240-     ax , first_tuple  =  _check_tuple_in_slicing_tuple (slice_tuple )
205+     ax , first_tuple  =  _check_list_in_slicing_tuple (slice_tuple )
241206    patch , slice_tuple  =  handle_int_set_as_dask (patch , slice_tuple )
242207    if  ax  is  None :
243208        # Base case, no tuple in the slicing tuple 
@@ -261,13 +226,13 @@ def set_slice_as_dask(
261226############################################################## 
262227
263228
264- def  _try_to_slice (value : Sequence [int ]) ->  slice  |  tuple [int , ... ]:
229+ def  _try_to_slice (value : Sequence [int ]) ->  slice  |  list [int ]:
265230    """Try to convert a list of integers into a slice if they are contiguous. 
266231
267232    - If the input is empty, return an empty tuple. 
268233    - If the input is sorted, and contains contiguous integers, 
269234      return a slice from the minimum to the maximum integer. 
270-     - Otherwise, return the input as a tuple . 
235+     - Otherwise, return the input as a list of integers . 
271236
272237    This is useful for optimizing array slicing operations 
273238    by allowing the use of slices when possible, which can be more efficient. 
@@ -293,7 +258,7 @@ def _try_to_slice(value: Sequence[int]) -> slice | tuple[int, ...]:
293258    if  sorted (value ) ==  list (range (min_input , max_input  +  1 )):
294259        return  slice (min_input , max_input  +  1 )
295260
296-     return  tuple (value )
261+     return  list (value )
297262
298263
299264def  _remove_channel_slicing (
@@ -393,7 +358,7 @@ def _normalize_slicing_tuple(
393358    The output types are: 
394359    - slice 
395360    - int 
396-     - tuple  of int (for non-contiguous selection) 
361+     - list  of int (for non-contiguous selection) 
397362    """ 
398363    axis_name  =  axis .name 
399364    if  axis_name  not  in   slicing_dict :
@@ -408,7 +373,7 @@ def _normalize_slicing_tuple(
408373    elif  isinstance (value , Sequence ):
409374        # If a contiguous sequence of integers is provided, 
410375        # convert it to a slice for simplicity. 
411-         # Alternatively, it will be converted to a tuple  of ints 
376+         # Alternatively, it will be converted to a list  of ints 
412377        return  _try_to_slice (value )
413378
414379    raise  NgioValueError (
0 commit comments