bpo-37191: Move TestPEP590 from test_capi to test_call (GH-13892) · python/cpython@740a84d (original) (raw)
`@@ -27,18 +27,11 @@
`
27
27
`# Were we compiled --with-pydebug or with #define Py_DEBUG?
`
28
28
`Py_DEBUG = hasattr(sys, 'gettotalrefcount')
`
29
29
``
30
``
`-
Py_TPFLAGS_HAVE_VECTORCALL = 1 << 11
`
31
``
`-
Py_TPFLAGS_METHOD_DESCRIPTOR = 1 << 17
`
32
``
-
33
30
``
34
31
`def testfunction(self):
`
35
32
`"""some doc"""
`
36
33
`return self
`
37
34
``
38
``
`-
def testfunction_kw(self, *, kw):
`
39
``
`-
"""some doc"""
`
40
``
`-
return self
`
41
``
-
42
35
``
43
36
`class InstanceMethod:
`
44
37
`id = _testcapi.instancemethod(id)
`
`@@ -471,114 +464,6 @@ def test_pendingcalls_non_threaded(self):
`
471
464
`self.pendingcalls_wait(l, n)
`
472
465
``
473
466
``
474
``
`-
class TestPEP590(unittest.TestCase):
`
475
``
-
476
``
`-
def test_method_descriptor_flag(self):
`
477
``
`-
import functools
`
478
``
`-
cached = functools.lru_cache(1)(testfunction)
`
479
``
-
480
``
`-
self.assertFalse(type(repr).flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
481
``
`-
self.assertTrue(type(list.append).flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
482
``
`-
self.assertTrue(type(list.add).flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
483
``
`-
self.assertTrue(type(testfunction).flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
484
``
`-
self.assertTrue(type(cached).flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
485
``
-
486
``
`-
self.assertTrue(_testcapi.MethodDescriptorBase.flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
487
``
`-
self.assertTrue(_testcapi.MethodDescriptorDerived.flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
488
``
`-
self.assertFalse(_testcapi.MethodDescriptorNopGet.flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
489
``
-
490
``
`-
Heap type should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR
`
491
``
`-
class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
`
492
``
`-
pass
`
493
``
`-
self.assertFalse(MethodDescriptorHeap.flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
`
494
``
-
495
``
`-
def test_vectorcall_flag(self):
`
496
``
`-
self.assertTrue(_testcapi.MethodDescriptorBase.flags & Py_TPFLAGS_HAVE_VECTORCALL)
`
497
``
`-
self.assertTrue(_testcapi.MethodDescriptorDerived.flags & Py_TPFLAGS_HAVE_VECTORCALL)
`
498
``
`-
self.assertFalse(_testcapi.MethodDescriptorNopGet.flags & Py_TPFLAGS_HAVE_VECTORCALL)
`
499
``
`-
self.assertTrue(_testcapi.MethodDescriptor2.flags & Py_TPFLAGS_HAVE_VECTORCALL)
`
500
``
-
501
``
`-
Heap type should not inherit Py_TPFLAGS_HAVE_VECTORCALL
`
502
``
`-
class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
`
503
``
`-
pass
`
504
``
`-
self.assertFalse(MethodDescriptorHeap.flags & Py_TPFLAGS_HAVE_VECTORCALL)
`
505
``
-
506
``
`-
def test_vectorcall_override(self):
`
507
``
`-
Check that tp_call can correctly override vectorcall.
`
508
``
`-
MethodDescriptorNopGet implements tp_call but it inherits from
`
509
``
`-
MethodDescriptorBase, which implements vectorcall. Since
`
510
``
`-
MethodDescriptorNopGet returns the args tuple when called, we check
`
511
``
`-
additionally that no new tuple is created for this call.
`
512
``
`-
args = tuple(range(5))
`
513
``
`-
f = _testcapi.MethodDescriptorNopGet()
`
514
``
`-
self.assertIs(f(*args), args)
`
515
``
-
516
``
`-
def test_vectorcall(self):
`
517
``
`-
Test a bunch of different ways to call objects:
`
518
``
`-
1. vectorcall using PyVectorcall_Call()
`
519
``
`-
(only for objects that support vectorcall directly)
`
520
``
`-
2. normal call
`
521
``
`-
3. vectorcall using _PyObject_Vectorcall()
`
522
``
`-
4. call as bound method
`
523
``
`-
5. call using functools.partial
`
524
``
-
525
``
`-
A list of (function, args, kwargs, result) calls to test
`
526
``
`-
calls = [(len, (range(42),), {}, 42),
`
527
``
`-
(list.append, ([], 0), {}, None),
`
528
``
`-
([].append, (0,), {}, None),
`
529
``
`-
(sum, ([36],), {"start":6}, 42),
`
530
``
`-
(testfunction, (42,), {}, 42),
`
531
``
`-
(testfunction_kw, (42,), {"kw":None}, 42),
`
532
``
`-
(_testcapi.MethodDescriptorBase(), (0,), {}, True),
`
533
``
`-
(_testcapi.MethodDescriptorDerived(), (0,), {}, True),
`
534
``
`-
(_testcapi.MethodDescriptor2(), (0,), {}, False)]
`
535
``
-
536
``
`-
from _testcapi import pyobject_vectorcall, pyvectorcall_call
`
537
``
`-
from types import MethodType
`
538
``
`-
from functools import partial
`
539
``
-
540
``
`-
def vectorcall(func, args, kwargs):
`
541
``
`-
args = *args, *kwargs.values()
`
542
``
`-
kwnames = tuple(kwargs)
`
543
``
`-
return pyobject_vectorcall(func, args, kwnames)
`
544
``
-
545
``
`-
for (func, args, kwargs, expected) in calls:
`
546
``
`-
with self.subTest(str(func)):
`
547
``
`-
if not kwargs:
`
548
``
`-
self.assertEqual(expected, pyvectorcall_call(func, args))
`
549
``
`-
self.assertEqual(expected, pyvectorcall_call(func, args, kwargs))
`
550
``
-
551
``
`-
Add derived classes (which do not support vectorcall directly,
`
552
``
`-
but do support all other ways of calling).
`
553
``
-
554
``
`-
class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
`
555
``
`-
pass
`
556
``
-
557
``
`-
class MethodDescriptorOverridden(_testcapi.MethodDescriptorBase):
`
558
``
`-
def call(self, n):
`
559
``
`-
return 'new'
`
560
``
-
561
``
`-
calls += [
`
562
``
`-
(MethodDescriptorHeap(), (0,), {}, True),
`
563
``
`-
(MethodDescriptorOverridden(), (0,), {}, 'new'),
`
564
``
`-
]
`
565
``
-
566
``
`-
for (func, args, kwargs, expected) in calls:
`
567
``
`-
with self.subTest(str(func)):
`
568
``
`-
args1 = args[1:]
`
569
``
`-
meth = MethodType(func, args[0])
`
570
``
`-
wrapped = partial(func)
`
571
``
`-
if not kwargs:
`
572
``
`-
self.assertEqual(expected, func(*args))
`
573
``
`-
self.assertEqual(expected, pyobject_vectorcall(func, args, None))
`
574
``
`-
self.assertEqual(expected, meth(*args1))
`
575
``
`-
self.assertEqual(expected, wrapped(*args))
`
576
``
`-
self.assertEqual(expected, func(*args, **kwargs))
`
577
``
`-
self.assertEqual(expected, vectorcall(func, args, kwargs))
`
578
``
`-
self.assertEqual(expected, meth(*args1, **kwargs))
`
579
``
`-
self.assertEqual(expected, wrapped(*args, **kwargs))
`
580
``
-
581
``
-
582
467
`class SubinterpreterTest(unittest.TestCase):
`
583
468
``
584
469
`def test_subinterps(self):
`