# HG changeset patch # User Mike Miller # Date 1471467753 25200 # Node ID 040aff46e4dbe111cca0853e8f3c698c9d02a2b2 # Parent e89a8a37fd8a1f841d1eda3853a54a1d0fd9ea2c Refactor calling a Python function into a set of wrapper functions * oct-py-eval.cc, oct-py-eval.h (pytave::py_call_function): New function overloads to call a Python function in various ways. * pycall.cc (Fpycall): Use pytave::py_call_function. diff -r e89a8a37fd8a -r 040aff46e4db oct-py-eval.cc --- a/oct-py-eval.cc Thu Aug 11 10:29:18 2016 -0700 +++ b/oct-py-eval.cc Wed Aug 17 14:02:33 2016 -0700 @@ -26,13 +26,78 @@ #include #include +#include +#include #include "oct-py-eval.h" +#include "oct-py-util.h" +#include "octave_to_python.h" namespace pytave { PyObject * +py_call_function (const std::string& func, const octave_value_list& args) +{ + // FIXME: factor out parsing of string into a function reference + boost::python::object obj; + get_object_from_python (func, obj); + return py_call_function (obj.ptr (), args); +} + +PyObject * +py_call_function (const std::string& func, PyObject *args, PyObject *kwargs) +{ + // FIXME: factor out parsing of string into a function reference + boost::python::object obj; + get_object_from_python (func, obj); + return py_call_function (obj.ptr (), args, kwargs); +} + +PyObject * +py_call_function (PyObject *callable, const octave_value_list& args) +{ + PyObject *kwargs = 0; + PyObject *args_list = PyList_New (0); + if (! args_list) + octave_throw_bad_alloc (); + + for (int i = 0; i < args.length (); ++i) + { + boost::python::object arg; + pytave::octvalue_to_pyobj (arg, args(i)); + PyObject *obj = arg.ptr (); + + if (pytave::is_py_kwargs_argument (obj)) + kwargs = pytave::update_py_dict (kwargs, obj); + else + { + Py_INCREF (obj); + PyList_Append (args_list, obj); + } + } + + PyObject *args_tuple = PyList_AsTuple (args_list); + Py_DECREF (args_list); + + PyObject *retval = py_call_function (callable, args_tuple, kwargs); + Py_DECREF (args_tuple); + Py_XDECREF (kwargs); + + return retval; +} + +PyObject * +py_call_function (PyObject *callable, PyObject *args, PyObject *kwargs) +{ + PyObject *retval = PyEval_CallObjectWithKeywords (callable, args, kwargs); + if (! retval) + throw boost::python::error_already_set (); + + return retval; +} + +PyObject * py_run_string_safe (const std::string& expr, int start, PyObject *globals, PyObject *locals) { diff -r e89a8a37fd8a -r 040aff46e4db oct-py-eval.h --- a/oct-py-eval.h Thu Aug 11 10:29:18 2016 -0700 +++ b/oct-py-eval.h Wed Aug 17 14:02:33 2016 -0700 @@ -26,9 +26,57 @@ #include #include +class octave_value_list; + namespace pytave { +//! Call a Python function by name with the given argument list. +//! +//! The @a func string may be the name of a builtin function or of a function +//! in a loadable module in the form @c module.function. +//! +//! If @a args contains one or more values created by the @c pyargs function, +//! they are automatically interpreted as keyword arguments. +//! +//! @param func name of a Python function +//! @param args Octave argument list to be converted and passed to @a func +//! @return return value of @a func +PyObject * +py_call_function (const std::string& func, const octave_value_list& args); + +//! Call a Python function by name with arguments and keyword arguments. +//! +//! The @a func string may be the name of a builtin function or of a function +//! in a loadable module in the form @c module.function. +//! +//! @param func name of a Python function +//! @param args tuple of positional arguments +//! @param kwargs dictionary of keyword arguments +//! @return return value of @a func +PyObject * +py_call_function (const std::string& func, PyObject *args, PyObject *kwargs = 0); + +//! Call a Python function with the given argument list. +//! +//! If @a args contains one or more values created by the @c pyargs function, +//! they are automatically interpreted as keyword arguments. +//! +//! @param callable Python function or other callable object +//! @param args Octave argument list to be converted and passed to @a func +//! @return return value of @a func +PyObject * +py_call_function (PyObject *callable, const octave_value_list& args); + +//! Call a Python function with arguments and keyword arguments. +//! +//! @param callable Python function or other callable object +//! @param args tuple of positional arguments +//! @param kwargs dictionary of keyword arguments +//! @return return value of @a func +PyObject * +py_call_function (PyObject *callable, PyObject *args, PyObject *kwargs = 0); + PyObject * py_eval_string (const std::string& expr, PyObject *globals = 0, PyObject *locals = 0); diff -r e89a8a37fd8a -r 040aff46e4db pycall.cc --- a/pycall.cc Thu Aug 11 10:29:18 2016 -0700 +++ b/pycall.cc Wed Aug 17 14:02:33 2016 -0700 @@ -33,6 +33,7 @@ #define PYTAVE_DO_DECLARE_SYMBOL #include "arrayobjectdefs.h" #include "exceptions.h" +#include "oct-py-eval.h" #include "oct-py-util.h" #include "octave_to_python.h" #include "python_to_octave.h" @@ -101,32 +102,10 @@ if (callable.is_none ()) error("pycall: FUNC must be a string or a Python reference"); - PyObject *args_list = PyList_New (0); - PyObject *kwargs = 0; - for (int i = 1; i < nargin; i++) - { - object arg; - pytave::octvalue_to_pyobj (arg, args(i)); - PyObject *obj = arg.ptr (); - - if (pytave::is_py_kwargs_argument (obj)) - kwargs = pytave::update_py_dict (kwargs, obj); - else - { - Py_INCREF (obj); - PyList_Append (args_list, obj); - } - } - - PyObject *pyargs = PyList_AsTuple (args_list); - PyObject *result = PyEval_CallObjectWithKeywords (callable.ptr (), pyargs, kwargs); + octave_value_list arglist = args.slice (1, nargin - 1); + PyObject *result = pytave::py_call_function (callable.ptr (), arglist); object res = object (handle (result)); - Py_DECREF (args_list); - Py_DECREF (pyargs); - if (kwargs) - Py_DECREF (kwargs); - // Ensure reasonable "ans" behaviour, consistent with Python's "_". if (nargout > 0 || ! res.is_none ()) {