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;
+}
+