From 5145108a052a492d40f9b5244ffc80f3b11549c0 Mon Sep 17 00:00:00 2001 From: Vivian Nguyen Date: Thu, 5 Oct 2023 15:40:15 -0500 Subject: [PATCH] Dense Arrays With Negative Domains Can Only Use Full Indexer --- tiledb/libtiledb.pyx | 11 +++++++ tiledb/tests/test_libtiledb.py | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/tiledb/libtiledb.pyx b/tiledb/libtiledb.pyx index 8cac1c804b..5caa8fb3be 100644 --- a/tiledb/libtiledb.pyx +++ b/tiledb/libtiledb.pyx @@ -2103,6 +2103,12 @@ cdef class DenseArrayImpl(Array): attr_names.extend(self.schema.attr(a).name for a in attrs) selection = index_as_tuple(selection) + + for dim, sel in zip(self.schema.domain, selection): + if dim.domain[0] < 0 and sel != slice(None, None, None): + raise TileDBError("Must use full indexer for arrays containing " + "dimensions with negative integers.") + idx = replace_ellipsis(self.schema.domain.ndim, selection) idx, drop_axes = replace_scalars_slice(self.schema.domain, idx) dim_ranges = index_domain_subarray(self, self.schema.domain, idx) @@ -2246,6 +2252,11 @@ cdef class DenseArrayImpl(Array): from .subarray import Subarray if not self.isopen or self.mode != 'w': raise TileDBError("DenseArray is not opened for writing") + + for dim, sel in zip(self.schema.domain, index_as_tuple(selection)): + if dim.domain[0] < 0 and sel != slice(None, None, None): + raise TileDBError("Must use full indexer for arrays containing " + "dimensions with signed integers.") domain = self.domain cdef tuple idx = replace_ellipsis(domain.ndim, index_as_tuple(selection)) diff --git a/tiledb/tests/test_libtiledb.py b/tiledb/tests/test_libtiledb.py index a6c584b394..820e9134d8 100644 --- a/tiledb/tests/test_libtiledb.py +++ b/tiledb/tests/test_libtiledb.py @@ -2492,6 +2492,63 @@ def test_index_2d(self): with self.assertRaises(IndexError): T[idx] + def test_dense_array_with_negative_domain(self): + path = self.path("test_dense_array_with_negative_domain") + attr = tiledb.Attr(dtype=np.uint8) + dom = tiledb.Domain(tiledb.Dim("X", domain=(-10, 10), dtype=np.int64)) + schema = tiledb.ArraySchema(domain=dom, sparse=False, attrs=[attr]) + tiledb.Array.create(path, schema) + data = np.random.randint(10, size=21) + + with tiledb.open(path, "w") as A: + with pytest.raises(tiledb.TileDBError): + A[-5:5] = np.random.randint(10, size=11) + with pytest.raises(tiledb.TileDBError): + A[:0] = np.random.randint(10, size=11) + with pytest.raises(tiledb.TileDBError): + A[0:] = np.random.randint(10, size=11) + with pytest.raises(tiledb.TileDBError): + A[0] = np.random.randint(10, size=1) + A[:] = data + + with tiledb.open(path, "r") as A: + with pytest.raises(tiledb.TileDBError): + A[-5:5] + with pytest.raises(tiledb.TileDBError): + A[:0] + with pytest.raises(tiledb.TileDBError): + A[0:] + with pytest.raises(tiledb.TileDBError): + A[0] + assert_array_equal(A[:], data[:]) + + def test_dense_array_with_2d_negative_domain(self): + path = self.path("test_dense_array_with_2d_negative_domain") + attr = tiledb.Attr(dtype=np.uint8) + dim1 = tiledb.Dim("X", domain=(-10, 10), dtype=np.int64) + dim2 = tiledb.Dim("Y", domain=(0, 10), dtype=np.int64) + dom = tiledb.Domain(dim1, dim2) + schema = tiledb.ArraySchema(domain=dom, sparse=False, attrs=[attr]) + tiledb.Array.create(path, schema) + data = np.random.randint(10, size=(21,11)) + + with tiledb.open(path, "w") as A: + with pytest.raises(tiledb.TileDBError): + A[:,-5:5] = np.random.randint(10, size=11) + with pytest.raises(tiledb.TileDBError): + A[:0, :] = np.random.randint(10, size=11) + with pytest.raises(tiledb.TileDBError): + A[0] = np.random.randint(10, size=1) + A[:] = data + + with tiledb.open(path, "r") as A: + with pytest.raises(tiledb.TileDBError): + A[:,-5:5] + with pytest.raises(tiledb.TileDBError): + A[:0, :] + with pytest.raises(tiledb.TileDBError): + A[0] + assert_array_equal(A[:], data[:]) class TestDatetimeSlicing(DiskTestCase): def test_dense_datetime_vector(self):