mirror of https://github.com/python/cpython.git
324 lines
12 KiB
Python
324 lines
12 KiB
Python
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()
|