diff options
-rw-r--r-- | Doc/library/stdtypes.rst | 15 | ||||
-rw-r--r-- | Lib/test/test_buffer.py | 6 | ||||
-rw-r--r-- | Lib/test/test_ctypes/test_pep3118.py | 24 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst | 2 | ||||
-rw-r--r-- | Objects/memoryobject.c | 6 |
5 files changed, 31 insertions, 22 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index aea2410..2360472 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -3715,12 +3715,15 @@ copying. types such as :class:`bytes` and :class:`bytearray`, an element is a single byte, but other types such as :class:`array.array` may have bigger elements. - ``len(view)`` is equal to the length of :class:`~memoryview.tolist`. - If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length - is equal to the number of elements in the view. For higher dimensions, - the length is equal to the length of the nested list representation of - the view. The :class:`~memoryview.itemsize` attribute will give you the - number of bytes in a single element. + ``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which + is the nested list representation of the view. If ``view.ndim = 1``, + this is equal to the number of elements in the view. + + .. versionchanged:: 3.12 + If ``view.ndim == 0``, ``len(view)`` now raises :exc:`TypeError` instead of returning 1. + + The :class:`~memoryview.itemsize` attribute will give you the number of + bytes in a single element. A :class:`memoryview` supports slicing and indexing to expose its data. One-dimensional slicing will result in a subview:: diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 8ac3b7e..098d2d9 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -965,8 +965,10 @@ class TestBufferProtocol(unittest.TestCase): self.assertEqual(m.strides, tuple(strides)) self.assertEqual(m.suboffsets, tuple(suboffsets)) - n = 1 if ndim == 0 else len(lst) - self.assertEqual(len(m), n) + if ndim == 0: + self.assertRaises(TypeError, len, m) + else: + self.assertEqual(len(m), len(lst)) rep = result.tolist() if fmt else result.tobytes() self.assertEqual(rep, lst) diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index c8a70e3..0381617 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -28,7 +28,7 @@ class Test(unittest.TestCase): if shape: self.assertEqual(len(v), shape[0]) else: - self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) + self.assertRaises(TypeError, len, v) self.assertEqual(v.itemsize, sizeof(itemtp)) self.assertEqual(v.shape, shape) # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides @@ -39,11 +39,10 @@ class Test(unittest.TestCase): # they are always read/write self.assertFalse(v.readonly) - if v.shape: - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n * v.itemsize, len(v.tobytes())) + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) except: # so that we can see the failing type print(tp) @@ -58,7 +57,7 @@ class Test(unittest.TestCase): if shape: self.assertEqual(len(v), shape[0]) else: - self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) + self.assertRaises(TypeError, len, v) self.assertEqual(v.itemsize, sizeof(itemtp)) self.assertEqual(v.shape, shape) # XXX Issue #12851 @@ -67,11 +66,10 @@ class Test(unittest.TestCase): # they are always read/write self.assertFalse(v.readonly) - if v.shape: - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n, len(v)) + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) except: # so that we can see the failing type print(tp) @@ -243,7 +241,7 @@ class LEPoint(LittleEndianStructure): # endian_types = [ (BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint), - (LEPoint, "T{<l:x:<l:y:}".replace('l', s_long), (), LEPoint), + (LEPoint * 1, "T{<l:x:<l:y:}".replace('l', s_long), (1,), LEPoint), (POINTER(BEPoint), "&T{>l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)), (POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)), ] diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst b/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst new file mode 100644 index 0000000..d65e0f3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst @@ -0,0 +1,2 @@ +``len()`` for 0-dimensional :class:`memoryview`` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`.
+Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` raising an :exc:`IndexError``.
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 1d6cc3b..34cc797 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2642,7 +2642,11 @@ static Py_ssize_t memory_length(PyMemoryViewObject *self) { CHECK_RELEASED_INT(self); - return self->view.ndim == 0 ? 1 : self->view.shape[0]; + if (self->view.ndim == 0) { + PyErr_SetString(PyExc_TypeError, "0-dim memory has no length"); + return -1; + } + return self->view.shape[0]; } /* As mapping */ |