Skip to content

Commit

Permalink
Merge pull request #567 from frmdstryr/funchelper-updates
Browse files Browse the repository at this point in the history
Update funchelper call_func
  • Loading branch information
MatthieuDartiailh authored Jan 18, 2025
2 parents aa286f0 + b0c9e78 commit 1f13f6a
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
23 changes: 12 additions & 11 deletions enaml/src/funchelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 == 4 || nargs == 3) )
{
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" );
Expand Down Expand Up @@ -64,11 +65,11 @@ call_func( PyObject* mod, PyObject* args )
if( ( argdefs ) && PyTuple_Check( argdefs ) )
{
defaults = &PyTuple_GET_ITEM( reinterpret_cast<PyTupleObject*>( 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 );
Expand All @@ -90,7 +91,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 )
);
Expand All @@ -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
};
Expand Down
4 changes: 4 additions & 0 deletions tests/core/test_funchelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit 1f13f6a

Please sign in to comment.