mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-93649: Add Modules/_testcapi/function.c file (#129521)
* Move PyFunction C API tests to a new file. * Add Lib/test/test_capi/test_function.py. * Move tests from test_capi.test_misc to test_capi.test_function.
This commit is contained in:
parent
fad36bf382
commit
60a85415ae
8 changed files with 476 additions and 413 deletions
323
Lib/test/test_capi/test_function.py
Normal file
323
Lib/test/test_capi/test_function.py
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
import unittest
|
||||||
|
from test.support import import_helper
|
||||||
|
|
||||||
|
|
||||||
|
_testcapi = import_helper.import_module('_testcapi')
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionTest(unittest.TestCase):
|
||||||
|
def test_function_get_code(self):
|
||||||
|
# Test PyFunction_GetCode()
|
||||||
|
import types
|
||||||
|
|
||||||
|
def some():
|
||||||
|
pass
|
||||||
|
|
||||||
|
code = _testcapi.function_get_code(some)
|
||||||
|
self.assertIsInstance(code, types.CodeType)
|
||||||
|
self.assertEqual(code, some.__code__)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_code(None) # not a function
|
||||||
|
|
||||||
|
def test_function_get_globals(self):
|
||||||
|
# Test PyFunction_GetGlobals()
|
||||||
|
def some():
|
||||||
|
pass
|
||||||
|
|
||||||
|
globals_ = _testcapi.function_get_globals(some)
|
||||||
|
self.assertIsInstance(globals_, dict)
|
||||||
|
self.assertEqual(globals_, some.__globals__)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_globals(None) # not a function
|
||||||
|
|
||||||
|
def test_function_get_module(self):
|
||||||
|
# Test PyFunction_GetModule()
|
||||||
|
def some():
|
||||||
|
pass
|
||||||
|
|
||||||
|
module = _testcapi.function_get_module(some)
|
||||||
|
self.assertIsInstance(module, str)
|
||||||
|
self.assertEqual(module, some.__module__)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_module(None) # not a function
|
||||||
|
|
||||||
|
def test_function_get_defaults(self):
|
||||||
|
# Test PyFunction_GetDefaults()
|
||||||
|
def some(
|
||||||
|
pos_only1, pos_only2='p',
|
||||||
|
/,
|
||||||
|
zero=0, optional=None,
|
||||||
|
*,
|
||||||
|
kw1,
|
||||||
|
kw2=True,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
defaults = _testcapi.function_get_defaults(some)
|
||||||
|
self.assertEqual(defaults, ('p', 0, None))
|
||||||
|
self.assertEqual(defaults, some.__defaults__)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_defaults(None) # not a function
|
||||||
|
|
||||||
|
def test_function_set_defaults(self):
|
||||||
|
# Test PyFunction_SetDefaults()
|
||||||
|
def some(
|
||||||
|
pos_only1, pos_only2='p',
|
||||||
|
/,
|
||||||
|
zero=0, optional=None,
|
||||||
|
*,
|
||||||
|
kw1,
|
||||||
|
kw2=True,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
old_defaults = ('p', 0, None)
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, old_defaults)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_defaults(some, 1) # not tuple or None
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, old_defaults)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_defaults(1, ()) # not a function
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, old_defaults)
|
||||||
|
|
||||||
|
new_defaults = ('q', 1, None)
|
||||||
|
_testcapi.function_set_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, new_defaults)
|
||||||
|
|
||||||
|
# Empty tuple is fine:
|
||||||
|
new_defaults = ()
|
||||||
|
_testcapi.function_set_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, new_defaults)
|
||||||
|
|
||||||
|
class tuplesub(tuple): ... # tuple subclasses must work
|
||||||
|
|
||||||
|
new_defaults = tuplesub(((1, 2), ['a', 'b'], None))
|
||||||
|
_testcapi.function_set_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__defaults__, new_defaults)
|
||||||
|
|
||||||
|
# `None` is special, it sets `defaults` to `NULL`,
|
||||||
|
# it needs special handling in `_testcapi`:
|
||||||
|
_testcapi.function_set_defaults(some, None)
|
||||||
|
self.assertEqual(_testcapi.function_get_defaults(some), None)
|
||||||
|
self.assertEqual(some.__defaults__, None)
|
||||||
|
|
||||||
|
def test_function_get_kw_defaults(self):
|
||||||
|
# Test PyFunction_GetKwDefaults()
|
||||||
|
def some(
|
||||||
|
pos_only1, pos_only2='p',
|
||||||
|
/,
|
||||||
|
zero=0, optional=None,
|
||||||
|
*,
|
||||||
|
kw1,
|
||||||
|
kw2=True,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
defaults = _testcapi.function_get_kw_defaults(some)
|
||||||
|
self.assertEqual(defaults, {'kw2': True})
|
||||||
|
self.assertEqual(defaults, some.__kwdefaults__)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_kw_defaults(None) # not a function
|
||||||
|
|
||||||
|
def test_function_set_kw_defaults(self):
|
||||||
|
# Test PyFunction_SetKwDefaults()
|
||||||
|
def some(
|
||||||
|
pos_only1, pos_only2='p',
|
||||||
|
/,
|
||||||
|
zero=0, optional=None,
|
||||||
|
*,
|
||||||
|
kw1,
|
||||||
|
kw2=True,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
old_defaults = {'kw2': True}
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, old_defaults)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_kw_defaults(some, 1) # not dict or None
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, old_defaults)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_kw_defaults(1, {}) # not a function
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, old_defaults)
|
||||||
|
|
||||||
|
new_defaults = {'kw2': (1, 2, 3)}
|
||||||
|
_testcapi.function_set_kw_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, new_defaults)
|
||||||
|
|
||||||
|
# Empty dict is fine:
|
||||||
|
new_defaults = {}
|
||||||
|
_testcapi.function_set_kw_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, new_defaults)
|
||||||
|
|
||||||
|
class dictsub(dict): ... # dict subclasses must work
|
||||||
|
|
||||||
|
new_defaults = dictsub({'kw2': None})
|
||||||
|
_testcapi.function_set_kw_defaults(some, new_defaults)
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
||||||
|
self.assertEqual(some.__kwdefaults__, new_defaults)
|
||||||
|
|
||||||
|
# `None` is special, it sets `kwdefaults` to `NULL`,
|
||||||
|
# it needs special handling in `_testcapi`:
|
||||||
|
_testcapi.function_set_kw_defaults(some, None)
|
||||||
|
self.assertEqual(_testcapi.function_get_kw_defaults(some), None)
|
||||||
|
self.assertEqual(some.__kwdefaults__, None)
|
||||||
|
|
||||||
|
def test_function_get_closure(self):
|
||||||
|
# Test PyFunction_GetClosure()
|
||||||
|
from types import CellType
|
||||||
|
|
||||||
|
def regular_function(): ...
|
||||||
|
def unused_one_level(arg1):
|
||||||
|
def inner(arg2, arg3): ...
|
||||||
|
return inner
|
||||||
|
def unused_two_levels(arg1, arg2):
|
||||||
|
def decorator(arg3, arg4):
|
||||||
|
def inner(arg5, arg6): ...
|
||||||
|
return inner
|
||||||
|
return decorator
|
||||||
|
def with_one_level(arg1):
|
||||||
|
def inner(arg2, arg3):
|
||||||
|
return arg1 + arg2 + arg3
|
||||||
|
return inner
|
||||||
|
def with_two_levels(arg1, arg2):
|
||||||
|
def decorator(arg3, arg4):
|
||||||
|
def inner(arg5, arg6):
|
||||||
|
return arg1 + arg2 + arg3 + arg4 + arg5 + arg6
|
||||||
|
return inner
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
# Functions without closures:
|
||||||
|
self.assertIsNone(_testcapi.function_get_closure(regular_function))
|
||||||
|
self.assertIsNone(regular_function.__closure__)
|
||||||
|
|
||||||
|
func = unused_one_level(1)
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertIsNone(closure)
|
||||||
|
self.assertIsNone(func.__closure__)
|
||||||
|
|
||||||
|
func = unused_two_levels(1, 2)(3, 4)
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertIsNone(closure)
|
||||||
|
self.assertIsNone(func.__closure__)
|
||||||
|
|
||||||
|
# Functions with closures:
|
||||||
|
func = with_one_level(5)
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertEqual(closure, func.__closure__)
|
||||||
|
self.assertIsInstance(closure, tuple)
|
||||||
|
self.assertEqual(len(closure), 1)
|
||||||
|
self.assertEqual(len(closure), len(func.__code__.co_freevars))
|
||||||
|
for cell in closure:
|
||||||
|
self.assertIsInstance(cell, CellType)
|
||||||
|
self.assertTrue(closure[0].cell_contents, 5)
|
||||||
|
|
||||||
|
func = with_two_levels(1, 2)(3, 4)
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertEqual(closure, func.__closure__)
|
||||||
|
self.assertIsInstance(closure, tuple)
|
||||||
|
self.assertEqual(len(closure), 4)
|
||||||
|
self.assertEqual(len(closure), len(func.__code__.co_freevars))
|
||||||
|
for cell in closure:
|
||||||
|
self.assertIsInstance(cell, CellType)
|
||||||
|
self.assertEqual([cell.cell_contents for cell in closure],
|
||||||
|
[1, 2, 3, 4])
|
||||||
|
|
||||||
|
def test_function_get_closure_error(self):
|
||||||
|
# Test PyFunction_GetClosure()
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_closure(1)
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_get_closure(None)
|
||||||
|
|
||||||
|
def test_function_set_closure(self):
|
||||||
|
# Test PyFunction_SetClosure()
|
||||||
|
from types import CellType
|
||||||
|
|
||||||
|
def function_without_closure(): ...
|
||||||
|
def function_with_closure(arg):
|
||||||
|
def inner():
|
||||||
|
return arg
|
||||||
|
return inner
|
||||||
|
|
||||||
|
func = function_without_closure
|
||||||
|
_testcapi.function_set_closure(func, (CellType(1), CellType(1)))
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertEqual([c.cell_contents for c in closure], [1, 1])
|
||||||
|
self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1])
|
||||||
|
|
||||||
|
func = function_with_closure(1)
|
||||||
|
_testcapi.function_set_closure(func,
|
||||||
|
(CellType(1), CellType(2), CellType(3)))
|
||||||
|
closure = _testcapi.function_get_closure(func)
|
||||||
|
self.assertEqual([c.cell_contents for c in closure], [1, 2, 3])
|
||||||
|
self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3])
|
||||||
|
|
||||||
|
def test_function_set_closure_none(self):
|
||||||
|
# Test PyFunction_SetClosure()
|
||||||
|
def function_without_closure(): ...
|
||||||
|
def function_with_closure(arg):
|
||||||
|
def inner():
|
||||||
|
return arg
|
||||||
|
return inner
|
||||||
|
|
||||||
|
_testcapi.function_set_closure(function_without_closure, None)
|
||||||
|
self.assertIsNone(
|
||||||
|
_testcapi.function_get_closure(function_without_closure))
|
||||||
|
self.assertIsNone(function_without_closure.__closure__)
|
||||||
|
|
||||||
|
_testcapi.function_set_closure(function_with_closure, None)
|
||||||
|
self.assertIsNone(
|
||||||
|
_testcapi.function_get_closure(function_with_closure))
|
||||||
|
self.assertIsNone(function_with_closure.__closure__)
|
||||||
|
|
||||||
|
def test_function_set_closure_errors(self):
|
||||||
|
# Test PyFunction_SetClosure()
|
||||||
|
def function_without_closure(): ...
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_closure(None, ()) # not a function
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.function_set_closure(function_without_closure, 1)
|
||||||
|
self.assertIsNone(function_without_closure.__closure__) # no change
|
||||||
|
|
||||||
|
# NOTE: this works, but goes against the docs:
|
||||||
|
_testcapi.function_set_closure(function_without_closure, (1, 2))
|
||||||
|
self.assertEqual(
|
||||||
|
_testcapi.function_get_closure(function_without_closure), (1, 2))
|
||||||
|
self.assertEqual(function_without_closure.__closure__, (1, 2))
|
||||||
|
|
||||||
|
# TODO: test PyFunction_New()
|
||||||
|
# TODO: test PyFunction_NewWithQualName()
|
||||||
|
# TODO: test PyFunction_SetVectorcall()
|
||||||
|
# TODO: test PyFunction_GetAnnotations()
|
||||||
|
# TODO: test PyFunction_SetAnnotations()
|
||||||
|
# TODO: test PyClassMethod_New()
|
||||||
|
# TODO: test PyStaticMethod_New()
|
||||||
|
#
|
||||||
|
# PyFunction_AddWatcher() and PyFunction_ClearWatcher() are tested by
|
||||||
|
# test_capi.test_watchers.
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
|
@ -928,175 +928,6 @@ class CAPITest(unittest.TestCase):
|
||||||
_testcapi.clear_managed_dict(c)
|
_testcapi.clear_managed_dict(c)
|
||||||
self.assertEqual(c.__dict__, {})
|
self.assertEqual(c.__dict__, {})
|
||||||
|
|
||||||
def test_function_get_code(self):
|
|
||||||
import types
|
|
||||||
|
|
||||||
def some():
|
|
||||||
pass
|
|
||||||
|
|
||||||
code = _testcapi.function_get_code(some)
|
|
||||||
self.assertIsInstance(code, types.CodeType)
|
|
||||||
self.assertEqual(code, some.__code__)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_code(None) # not a function
|
|
||||||
|
|
||||||
def test_function_get_globals(self):
|
|
||||||
def some():
|
|
||||||
pass
|
|
||||||
|
|
||||||
globals_ = _testcapi.function_get_globals(some)
|
|
||||||
self.assertIsInstance(globals_, dict)
|
|
||||||
self.assertEqual(globals_, some.__globals__)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_globals(None) # not a function
|
|
||||||
|
|
||||||
def test_function_get_module(self):
|
|
||||||
def some():
|
|
||||||
pass
|
|
||||||
|
|
||||||
module = _testcapi.function_get_module(some)
|
|
||||||
self.assertIsInstance(module, str)
|
|
||||||
self.assertEqual(module, some.__module__)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_module(None) # not a function
|
|
||||||
|
|
||||||
def test_function_get_defaults(self):
|
|
||||||
def some(
|
|
||||||
pos_only1, pos_only2='p',
|
|
||||||
/,
|
|
||||||
zero=0, optional=None,
|
|
||||||
*,
|
|
||||||
kw1,
|
|
||||||
kw2=True,
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
defaults = _testcapi.function_get_defaults(some)
|
|
||||||
self.assertEqual(defaults, ('p', 0, None))
|
|
||||||
self.assertEqual(defaults, some.__defaults__)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_defaults(None) # not a function
|
|
||||||
|
|
||||||
def test_function_set_defaults(self):
|
|
||||||
def some(
|
|
||||||
pos_only1, pos_only2='p',
|
|
||||||
/,
|
|
||||||
zero=0, optional=None,
|
|
||||||
*,
|
|
||||||
kw1,
|
|
||||||
kw2=True,
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
old_defaults = ('p', 0, None)
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, old_defaults)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_defaults(some, 1) # not tuple or None
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, old_defaults)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_defaults(1, ()) # not a function
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, old_defaults)
|
|
||||||
|
|
||||||
new_defaults = ('q', 1, None)
|
|
||||||
_testcapi.function_set_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, new_defaults)
|
|
||||||
|
|
||||||
# Empty tuple is fine:
|
|
||||||
new_defaults = ()
|
|
||||||
_testcapi.function_set_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, new_defaults)
|
|
||||||
|
|
||||||
class tuplesub(tuple): ... # tuple subclasses must work
|
|
||||||
|
|
||||||
new_defaults = tuplesub(((1, 2), ['a', 'b'], None))
|
|
||||||
_testcapi.function_set_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__defaults__, new_defaults)
|
|
||||||
|
|
||||||
# `None` is special, it sets `defaults` to `NULL`,
|
|
||||||
# it needs special handling in `_testcapi`:
|
|
||||||
_testcapi.function_set_defaults(some, None)
|
|
||||||
self.assertEqual(_testcapi.function_get_defaults(some), None)
|
|
||||||
self.assertEqual(some.__defaults__, None)
|
|
||||||
|
|
||||||
def test_function_get_kw_defaults(self):
|
|
||||||
def some(
|
|
||||||
pos_only1, pos_only2='p',
|
|
||||||
/,
|
|
||||||
zero=0, optional=None,
|
|
||||||
*,
|
|
||||||
kw1,
|
|
||||||
kw2=True,
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
defaults = _testcapi.function_get_kw_defaults(some)
|
|
||||||
self.assertEqual(defaults, {'kw2': True})
|
|
||||||
self.assertEqual(defaults, some.__kwdefaults__)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_kw_defaults(None) # not a function
|
|
||||||
|
|
||||||
def test_function_set_kw_defaults(self):
|
|
||||||
def some(
|
|
||||||
pos_only1, pos_only2='p',
|
|
||||||
/,
|
|
||||||
zero=0, optional=None,
|
|
||||||
*,
|
|
||||||
kw1,
|
|
||||||
kw2=True,
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
old_defaults = {'kw2': True}
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, old_defaults)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_kw_defaults(some, 1) # not dict or None
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, old_defaults)
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_kw_defaults(1, {}) # not a function
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, old_defaults)
|
|
||||||
|
|
||||||
new_defaults = {'kw2': (1, 2, 3)}
|
|
||||||
_testcapi.function_set_kw_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, new_defaults)
|
|
||||||
|
|
||||||
# Empty dict is fine:
|
|
||||||
new_defaults = {}
|
|
||||||
_testcapi.function_set_kw_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, new_defaults)
|
|
||||||
|
|
||||||
class dictsub(dict): ... # dict subclasses must work
|
|
||||||
|
|
||||||
new_defaults = dictsub({'kw2': None})
|
|
||||||
_testcapi.function_set_kw_defaults(some, new_defaults)
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults)
|
|
||||||
self.assertEqual(some.__kwdefaults__, new_defaults)
|
|
||||||
|
|
||||||
# `None` is special, it sets `kwdefaults` to `NULL`,
|
|
||||||
# it needs special handling in `_testcapi`:
|
|
||||||
_testcapi.function_set_kw_defaults(some, None)
|
|
||||||
self.assertEqual(_testcapi.function_get_kw_defaults(some), None)
|
|
||||||
self.assertEqual(some.__kwdefaults__, None)
|
|
||||||
|
|
||||||
def test_unstable_gc_new_with_extra_data(self):
|
def test_unstable_gc_new_with_extra_data(self):
|
||||||
class Data(_testcapi.ObjExtraData):
|
class Data(_testcapi.ObjExtraData):
|
||||||
__slots__ = ('x', 'y')
|
__slots__ = ('x', 'y')
|
||||||
|
@ -1319,127 +1150,6 @@ class TestHeapTypeRelative(unittest.TestCase):
|
||||||
_testcapi.pyobject_getitemdata(0)
|
_testcapi.pyobject_getitemdata(0)
|
||||||
|
|
||||||
|
|
||||||
def test_function_get_closure(self):
|
|
||||||
from types import CellType
|
|
||||||
|
|
||||||
def regular_function(): ...
|
|
||||||
def unused_one_level(arg1):
|
|
||||||
def inner(arg2, arg3): ...
|
|
||||||
return inner
|
|
||||||
def unused_two_levels(arg1, arg2):
|
|
||||||
def decorator(arg3, arg4):
|
|
||||||
def inner(arg5, arg6): ...
|
|
||||||
return inner
|
|
||||||
return decorator
|
|
||||||
def with_one_level(arg1):
|
|
||||||
def inner(arg2, arg3):
|
|
||||||
return arg1 + arg2 + arg3
|
|
||||||
return inner
|
|
||||||
def with_two_levels(arg1, arg2):
|
|
||||||
def decorator(arg3, arg4):
|
|
||||||
def inner(arg5, arg6):
|
|
||||||
return arg1 + arg2 + arg3 + arg4 + arg5 + arg6
|
|
||||||
return inner
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
# Functions without closures:
|
|
||||||
self.assertIsNone(_testcapi.function_get_closure(regular_function))
|
|
||||||
self.assertIsNone(regular_function.__closure__)
|
|
||||||
|
|
||||||
func = unused_one_level(1)
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertIsNone(closure)
|
|
||||||
self.assertIsNone(func.__closure__)
|
|
||||||
|
|
||||||
func = unused_two_levels(1, 2)(3, 4)
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertIsNone(closure)
|
|
||||||
self.assertIsNone(func.__closure__)
|
|
||||||
|
|
||||||
# Functions with closures:
|
|
||||||
func = with_one_level(5)
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertEqual(closure, func.__closure__)
|
|
||||||
self.assertIsInstance(closure, tuple)
|
|
||||||
self.assertEqual(len(closure), 1)
|
|
||||||
self.assertEqual(len(closure), len(func.__code__.co_freevars))
|
|
||||||
for cell in closure:
|
|
||||||
self.assertIsInstance(cell, CellType)
|
|
||||||
self.assertTrue(closure[0].cell_contents, 5)
|
|
||||||
|
|
||||||
func = with_two_levels(1, 2)(3, 4)
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertEqual(closure, func.__closure__)
|
|
||||||
self.assertIsInstance(closure, tuple)
|
|
||||||
self.assertEqual(len(closure), 4)
|
|
||||||
self.assertEqual(len(closure), len(func.__code__.co_freevars))
|
|
||||||
for cell in closure:
|
|
||||||
self.assertIsInstance(cell, CellType)
|
|
||||||
self.assertEqual([cell.cell_contents for cell in closure],
|
|
||||||
[1, 2, 3, 4])
|
|
||||||
|
|
||||||
def test_function_get_closure_error(self):
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_closure(1)
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_get_closure(None)
|
|
||||||
|
|
||||||
def test_function_set_closure(self):
|
|
||||||
from types import CellType
|
|
||||||
|
|
||||||
def function_without_closure(): ...
|
|
||||||
def function_with_closure(arg):
|
|
||||||
def inner():
|
|
||||||
return arg
|
|
||||||
return inner
|
|
||||||
|
|
||||||
func = function_without_closure
|
|
||||||
_testcapi.function_set_closure(func, (CellType(1), CellType(1)))
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertEqual([c.cell_contents for c in closure], [1, 1])
|
|
||||||
self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1])
|
|
||||||
|
|
||||||
func = function_with_closure(1)
|
|
||||||
_testcapi.function_set_closure(func,
|
|
||||||
(CellType(1), CellType(2), CellType(3)))
|
|
||||||
closure = _testcapi.function_get_closure(func)
|
|
||||||
self.assertEqual([c.cell_contents for c in closure], [1, 2, 3])
|
|
||||||
self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3])
|
|
||||||
|
|
||||||
def test_function_set_closure_none(self):
|
|
||||||
def function_without_closure(): ...
|
|
||||||
def function_with_closure(arg):
|
|
||||||
def inner():
|
|
||||||
return arg
|
|
||||||
return inner
|
|
||||||
|
|
||||||
_testcapi.function_set_closure(function_without_closure, None)
|
|
||||||
self.assertIsNone(
|
|
||||||
_testcapi.function_get_closure(function_without_closure))
|
|
||||||
self.assertIsNone(function_without_closure.__closure__)
|
|
||||||
|
|
||||||
_testcapi.function_set_closure(function_with_closure, None)
|
|
||||||
self.assertIsNone(
|
|
||||||
_testcapi.function_get_closure(function_with_closure))
|
|
||||||
self.assertIsNone(function_with_closure.__closure__)
|
|
||||||
|
|
||||||
def test_function_set_closure_errors(self):
|
|
||||||
def function_without_closure(): ...
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_closure(None, ()) # not a function
|
|
||||||
|
|
||||||
with self.assertRaises(SystemError):
|
|
||||||
_testcapi.function_set_closure(function_without_closure, 1)
|
|
||||||
self.assertIsNone(function_without_closure.__closure__) # no change
|
|
||||||
|
|
||||||
# NOTE: this works, but goes against the docs:
|
|
||||||
_testcapi.function_set_closure(function_without_closure, (1, 2))
|
|
||||||
self.assertEqual(
|
|
||||||
_testcapi.function_get_closure(function_without_closure), (1, 2))
|
|
||||||
self.assertEqual(function_without_closure.__closure__, (1, 2))
|
|
||||||
|
|
||||||
|
|
||||||
class TestPendingCalls(unittest.TestCase):
|
class TestPendingCalls(unittest.TestCase):
|
||||||
|
|
||||||
# See the comment in ceval.c (at the "handle_eval_breaker" label)
|
# See the comment in ceval.c (at the "handle_eval_breaker" label)
|
||||||
|
@ -3209,5 +2919,6 @@ class TestVersions(unittest.TestCase):
|
||||||
result = ctypes_func(*args)
|
result = ctypes_func(*args)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
||||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
||||||
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
|
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
|
||||||
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c
|
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c
|
||||||
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
|
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
|
||||||
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
||||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||||
|
|
143
Modules/_testcapi/function.c
Normal file
143
Modules/_testcapi/function.c
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#include "parts.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_code(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *code = PyFunction_GetCode(func);
|
||||||
|
if (code != NULL) {
|
||||||
|
return Py_NewRef(code);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_globals(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *globals = PyFunction_GetGlobals(func);
|
||||||
|
if (globals != NULL) {
|
||||||
|
return Py_NewRef(globals);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_module(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *module = PyFunction_GetModule(func);
|
||||||
|
if (module != NULL) {
|
||||||
|
return Py_NewRef(module);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_defaults(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *defaults = PyFunction_GetDefaults(func);
|
||||||
|
if (defaults != NULL) {
|
||||||
|
return Py_NewRef(defaults);
|
||||||
|
} else if (PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
Py_RETURN_NONE; // This can happen when `defaults` are set to `None`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_set_defaults(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *func = NULL, *defaults = NULL;
|
||||||
|
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int result = PyFunction_SetDefaults(func, defaults);
|
||||||
|
if (result == -1)
|
||||||
|
return NULL;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_kw_defaults(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *defaults = PyFunction_GetKwDefaults(func);
|
||||||
|
if (defaults != NULL) {
|
||||||
|
return Py_NewRef(defaults);
|
||||||
|
} else if (PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_set_kw_defaults(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *func = NULL, *defaults = NULL;
|
||||||
|
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int result = PyFunction_SetKwDefaults(func, defaults);
|
||||||
|
if (result == -1)
|
||||||
|
return NULL;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_get_closure(PyObject *self, PyObject *func)
|
||||||
|
{
|
||||||
|
PyObject *closure = PyFunction_GetClosure(func);
|
||||||
|
if (closure != NULL) {
|
||||||
|
return Py_NewRef(closure);
|
||||||
|
} else if (PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
Py_RETURN_NONE; // This can happen when `closure` is set to `None`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
function_set_closure(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *func = NULL, *closure = NULL;
|
||||||
|
if (!PyArg_ParseTuple(args, "OO", &func, &closure)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int result = PyFunction_SetClosure(func, closure);
|
||||||
|
if (result == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyMethodDef test_methods[] = {
|
||||||
|
{"function_get_code", function_get_code, METH_O, NULL},
|
||||||
|
{"function_get_globals", function_get_globals, METH_O, NULL},
|
||||||
|
{"function_get_module", function_get_module, METH_O, NULL},
|
||||||
|
{"function_get_defaults", function_get_defaults, METH_O, NULL},
|
||||||
|
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
|
||||||
|
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
||||||
|
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||||
|
{"function_get_closure", function_get_closure, METH_O, NULL},
|
||||||
|
{"function_set_closure", function_set_closure, METH_VARARGS, NULL},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyTestCapi_Init_Function(PyObject *m)
|
||||||
|
{
|
||||||
|
return PyModule_AddFunctions(m, test_methods);
|
||||||
|
}
|
|
@ -64,5 +64,6 @@ int _PyTestCapi_Init_Config(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Import(PyObject *mod);
|
int _PyTestCapi_Init_Import(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Frame(PyObject *mod);
|
int _PyTestCapi_Init_Frame(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Type(PyObject *mod);
|
int _PyTestCapi_Init_Type(PyObject *mod);
|
||||||
|
int _PyTestCapi_Init_Function(PyObject *mod);
|
||||||
|
|
||||||
#endif // Py_TESTCAPI_PARTS_H
|
#endif // Py_TESTCAPI_PARTS_H
|
||||||
|
|
|
@ -2652,119 +2652,6 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_code(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *code = PyFunction_GetCode(func);
|
|
||||||
if (code != NULL) {
|
|
||||||
return Py_NewRef(code);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_globals(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *globals = PyFunction_GetGlobals(func);
|
|
||||||
if (globals != NULL) {
|
|
||||||
return Py_NewRef(globals);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_module(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *module = PyFunction_GetModule(func);
|
|
||||||
if (module != NULL) {
|
|
||||||
return Py_NewRef(module);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_defaults(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *defaults = PyFunction_GetDefaults(func);
|
|
||||||
if (defaults != NULL) {
|
|
||||||
return Py_NewRef(defaults);
|
|
||||||
} else if (PyErr_Occurred()) {
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
Py_RETURN_NONE; // This can happen when `defaults` are set to `None`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_set_defaults(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *func = NULL, *defaults = NULL;
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int result = PyFunction_SetDefaults(func, defaults);
|
|
||||||
if (result == -1)
|
|
||||||
return NULL;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_kw_defaults(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *defaults = PyFunction_GetKwDefaults(func);
|
|
||||||
if (defaults != NULL) {
|
|
||||||
return Py_NewRef(defaults);
|
|
||||||
} else if (PyErr_Occurred()) {
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_set_kw_defaults(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *func = NULL, *defaults = NULL;
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int result = PyFunction_SetKwDefaults(func, defaults);
|
|
||||||
if (result == -1)
|
|
||||||
return NULL;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_get_closure(PyObject *self, PyObject *func)
|
|
||||||
{
|
|
||||||
PyObject *closure = PyFunction_GetClosure(func);
|
|
||||||
if (closure != NULL) {
|
|
||||||
return Py_NewRef(closure);
|
|
||||||
} else if (PyErr_Occurred()) {
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
Py_RETURN_NONE; // This can happen when `closure` is set to `None`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
function_set_closure(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *func = NULL, *closure = NULL;
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &func, &closure)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int result = PyFunction_SetClosure(func, closure);
|
|
||||||
if (result == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||||
{
|
{
|
||||||
|
@ -3286,15 +3173,6 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"settrace_to_record", settrace_to_record, METH_O, NULL},
|
{"settrace_to_record", settrace_to_record, METH_O, NULL},
|
||||||
{"test_macros", test_macros, METH_NOARGS, NULL},
|
{"test_macros", test_macros, METH_NOARGS, NULL},
|
||||||
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
||||||
{"function_get_code", function_get_code, METH_O, NULL},
|
|
||||||
{"function_get_globals", function_get_globals, METH_O, NULL},
|
|
||||||
{"function_get_module", function_get_module, METH_O, NULL},
|
|
||||||
{"function_get_defaults", function_get_defaults, METH_O, NULL},
|
|
||||||
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
|
|
||||||
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
|
||||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
|
||||||
{"function_get_closure", function_get_closure, METH_O, NULL},
|
|
||||||
{"function_set_closure", function_set_closure, METH_VARARGS, NULL},
|
|
||||||
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
|
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
|
||||||
{"function_set_warning", function_set_warning, METH_NOARGS},
|
{"function_set_warning", function_set_warning, METH_NOARGS},
|
||||||
{"test_critical_sections", test_critical_sections, METH_NOARGS},
|
{"test_critical_sections", test_critical_sections, METH_NOARGS},
|
||||||
|
@ -4081,6 +3959,9 @@ PyInit__testcapi(void)
|
||||||
if (_PyTestCapi_Init_Type(m) < 0) {
|
if (_PyTestCapi_Init_Type(m) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (_PyTestCapi_Init_Function(m) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
PyState_AddModule(m, &_testcapimodule);
|
PyState_AddModule(m, &_testcapimodule);
|
||||||
return m;
|
return m;
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\import.c" />
|
<ClCompile Include="..\Modules\_testcapi\import.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\frame.c" />
|
<ClCompile Include="..\Modules\_testcapi\frame.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\type.c" />
|
<ClCompile Include="..\Modules\_testcapi\type.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\function.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\PC\python_nt.rc" />
|
<ResourceCompile Include="..\PC\python_nt.rc" />
|
||||||
|
|
|
@ -123,6 +123,9 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\type.c">
|
<ClCompile Include="..\Modules\_testcapi\type.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\function.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\PC\python_nt.rc">
|
<ResourceCompile Include="..\PC\python_nt.rc">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue