diff options
author | Nikita Sobolev <mail@sobolevn.me> | 2022-10-27 00:47:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-27 00:47:29 (GMT) |
commit | 7b24333fff51f9ca36ef19748016cc2b39ab6301 (patch) | |
tree | 8a26e5b4db2cd4ca509b822b6c96baf88495ebe7 | |
parent | 29b391b1378577825a658b14764a8ff3e0b5c958 (diff) | |
download | cpython-7b24333fff51f9ca36ef19748016cc2b39ab6301.zip cpython-7b24333fff51f9ca36ef19748016cc2b39ab6301.tar.gz cpython-7b24333fff51f9ca36ef19748016cc2b39ab6301.tar.bz2 |
gh-94808: cover `PyFunction_GetDefaults` and `PyFunction_SetDefaults` (#98449)
-rw-r--r-- | Lib/test/test_capi.py | 42 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 29 |
2 files changed, 71 insertions, 0 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 9446d47..2a35576 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -942,6 +942,48 @@ class CAPITest(unittest.TestCase): with self.assertRaises(SystemError): _testcapi.function_get_module(None) # not a function + def test_function_get_defaults(self): + def some(pos_only='p', zero=0, optional=None): + 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_module(None) # not a function + + def test_function_set_defaults(self): + def some(pos_only='p', zero=0, optional=None): + 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) + + 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) + + 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) + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index fdf2f20..bade0db 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5788,6 +5788,33 @@ function_get_module(PyObject *self, PyObject *func) } } +static PyObject * +function_get_defaults(PyObject *self, PyObject *func) +{ + PyObject *defaults = PyFunction_GetDefaults(func); + if (defaults != NULL) { + Py_INCREF(defaults); + return 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; +} + // type watchers @@ -6202,6 +6229,8 @@ static PyMethodDef TestMethods[] = { {"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}, {"add_type_watcher", add_type_watcher, METH_O, NULL}, {"clear_type_watcher", clear_type_watcher, METH_O, NULL}, {"watch_type", watch_type, METH_VARARGS, NULL}, |