Example #1
0
    def test_vectorcall(self):
        # Test PyObject_Vectorcall()

        for func, args, expected in self.CALLS_POSARGS:
            with self.subTest(func=func, args=args):
                # kwnames=NULL
                result = _testcapi.pyobject_vectorcall(func, args, None)
                self.check_result(result, expected)

                # kwnames=()
                result = _testcapi.pyobject_vectorcall(func, args, ())
                self.check_result(result, expected)

                if not args:
                    # kwnames=NULL
                    result = _testcapi.pyobject_vectorcall(func, None, None)
                    self.check_result(result, expected)

                    # kwnames=()
                    result = _testcapi.pyobject_vectorcall(func, None, ())
                    self.check_result(result, expected)

        for func, args, kwargs, expected in self.CALLS_KWARGS:
            with self.subTest(func=func, args=args, kwargs=kwargs):
                kwnames = tuple(kwargs.keys())
                args = args + tuple(kwargs.values())
                result = _testcapi.pyobject_vectorcall(func, args, kwnames)
                self.check_result(result, expected)
Example #2
0
    def test_vectorcall(self):
        # Test a bunch of different ways to call objects:
        # 1. normal call
        # 2. vectorcall using _PyObject_Vectorcall()
        # 3. vectorcall using PyVectorcall_Call()
        # 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)):
                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, pyvectorcall_call(func, args))
                    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,
                                 pyvectorcall_call(func, args, kwargs))
                self.assertEqual(expected, meth(*args1, **kwargs))
                self.assertEqual(expected, wrapped(*args, **kwargs))
Example #3
0
 def vectorcall(func, args, kwargs):
     args = *args, *kwargs.values()
     kwnames = tuple(kwargs)
     return pyobject_vectorcall(func, args, kwnames)
Example #4
0
    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'

        class SuperBase:
            def __call__(self, *args):
                return super().__call__(*args)

        class MethodDescriptorSuper(SuperBase, _testcapi.MethodDescriptorBase):
            def __call__(self, *args):
                return super().__call__(*args)

        calls += [
            (dict.update, ({}, ), {
                "key": True
            }, None),
            ({}.update, ({}, ), {
                "key": True
            }, None),
            (MethodDescriptorHeap(), (0, ), {}, True),
            (MethodDescriptorOverridden(), (0, ), {}, 'new'),
            (MethodDescriptorSuper(), (0, ), {}, True),
        ]

        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))
Example #5
0
 def test_vectorcall_limited(self):
     from _testcapi import pyobject_vectorcall
     obj = _testcapi.LimitedVectorCallClass()
     self.assertEqual(pyobject_vectorcall(obj, (), ()), "vectorcall called")