From 76a8189a8e543d9a1280801d5b028e88281b997a Mon Sep 17 00:00:00 2001 From: frmdstryr Date: Thu, 16 Jan 2025 12:51:44 -0500 Subject: [PATCH 1/3] Replace funchelper's call_func PyX_Size calls with PyX_GET_SIZE --- enaml/src/funchelper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enaml/src/funchelper.cpp b/enaml/src/funchelper.cpp index cef839324..8ca791d65 100644 --- a/enaml/src/funchelper.cpp +++ b/enaml/src/funchelper.cpp @@ -64,11 +64,11 @@ call_func( PyObject* mod, PyObject* args ) if( ( argdefs ) && PyTuple_Check( argdefs ) ) { defaults = &PyTuple_GET_ITEM( reinterpret_cast( argdefs ), 0 ); - num_defaults = PyTuple_Size( argdefs ); + num_defaults = PyTuple_GET_SIZE( argdefs ); } PyObject** keywords = 0; - Py_ssize_t num_keywords = PyDict_Size( func_kwargs ); + Py_ssize_t num_keywords = PyDict_GET_SIZE( func_kwargs ); if( num_keywords > 0 ) { keywords = PyMem_NEW( PyObject*, 2 * num_keywords ); @@ -90,7 +90,7 @@ call_func( PyObject* mod, PyObject* args ) PyFunction_GET_GLOBALS( func ), func_locals, &PyTuple_GET_ITEM( func_args, 0 ), - PyTuple_Size( func_args ), + PyTuple_GET_SIZE( func_args ), keywords, num_keywords, defaults, num_defaults, NULL, PyFunction_GET_CLOSURE( func ) ); From d90183bb2f86b79daaa44af95609856e13d9444c Mon Sep 17 00:00:00 2001 From: frmdstryr Date: Thu, 16 Jan 2025 13:16:24 -0500 Subject: [PATCH 2/3] Update call_func to use fastcall --- enaml/src/funchelper.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/enaml/src/funchelper.cpp b/enaml/src/funchelper.cpp index 8ca791d65..42553e9cb 100644 --- a/enaml/src/funchelper.cpp +++ b/enaml/src/funchelper.cpp @@ -20,18 +20,19 @@ from Python's funcobject.c */ PyObject* -call_func( PyObject* mod, PyObject* args ) +call_func( PyObject* mod, PyObject *const *args, Py_ssize_t nargs ) { - PyObject* func; - PyObject* func_args; - PyObject* func_kwargs; - PyObject* func_locals = Py_None; - - if( !PyArg_UnpackTuple( args, "call_func", 3, 4, &func, &func_args, &func_kwargs, &func_locals ) ) + if( !(nargs == 3 || nargs == 4) ) { + PyErr_SetString( PyExc_TypeError, "call_func must have 3 or 4 arguments" ); return 0; } + PyObject* func = args[0]; + PyObject* func_args = args[1]; + PyObject* func_kwargs = args[2]; + PyObject* func_locals = nargs == 4 ? args[3] : Py_None; + if( !PyFunction_Check( func ) ) { PyErr_SetString( PyExc_TypeError, "function must be a Python function" ); @@ -115,7 +116,7 @@ funchelper_modexec( PyObject *mod ) static PyMethodDef funchelper_methods[] = { - { "call_func", ( PyCFunction )call_func, METH_VARARGS, + { "call_func", ( PyCFunction )call_func, METH_FASTCALL, "call_func(func, args, kwargs[, locals])" }, { 0 } // sentinel }; From b0c9e78abaa3b601950a47a4b9a13e254cf0f02b Mon Sep 17 00:00:00 2001 From: frmdstryr Date: Thu, 16 Jan 2025 13:38:26 -0500 Subject: [PATCH 3/3] Update test and test nargs==4 first --- enaml/src/funchelper.cpp | 2 +- tests/core/test_funchelper.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/enaml/src/funchelper.cpp b/enaml/src/funchelper.cpp index 42553e9cb..2e18fe00b 100644 --- a/enaml/src/funchelper.cpp +++ b/enaml/src/funchelper.cpp @@ -22,7 +22,7 @@ from Python's funcobject.c PyObject* call_func( PyObject* mod, PyObject *const *args, Py_ssize_t nargs ) { - if( !(nargs == 3 || nargs == 4) ) + if( !(nargs == 4 || nargs == 3) ) { PyErr_SetString( PyExc_TypeError, "call_func must have 3 or 4 arguments" ); return 0; diff --git a/tests/core/test_funchelper.py b/tests/core/test_funchelper.py index 2897f2841..f847afc14 100644 --- a/tests/core/test_funchelper.py +++ b/tests/core/test_funchelper.py @@ -67,3 +67,7 @@ def test_handling_wrong_arguments(): with pytest.raises(TypeError) as excinfo: call_func(func, (), {}, 1) assert 'mapping' in excinfo.exconly() + + with pytest.raises(TypeError) as excinfo: + call_func(func, ()) + assert 'must have 3 or 4 arguments' in excinfo.exconly()