@@ -1804,3 +1804,142 @@ def test_invalid_chunk_coordinates_raise() -> None:
18041804
18051805 with pytest .raises (IndexError ):
18061806 grid .get_chunk_start (array_shape , (0 , 2 )) # Only 2 chunks in dim 1 (0,1)
1807+
1808+
1809+ # ===================================================================
1810+ # End-to-end indexing tests through full zarr Array pipeline
1811+ # (SliceDimIndexer, IntDimIndexer, etc. with rectilinear grids)
1812+ # ===================================================================
1813+
1814+
1815+ def test_slice_at_exact_chunk_boundaries () -> None :
1816+ """Test slicing exactly at rectilinear chunk boundaries.
1817+
1818+ This exercises the SliceDimIndexer code path end-to-end, verifying
1819+ that the refactored boundary calculation (stop-1 → +1 pattern) is correct.
1820+ Chunk boundaries for rows: [0:10, 10:30, 30:60]
1821+ Chunk boundaries for cols: [0:25, 25:50, 50:75, 75:100]
1822+ """
1823+ store = MemoryStore ()
1824+ data = np .arange (6000 , dtype = "float64" ).reshape (60 , 100 )
1825+ arr = zarr .create_array (
1826+ store = store ,
1827+ shape = (60 , 100 ),
1828+ chunks = [[10 , 20 , 30 ], [25 , 25 , 25 , 25 ]],
1829+ dtype = "float64" ,
1830+ zarr_format = 3 ,
1831+ )
1832+ arr [:] = data
1833+
1834+ # Slice exactly one chunk (second row-chunk, first col-chunk)
1835+ np .testing .assert_array_equal (arr [10 :30 , 0 :25 ], data [10 :30 , 0 :25 ])
1836+
1837+ # Slice exactly at a boundary start
1838+ np .testing .assert_array_equal (arr [30 :60 , 75 :100 ], data [30 :60 , 75 :100 ])
1839+
1840+ # Slice spanning exactly two chunk boundaries
1841+ np .testing .assert_array_equal (arr [0 :30 , 0 :50 ], data [0 :30 , 0 :50 ])
1842+ np .testing .assert_array_equal (arr [10 :60 , 25 :75 ], data [10 :60 , 25 :75 ])
1843+
1844+ # Single-element slices at each boundary
1845+ np .testing .assert_array_equal (arr [9 :10 , :], data [9 :10 , :]) # last row of chunk 0
1846+ np .testing .assert_array_equal (arr [10 :11 , :], data [10 :11 , :]) # first row of chunk 1
1847+ np .testing .assert_array_equal (arr [29 :30 , :], data [29 :30 , :]) # last row of chunk 1
1848+ np .testing .assert_array_equal (arr [30 :31 , :], data [30 :31 , :]) # first row of chunk 2
1849+
1850+
1851+ def test_strided_slicing_rectilinear () -> None :
1852+ """Test slicing with step > 1 on rectilinear arrays."""
1853+ store = MemoryStore ()
1854+ data = np .arange (6000 , dtype = "float64" ).reshape (60 , 100 )
1855+ arr = zarr .create_array (
1856+ store = store ,
1857+ shape = (60 , 100 ),
1858+ chunks = [[10 , 20 , 30 ], [25 , 25 , 25 , 25 ]],
1859+ dtype = "float64" ,
1860+ zarr_format = 3 ,
1861+ )
1862+ arr [:] = data
1863+
1864+ np .testing .assert_array_equal (arr [::2 , ::3 ], data [::2 , ::3 ])
1865+ np .testing .assert_array_equal (arr [5 :55 :5 , 10 :90 :10 ], data [5 :55 :5 , 10 :90 :10 ])
1866+ np .testing .assert_array_equal (arr [::7 , ::13 ], data [::7 , ::13 ])
1867+
1868+
1869+ def test_fancy_indexing_rectilinear () -> None :
1870+ """Test oindex and vindex on rectilinear arrays through the full Array pipeline."""
1871+ store = MemoryStore ()
1872+ data = np .arange (6000 , dtype = "float64" ).reshape (60 , 100 )
1873+ arr = zarr .create_array (
1874+ store = store ,
1875+ shape = (60 , 100 ),
1876+ chunks = [[10 , 20 , 30 ], [25 , 25 , 25 , 25 ]],
1877+ dtype = "float64" ,
1878+ zarr_format = 3 ,
1879+ )
1880+ arr [:] = data
1881+
1882+ # oindex: orthogonal indexing with integer arrays spanning multiple chunks
1883+ rows = np .array ([0 , 9 , 10 , 29 , 30 , 59 ])
1884+ cols = np .array ([0 , 24 , 25 , 49 , 50 , 99 ])
1885+ np .testing .assert_array_equal (arr .oindex [rows , cols ], data [np .ix_ (rows , cols )])
1886+
1887+ # vindex: coordinate-based indexing
1888+ r = np .array ([0 , 10 , 30 , 59 ])
1889+ c = np .array ([0 , 25 , 50 , 99 ])
1890+ np .testing .assert_array_equal (arr .vindex [r , c ], data [r , c ])
1891+
1892+ # oindex with slice on one axis, int array on other
1893+ np .testing .assert_array_equal (arr .oindex [rows , 50 :75 ], data [np .ix_ (rows , np .arange (50 , 75 ))])
1894+ np .testing .assert_array_equal (arr .oindex [10 :30 , cols ], data [np .ix_ (np .arange (10 , 30 ), cols )])
1895+
1896+
1897+ def test_boolean_mask_indexing_rectilinear () -> None :
1898+ """Test boolean mask indexing on rectilinear arrays."""
1899+ store = MemoryStore ()
1900+ data = np .arange (6000 , dtype = "float64" ).reshape (60 , 100 )
1901+ arr = zarr .create_array (
1902+ store = store ,
1903+ shape = (60 , 100 ),
1904+ chunks = [[10 , 20 , 30 ], [25 , 25 , 25 , 25 ]],
1905+ dtype = "float64" ,
1906+ zarr_format = 3 ,
1907+ )
1908+ arr [:] = data
1909+
1910+ # Full 2D boolean mask
1911+ mask = data > 3000
1912+ np .testing .assert_array_equal (arr .vindex [mask ], data [mask ])
1913+
1914+ # 1D boolean mask on rows via oindex
1915+ row_mask = np .zeros (60 , dtype = bool )
1916+ row_mask [[0 , 9 , 10 , 29 , 30 , 59 ]] = True # hits all chunk boundaries
1917+ np .testing .assert_array_equal (arr .oindex [row_mask , :], data [row_mask , :])
1918+
1919+ # 1D boolean mask on cols via oindex
1920+ col_mask = np .zeros (100 , dtype = bool )
1921+ col_mask [[0 , 24 , 25 , 49 , 50 , 99 ]] = True # hits all chunk boundaries
1922+ np .testing .assert_array_equal (arr .oindex [:, col_mask ], data [:, col_mask ])
1923+
1924+
1925+ def test_block_indexing_rectilinear () -> None :
1926+ """Test block (chunk-level) indexing on rectilinear arrays."""
1927+ store = MemoryStore ()
1928+ data = np .arange (6000 , dtype = "float64" ).reshape (60 , 100 )
1929+ arr = zarr .create_array (
1930+ store = store ,
1931+ shape = (60 , 100 ),
1932+ chunks = [[10 , 20 , 30 ], [25 , 25 , 25 , 25 ]],
1933+ dtype = "float64" ,
1934+ zarr_format = 3 ,
1935+ )
1936+ arr [:] = data
1937+
1938+ # Individual blocks
1939+ np .testing .assert_array_equal (arr .blocks [0 , 0 ], data [0 :10 , 0 :25 ])
1940+ np .testing .assert_array_equal (arr .blocks [1 , 0 ], data [10 :30 , 0 :25 ])
1941+ np .testing .assert_array_equal (arr .blocks [2 , 3 ], data [30 :60 , 75 :100 ])
1942+
1943+ # Block range
1944+ np .testing .assert_array_equal (arr .blocks [0 :2 , 0 :2 ], data [0 :30 , 0 :50 ])
1945+ np .testing .assert_array_equal (arr .blocks [1 :3 , 2 :4 ], data [10 :60 , 50 :100 ])
0 commit comments