Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions genome_kit/interval_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ def interval(self) -> IntervalLike:
return self._interval

@property
def data(self):
"""Return the backing data array."""
def data(self) -> np.ndarray:
"""Return the backing data array as read-only."""
if isinstance(self._data, np.ndarray):
read_only_view = self._data.view()
read_only_view.flags.writeable = False
Expand Down Expand Up @@ -435,7 +435,7 @@ def _concat_pieces(self, intervals: list[Interval]):
"""Fetch and concatenate the data slices for ``intervals`` (in order)
along the aligned axis.
"""
pieces = [self._get_interval_like(iv).data for iv in intervals]
pieces = [self._get_interval_like(iv)._data for iv in intervals]
return pieces[0] if len(pieces) == 1 else np.concatenate(pieces, axis=self._axis)

# The forms a value assigned via an interval-like key may take. See
Expand Down
30 changes: 30 additions & 0 deletions tests/test_interval_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,36 @@ def test_set_dis(self):
interval_data[0] = -interval_data[0]
np.testing.assert_equal(-data[0], interval_data[0])

def test_data_read_only_does_not_affect_backing_array(self):
position = Interval('chr1', '+', 100, 100, self.genome)
interval = position.expand(0, 3)
data = np.arange(0, 30).reshape(3, 10)
interval_data = IntervalData(interval, data)

view = interval_data.data

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe change the docstring for the data property to add that the returned object is read-only.

self.assertFalse(view.flags.writeable)
with self.assertRaises(ValueError):
view[0, 0] = 1

self.assertTrue(data.flags.writeable)
interval_data[0] = -interval_data[0]
np.testing.assert_equal(-np.arange(0, 10), interval_data[0])

def test_set_after_single_piece_concat(self):
base = Interval('chr1', '+', 100, 106, self.genome)
piece = Interval('chr1', '+', 101, 103, self.genome)
keys = {
'list': [piece],
'dis': DisjointIntervalSequence.from_intervals([piece]),
}
for name, key in keys.items():
with self.subTest(name):
interval_data = IntervalData(base, np.zeros((6, 4), dtype=int))
sub = interval_data[key]
sub[0] = 1
np.testing.assert_equal(np.ones(4), sub[0])
np.testing.assert_equal(np.ones(4), interval_data[1])


class TestIntervalDataSliceIndex(unittest.TestCase):
rank = 3
Expand Down
Loading