Mercurial > pytave
changeset 172:29d9da90afcf
pycall: New function to pass Octave values to a Python function
* pycall.cc: Rename from py.cc. Add support for dispatching variable
length Octave arguments to a Python function.
* Makefile.am (OCT_FILES): Rename py.oct to pycall.oct.
author | Mike Miller <mtmiller@octave.org> |
---|---|
date | Thu, 07 Apr 2016 14:51:18 -0700 |
parents | b8560f97e9bf |
children | 28dc607532c2 |
files | Makefile.am py.cc pycall.cc |
diffstat | 3 files changed, 188 insertions(+), 127 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.am Thu Apr 07 14:12:09 2016 -0700 +++ b/Makefile.am Thu Apr 07 14:51:18 2016 -0700 @@ -34,7 +34,7 @@ README.md OCT_FILES = \ - py.oct \ + pycall.oct \ pyeval.oct \ pyexec.oct
--- a/py.cc Thu Apr 07 14:12:09 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - -Copyright (C) 2015-2016 Mike Miller - -This file is part of Pytave. - -Pytave is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation, either version 3 of the License, or (at your -option) any later version. - -Pytave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Pytave; see the file COPYING. If not, see -<http://www.gnu.org/licenses/>. - -*/ - -#if defined (HAVE_CONFIG_H) -# include <config.h> -#endif - -#include <boost/python.hpp> -#include <boost/python/numeric.hpp> - -#include <oct.h> - -#define PYTAVE_DO_DECLARE_SYMBOL -#include "arrayobjectdefs.h" -#include "exceptions.h" -#include "python_to_octave.h" - -using namespace boost::python; - -DEFUN_DLD (py, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} py (@var{func})\n\ -@deftypefnx {Loadable Function} {@var{x} =} py (@var{func})\n\ -@deftypefnx {Loadable Function} {@var{x} =} py (@var{func}, @var{arg1}, @var{arg2}, @dots{})\n\ -Execute method of a Python module.\n\ -\n\ -Examples:\n\ -@example\n\ -@group\n\ -y = py('__builtin__.int(6)')\n\ - @result{} y = 6\n\ -py('sys.version')\n\ - @result{} ans = ...\n\ -py('__builtin__.eval(\"4+5\")')\n\ - @result{} ans = 9\n\ -py('__builtin__.dict(one=1,two=2)')\n\ - @result{} ans =\n\ - scalar structure containing the fields:\n\ - two = 2\n\ - one = 1\n\ -@end group\n\ -@end example\n\ -@end deftypefn") -{ - octave_value_list retval; - - int nargin = args.length (); - - if (nargin != 1) - { - print_usage (); - return retval; - } - - std::string module; - std::string func = args(0).string_value (); - - size_t idx = func.rfind ("."); - if (idx != std::string::npos) - { - module = func.substr (0, idx); - func = func.substr (idx + 1); - } - - Py_Initialize (); - - try - { - object main_module = import ("__main__"); - object main_namespace = main_module.attr ("__dict__"); - - object mod = (module.empty ()) ? main_module : import (module.c_str ()); - object callable = mod.attr (func.c_str ()); - object res = callable (); - - if (! res.is_none ()) - { - octave_value val; - pytave::pyobj_to_octvalue (val, res); - retval(0) = val; - } - } - catch (pytave::object_convert_exception const &) - { - error ("py: error in return value type conversion"); - } - catch (error_already_set const &) - { - std::cerr << "in here" << std::endl; - PyObject *ptype, *pvalue, *ptraceback; - PyErr_Fetch (&ptype, &pvalue, &ptraceback); - - try - { - std::string message = extract<std::string> (pvalue); - error ("py: %s", message.c_str ()); - } - catch (error_already_set const &) - { - PyErr_Restore (ptype, pvalue, ptraceback); - PyErr_Print (); - } - } - - return retval; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pycall.cc Thu Apr 07 14:51:18 2016 -0700 @@ -0,0 +1,187 @@ +/* + +Copyright (C) 2015-2016 Mike Miller + +This file is part of Pytave. + +Pytave is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Pytave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pytave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <boost/python.hpp> +#include <boost/python/numeric.hpp> + +#include <oct.h> + +#define PYTAVE_DO_DECLARE_SYMBOL +#include "arrayobjectdefs.h" +#include "exceptions.h" +#include "octave_to_python.h" +#include "python_to_octave.h" + +using namespace boost::python; + +DEFUN_DLD (pycall, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} pycall (@var{func})\n\ +@deftypefnx {Loadable Function} {@var{x} =} pycall (@var{func})\n\ +@deftypefnx {Loadable Function} {@var{x} =} pycall (@var{func}, @var{arg1}, @var{arg2}, @dots{})\n\ +Execute method of a Python module.\n\ +\n\ +Examples:\n\ +@example\n\ +@group\n\ +y = pycall('__builtin__.int(6)')\n\ + @result{} y = 6\n\ +pycall('sys.version')\n\ + @result{} ans = ...\n\ +pycall('__builtin__.eval(\"4+5\")')\n\ + @result{} ans = 9\n\ +pycall('__builtin__.dict(one=1,two=2)')\n\ + @result{} ans =\n\ + scalar structure containing the fields:\n\ + two = 2\n\ + one = 1\n\ +@end group\n\ +@end example\n\ +@end deftypefn") +{ + octave_value_list retval; + + int nargin = args.length (); + + if (nargin < 1) + { + print_usage (); + return retval; + } + + std::string module; + std::string func = args(0).string_value (); + + size_t idx = func.rfind ("."); + if (idx != std::string::npos) + { + module = func.substr (0, idx); + func = func.substr (idx + 1); + } + + Py_Initialize (); + + pytave::init_exceptions (); + numeric::array::set_module_and_type ("numpy", "ndarray"); + _import_array (); + + try + { + object main_module = import ("__main__"); + object main_namespace = main_module.attr ("__dict__"); + + object mod = (module.empty ()) ? main_module : import (module.c_str ()); + object callable = mod.attr (func.c_str ()); + + std::vector<object> pyargs; + for (int i = 1; i < nargin; i++) + { + object arg; + pytave::octvalue_to_pyobj (arg, args(i)); + pyargs.push_back (arg); + } + + object res; + + switch (nargin - 1) + { + case 0: + res = callable (); + break; + case 1: + res = callable (pyargs[0]); + break; + case 2: + res = callable (pyargs[0], pyargs[1]); + break; + case 3: + res = callable (pyargs[0], pyargs[1], pyargs[2]); + break; + case 4: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3]); + break; + case 5: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4]); + break; + case 6: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4], pyargs[5]); + break; + case 7: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4], pyargs[5], pyargs[6]); + break; + case 8: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4], pyargs[5], pyargs[6], pyargs[7]); + break; + case 9: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4], pyargs[5], pyargs[6], pyargs[7], + pyargs[8]); + break; + case 10: + res = callable (pyargs[0], pyargs[1], pyargs[2], pyargs[3], + pyargs[4], pyargs[5], pyargs[6], pyargs[7], + pyargs[8], pyargs[9]); + break; + default: + error ("pycall: more than 10 arguments are not yet supported"); + break; + } + + if (! res.is_none ()) + { + octave_value val; + pytave::pyobj_to_octvalue (val, res); + retval(0) = val; + } + } + catch (pytave::object_convert_exception const &) + { + error ("pycall: error in return value type conversion"); + } + catch (error_already_set const &) + { + PyObject *ptype, *pvalue, *ptraceback; + PyErr_Fetch (&ptype, &pvalue, &ptraceback); + + try + { + std::string message = extract<std::string> (pvalue); + error ("pycall: %s", message.c_str ()); + } + catch (error_already_set const &) + { + PyErr_Restore (ptype, pvalue, ptraceback); + PyErr_Print (); + } + } + + return retval; +} +