Author: Antonio Cuni <anto.c...@gmail.com> Branch: ndarray-buffer Changeset: r68356:9c8634e4593f Date: 2013-12-02 16:42 +0100 http://bitbucket.org/pypy/pypy/changeset/9c8634e4593f/
Log: raise ValueError if we try to write to a mmapped array which is ready-only diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py --- a/pypy/interpreter/buffer.py +++ b/pypy/interpreter/buffer.py @@ -47,6 +47,9 @@ def get_raw_address(self): raise ValueError("no raw buffer") + def is_writable(self): + return False + # __________ app-level support __________ def descr_len(self, space): @@ -135,6 +138,9 @@ __slots__ = () # no extra slot here + def is_writable(self): + return True + def setitem(self, index, char): "Write a character into the buffer." raise NotImplementedError # Must be overriden. No bounds checks. diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -400,7 +400,14 @@ def base(self): return self.orig_base - + + +class ConcreteNonWritableArrayWithBase(ConcreteArrayWithBase): + def descr_setitem(self, space, orig_array, w_index, w_value): + raise OperationError(space.w_ValueError, space.wrap( + "assignment destination is read-only")) + + class NonWritableArray(ConcreteArray): def descr_setitem(self, space, orig_array, w_index, w_value): raise OperationError(space.w_ValueError, space.wrap( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -50,7 +50,7 @@ @staticmethod def from_shape_and_storage(space, shape, storage, dtype, order='C', owning=False, - w_subtype=None, w_base=None): + w_subtype=None, w_base=None, writable=True): from pypy.module.micronumpy.arrayimpl import concrete assert shape strides, backstrides = calc_strides(shape, dtype, order) @@ -58,8 +58,14 @@ if owning: raise OperationError(space.w_ValueError, space.wrap("Cannot have owning=True when specifying a buffer")) - impl = concrete.ConcreteArrayWithBase(shape, dtype, order, strides, - backstrides, storage, w_base) + if writable: + impl = concrete.ConcreteArrayWithBase(shape, dtype, order, strides, + backstrides, storage, w_base) + else: + impl = concrete.ConcreteNonWritableArrayWithBase(shape, dtype, order, + strides, backstrides, + storage, w_base) + elif owning: # Will free storage when GCd impl = concrete.ConcreteArray(shape, dtype, order, strides, diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1096,7 +1096,8 @@ storage = rffi.ptradd(storage, offset) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, w_subtype=w_subtype, - w_base=w_buffer) + w_base=w_buffer, + writable=buf.is_writable()) if not shape: return W_NDimArray.new_scalar(space, dtype) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -218,7 +218,8 @@ assert get(1, 1) == 3 class AppTestNumArray(BaseNumpyAppTest): - spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii", "array"]) + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) + def w_CustomIndexObject(self, index): class CustomIndexObject(object): def __init__(self, index): @@ -2087,6 +2088,15 @@ a = np.ndarray([1], dtype=bool) assert a[0] == True + +class AppTestNumArrayFromBuffer(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "array", "mmap"]) + + def setup_class(cls): + from rpython.tool.udir import udir + BaseNumpyAppTest.setup_class.im_func(cls) + cls.w_tmpname = cls.space.wrap(str(udir.join('mmap-'))) + def test_ndarray_from_buffer(self): import numpypy as np import array @@ -2126,7 +2136,19 @@ assert str(info.value).startswith('buffer is too small') info = raises(TypeError, "np.ndarray((5,), buffer=buf, offset=15, dtype='i2')") assert str(info.value).startswith('buffer is too small') - + + def test_ndarray_from_readonly_buffer(self): + import numpypy as np + from mmap import mmap, ACCESS_READ + f = open(self.tmpname, "w+") + f.write("hello") + f.flush() + buf = mmap(f.fileno(), 5, access=ACCESS_READ) + a = np.ndarray((5,), buffer=buf, dtype='c') + raises(ValueError, "a[0] = 'X'") + buf.close() + f.close() + class AppTestMultiDim(BaseNumpyAppTest): diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -314,6 +314,14 @@ self.check_valid_writeable() self.mmap.setslice(start, string) + def is_writable(self): + try: + self.mmap.check_writeable() + except RMMapError: + return False + else: + return True + def get_raw_address(self): self.check_valid() return self.mmap.data _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit