summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2019-06-07 15:51:28 (GMT)
committerGitHub <noreply@github.com>2019-06-07 15:51:28 (GMT)
commit740a84de73ad8d02655de0a084036f4b7e49a01b (patch)
tree44c2cbd5c8648a6f1560f397e114b4de8a2ad288
parent3bf0f3ad2046ac674d8e8a2c074a5a8b3327797d (diff)
downloadcpython-740a84de73ad8d02655de0a084036f4b7e49a01b.zip
cpython-740a84de73ad8d02655de0a084036f4b7e49a01b.tar.gz
cpython-740a84de73ad8d02655de0a084036f4b7e49a01b.tar.bz2
bpo-37191: Move TestPEP590 from test_capi to test_call (GH-13892)
-rw-r--r--Lib/test/test_call.py123
-rw-r--r--Lib/test/test_capi.py115
2 files changed, 123 insertions, 115 deletions
diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py
index 9f0a75b..b4ab749 100644
--- a/Lib/test/test_call.py
+++ b/Lib/test/test_call.py
@@ -475,5 +475,128 @@ class FastCallTests(unittest.TestCase):
# called, which changes the keywords dict.
compile("pass", "", "exec", x, **x.kwargs)
+
+Py_TPFLAGS_HAVE_VECTORCALL = 1 << 11
+Py_TPFLAGS_METHOD_DESCRIPTOR = 1 << 17
+
+
+def testfunction(self):
+ """some doc"""
+ return self
+
+
+def testfunction_kw(self, *, kw):
+ """some doc"""
+ return self
+
+
+class TestPEP590(unittest.TestCase):
+
+ def test_method_descriptor_flag(self):
+ import functools
+ cached = functools.lru_cache(1)(testfunction)
+
+ self.assertFalse(type(repr).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertTrue(type(list.append).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertTrue(type(list.__add__).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertTrue(type(testfunction).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertTrue(type(cached).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+
+ self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+
+ # Heap type should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR
+ class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
+ pass
+ self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+
+ def test_vectorcall_flag(self):
+ self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
+ self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
+ self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
+ self.assertTrue(_testcapi.MethodDescriptor2.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
+
+ # Heap type should not inherit Py_TPFLAGS_HAVE_VECTORCALL
+ class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
+ pass
+ self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
+
+ def test_vectorcall_override(self):
+ # Check that tp_call can correctly override vectorcall.
+ # MethodDescriptorNopGet implements tp_call but it inherits from
+ # MethodDescriptorBase, which implements vectorcall. Since
+ # MethodDescriptorNopGet returns the args tuple when called, we check
+ # additionally that no new tuple is created for this call.
+ args = tuple(range(5))
+ f = _testcapi.MethodDescriptorNopGet()
+ self.assertIs(f(*args), args)
+
+ def test_vectorcall(self):
+ # Test a bunch of different ways to call objects:
+ # 1. vectorcall using PyVectorcall_Call()
+ # (only for objects that support vectorcall directly)
+ # 2. normal call
+ # 3. vectorcall using _PyObject_Vectorcall()
+ # 4. call as bound method
+ # 5. call using functools.partial
+
+ # A list of (function, args, kwargs, result) calls to test
+ calls = [(len, (range(42),), {}, 42),
+ (list.append, ([], 0), {}, None),
+ ([].append, (0,), {}, None),
+ (sum, ([36],), {"start":6}, 42),
+ (testfunction, (42,), {}, 42),
+ (testfunction_kw, (42,), {"kw":None}, 42),
+ (_testcapi.MethodDescriptorBase(), (0,), {}, True),
+ (_testcapi.MethodDescriptorDerived(), (0,), {}, True),
+ (_testcapi.MethodDescriptor2(), (0,), {}, False)]
+
+ from _testcapi import pyobject_vectorcall, pyvectorcall_call
+ from types import MethodType
+ from functools import partial
+
+ def vectorcall(func, args, kwargs):
+ args = *args, *kwargs.values()
+ kwnames = tuple(kwargs)
+ return pyobject_vectorcall(func, args, kwnames)
+
+ for (func, args, kwargs, expected) in calls:
+ with self.subTest(str(func)):
+ if not kwargs:
+ self.assertEqual(expected, pyvectorcall_call(func, args))
+ self.assertEqual(expected, pyvectorcall_call(func, args, kwargs))
+
+ # Add derived classes (which do not support vectorcall directly,
+ # but do support all other ways of calling).
+
+ class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
+ pass
+
+ class MethodDescriptorOverridden(_testcapi.MethodDescriptorBase):
+ def __call__(self, n):
+ return 'new'
+
+ calls += [
+ (MethodDescriptorHeap(), (0,), {}, True),
+ (MethodDescriptorOverridden(), (0,), {}, 'new'),
+ ]
+
+ for (func, args, kwargs, expected) in calls:
+ with self.subTest(str(func)):
+ args1 = args[1:]
+ meth = MethodType(func, args[0])
+ wrapped = partial(func)
+ if not kwargs:
+ self.assertEqual(expected, func(*args))
+ self.assertEqual(expected, pyobject_vectorcall(func, args, None))
+ self.assertEqual(expected, meth(*args1))
+ self.assertEqual(expected, wrapped(*args))
+ self.assertEqual(expected, func(*args, **kwargs))
+ self.assertEqual(expected, vectorcall(func, args, kwargs))
+ self.assertEqual(expected, meth(*args1, **kwargs))
+ self.assertEqual(expected, wrapped(*args, **kwargs))
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 6a20f47..45fabd5 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -27,18 +27,11 @@ _testcapi = support.import_module('_testcapi')
# Were we compiled --with-pydebug or with #define Py_DEBUG?
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
-Py_TPFLAGS_HAVE_VECTORCALL = 1 << 11
-Py_TPFLAGS_METHOD_DESCRIPTOR = 1 << 17
-
def testfunction(self):
"""some doc"""
return self
-def testfunction_kw(self, *, kw):
- """some doc"""
- return self
-
class InstanceMethod:
id = _testcapi.instancemethod(id)
@@ -471,114 +464,6 @@ class TestPendingCalls(unittest.TestCase):
self.pendingcalls_wait(l, n)
-class TestPEP590(unittest.TestCase):
-
- def test_method_descriptor_flag(self):
- import functools
- cached = functools.lru_cache(1)(testfunction)
-
- self.assertFalse(type(repr).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertTrue(type(list.append).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertTrue(type(list.__add__).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertTrue(type(testfunction).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertTrue(type(cached).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
-
- self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
- self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
-
- # Heap type should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR
- class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
- pass
- self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
-
- def test_vectorcall_flag(self):
- self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
- self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
- self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
- self.assertTrue(_testcapi.MethodDescriptor2.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
-
- # Heap type should not inherit Py_TPFLAGS_HAVE_VECTORCALL
- class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
- pass
- self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
-
- def test_vectorcall_override(self):
- # Check that tp_call can correctly override vectorcall.
- # MethodDescriptorNopGet implements tp_call but it inherits from
- # MethodDescriptorBase, which implements vectorcall. Since
- # MethodDescriptorNopGet returns the args tuple when called, we check
- # additionally that no new tuple is created for this call.
- args = tuple(range(5))
- f = _testcapi.MethodDescriptorNopGet()
- self.assertIs(f(*args), args)
-
- def test_vectorcall(self):
- # Test a bunch of different ways to call objects:
- # 1. vectorcall using PyVectorcall_Call()
- # (only for objects that support vectorcall directly)
- # 2. normal call
- # 3. vectorcall using _PyObject_Vectorcall()
- # 4. call as bound method
- # 5. call using functools.partial
-
- # A list of (function, args, kwargs, result) calls to test
- calls = [(len, (range(42),), {}, 42),
- (list.append, ([], 0), {}, None),
- ([].append, (0,), {}, None),
- (sum, ([36],), {"start":6}, 42),
- (testfunction, (42,), {}, 42),
- (testfunction_kw, (42,), {"kw":None}, 42),
- (_testcapi.MethodDescriptorBase(), (0,), {}, True),
- (_testcapi.MethodDescriptorDerived(), (0,), {}, True),
- (_testcapi.MethodDescriptor2(), (0,), {}, False)]
-
- from _testcapi import pyobject_vectorcall, pyvectorcall_call
- from types import MethodType
- from functools import partial
-
- def vectorcall(func, args, kwargs):
- args = *args, *kwargs.values()
- kwnames = tuple(kwargs)
- return pyobject_vectorcall(func, args, kwnames)
-
- for (func, args, kwargs, expected) in calls:
- with self.subTest(str(func)):
- if not kwargs:
- self.assertEqual(expected, pyvectorcall_call(func, args))
- self.assertEqual(expected, pyvectorcall_call(func, args, kwargs))
-
- # Add derived classes (which do not support vectorcall directly,
- # but do support all other ways of calling).
-
- class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
- pass
-
- class MethodDescriptorOverridden(_testcapi.MethodDescriptorBase):
- def __call__(self, n):
- return 'new'
-
- calls += [
- (MethodDescriptorHeap(), (0,), {}, True),
- (MethodDescriptorOverridden(), (0,), {}, 'new'),
- ]
-
- for (func, args, kwargs, expected) in calls:
- with self.subTest(str(func)):
- args1 = args[1:]
- meth = MethodType(func, args[0])
- wrapped = partial(func)
- if not kwargs:
- self.assertEqual(expected, func(*args))
- self.assertEqual(expected, pyobject_vectorcall(func, args, None))
- self.assertEqual(expected, meth(*args1))
- self.assertEqual(expected, wrapped(*args))
- self.assertEqual(expected, func(*args, **kwargs))
- self.assertEqual(expected, vectorcall(func, args, kwargs))
- self.assertEqual(expected, meth(*args1, **kwargs))
- self.assertEqual(expected, wrapped(*args, **kwargs))
-
-
class SubinterpreterTest(unittest.TestCase):
def test_subinterps(self):