summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2023-05-04 14:59:46 (GMT)
committerGitHub <noreply@github.com>2023-05-04 14:59:46 (GMT)
commit04f673327530f47f002e784459037231de478412 (patch)
tree56b29e35a1147b9655b5f4b4337f8a2f905b0e3f /Lib/test
parentb17d32c1142d16a5fea0c95bce185bf9be696491 (diff)
downloadcpython-04f673327530f47f002e784459037231de478412.zip
cpython-04f673327530f47f002e784459037231de478412.tar.gz
cpython-04f673327530f47f002e784459037231de478412.tar.bz2
gh-102500: Implement PEP 688 (#102521)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_buffer.py142
-rw-r--r--Lib/test/test_collections.py11
-rw-r--r--Lib/test/test_doctest.py2
3 files changed, 153 insertions, 2 deletions
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 098d2d9..b6e82ad 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -17,6 +17,7 @@ import contextlib
import unittest
from test import support
from test.support import os_helper
+import inspect
from itertools import permutations, product
from random import randrange, sample, choice
import warnings
@@ -4438,5 +4439,146 @@ class TestBufferProtocol(unittest.TestCase):
struct.calcsize(format))
+class TestPythonBufferProtocol(unittest.TestCase):
+ def test_basic(self):
+ class MyBuffer:
+ def __buffer__(self, flags):
+ return memoryview(b"hello")
+
+ mv = memoryview(MyBuffer())
+ self.assertEqual(mv.tobytes(), b"hello")
+ self.assertEqual(bytes(MyBuffer()), b"hello")
+
+ def test_bad_buffer_method(self):
+ class MustReturnMV:
+ def __buffer__(self, flags):
+ return 42
+
+ self.assertRaises(TypeError, memoryview, MustReturnMV())
+
+ class NoBytesEither:
+ def __buffer__(self, flags):
+ return b"hello"
+
+ self.assertRaises(TypeError, memoryview, NoBytesEither())
+
+ class WrongArity:
+ def __buffer__(self):
+ return memoryview(b"hello")
+
+ self.assertRaises(TypeError, memoryview, WrongArity())
+
+ def test_release_buffer(self):
+ class WhatToRelease:
+ def __init__(self):
+ self.held = False
+ self.ba = bytearray(b"hello")
+
+ def __buffer__(self, flags):
+ if self.held:
+ raise TypeError("already held")
+ self.held = True
+ return memoryview(self.ba)
+
+ def __release_buffer__(self, buffer):
+ self.held = False
+
+ wr = WhatToRelease()
+ self.assertFalse(wr.held)
+ with memoryview(wr) as mv:
+ self.assertTrue(wr.held)
+ self.assertEqual(mv.tobytes(), b"hello")
+ self.assertFalse(wr.held)
+
+ def test_same_buffer_returned(self):
+ class WhatToRelease:
+ def __init__(self):
+ self.held = False
+ self.ba = bytearray(b"hello")
+ self.created_mv = None
+
+ def __buffer__(self, flags):
+ if self.held:
+ raise TypeError("already held")
+ self.held = True
+ self.created_mv = memoryview(self.ba)
+ return self.created_mv
+
+ def __release_buffer__(self, buffer):
+ assert buffer is self.created_mv
+ self.held = False
+
+ wr = WhatToRelease()
+ self.assertFalse(wr.held)
+ with memoryview(wr) as mv:
+ self.assertTrue(wr.held)
+ self.assertEqual(mv.tobytes(), b"hello")
+ self.assertFalse(wr.held)
+
+ def test_buffer_flags(self):
+ class PossiblyMutable:
+ def __init__(self, data, mutable) -> None:
+ self._data = bytearray(data)
+ self._mutable = mutable
+
+ def __buffer__(self, flags):
+ if flags & inspect.BufferFlags.WRITABLE:
+ if not self._mutable:
+ raise RuntimeError("not mutable")
+ return memoryview(self._data)
+ else:
+ return memoryview(bytes(self._data))
+
+ mutable = PossiblyMutable(b"hello", True)
+ immutable = PossiblyMutable(b"hello", False)
+ with memoryview._from_flags(mutable, inspect.BufferFlags.WRITABLE) as mv:
+ self.assertEqual(mv.tobytes(), b"hello")
+ mv[0] = ord(b'x')
+ self.assertEqual(mv.tobytes(), b"xello")
+ with memoryview._from_flags(mutable, inspect.BufferFlags.SIMPLE) as mv:
+ self.assertEqual(mv.tobytes(), b"xello")
+ with self.assertRaises(TypeError):
+ mv[0] = ord(b'h')
+ self.assertEqual(mv.tobytes(), b"xello")
+ with memoryview._from_flags(immutable, inspect.BufferFlags.SIMPLE) as mv:
+ self.assertEqual(mv.tobytes(), b"hello")
+ with self.assertRaises(TypeError):
+ mv[0] = ord(b'x')
+ self.assertEqual(mv.tobytes(), b"hello")
+
+ with self.assertRaises(RuntimeError):
+ memoryview._from_flags(immutable, inspect.BufferFlags.WRITABLE)
+ with memoryview(immutable) as mv:
+ self.assertEqual(mv.tobytes(), b"hello")
+ with self.assertRaises(TypeError):
+ mv[0] = ord(b'x')
+ self.assertEqual(mv.tobytes(), b"hello")
+
+ def test_call_builtins(self):
+ ba = bytearray(b"hello")
+ mv = ba.__buffer__(0)
+ self.assertEqual(mv.tobytes(), b"hello")
+ ba.__release_buffer__(mv)
+ with self.assertRaises(OverflowError):
+ ba.__buffer__(sys.maxsize + 1)
+
+ @unittest.skipIf(_testcapi is None, "requires _testcapi")
+ def test_c_buffer(self):
+ buf = _testcapi.testBuf()
+ self.assertEqual(buf.references, 0)
+ mv = buf.__buffer__(0)
+ self.assertIsInstance(mv, memoryview)
+ self.assertEqual(mv.tobytes(), b"test")
+ self.assertEqual(buf.references, 1)
+ buf.__release_buffer__(mv)
+ self.assertEqual(buf.references, 0)
+ with self.assertRaises(ValueError):
+ mv.tobytes()
+ # Calling it again doesn't cause issues
+ with self.assertRaises(ValueError):
+ buf.__release_buffer__(mv)
+ self.assertEqual(buf.references, 0)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index fb568a4..8fc28a6 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -25,7 +25,7 @@ from collections.abc import Sized, Container, Callable, Collection
from collections.abc import Set, MutableSet
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
from collections.abc import Sequence, MutableSequence
-from collections.abc import ByteString
+from collections.abc import ByteString, Buffer
class TestUserObjects(unittest.TestCase):
@@ -1949,6 +1949,15 @@ class TestCollectionABCs(ABCTestCase):
self.assertFalse(issubclass(memoryview, ByteString))
self.validate_abstract_methods(ByteString, '__getitem__', '__len__')
+ def test_Buffer(self):
+ for sample in [bytes, bytearray, memoryview]:
+ self.assertIsInstance(sample(b"x"), Buffer)
+ self.assertTrue(issubclass(sample, Buffer))
+ for sample in [str, list, tuple]:
+ self.assertNotIsInstance(sample(), Buffer)
+ self.assertFalse(issubclass(sample, Buffer))
+ self.validate_abstract_methods(Buffer, '__buffer__')
+
def test_MutableSequence(self):
for sample in [tuple, str, bytes]:
self.assertNotIsInstance(sample(), MutableSequence)
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 3491d4c..542fcdb 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -707,7 +707,7 @@ plain ol' Python and is guaranteed to be available.
>>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins)
- >>> 830 < len(tests) < 850 # approximate number of objects with docstrings
+ >>> 830 < len(tests) < 860 # approximate number of objects with docstrings
True
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests