Octave as a module for Python

View: New views
8 Messages — Rating Filter:   Alert me  

Octave as a module for Python

by David Grundberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Announcing Pytave

An Octave module for Python
===========================

  Pytave enables Python scripts to use existing m-files (Octave/Matlab
  scripts) for numerical calculations.  Pytave embeds the Octave
  language interpreter as a module to Python.

  This new revision allows dictionaries and lists to be passed to
   Octave.

Example use
===========

Calling Octave code in the interactive Python interpreter:

 >>> import pytave
 >>> pytave.feval(1, "cos", 0)
(1.0,)

Goals
=====

Pytave strives to uphold these points

  * Good out of the box experience

  * Good-natured implicit type conversions, no strange PyApple ->
    octave_orange -> PyBanana chains

Features
========

A short list of what Pytave is capable of

  * Implicit type conversions between Python and Octave.  Supports all
    Numeric integer, real double (and possibly real float) matrices

  * Architecture independent - no assumption on endian type or integer
    sizes

  * Supports cell <-> list and struct <-> dict conversions. (NEW)

Project homepage
================

https://launchpad.net/pytave

Using/hacking
=============

You need the Bazaar version control software (bzr).  Branch from trunk
with:

  $ bzr branch lp:pytave

   You will now have a directory called `pytave' with source code for
the module.  Read the INSTALL file for building instructions.

_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, May 5, 2009 at 9:32 PM, David Grundberg <c04dgg@...> wrote:

> Announcing Pytave
>
> An Octave module for Python
> ===========================
>
>  Pytave enables Python scripts to use existing m-files (Octave/Matlab
>  scripts) for numerical calculations.  Pytave embeds the Octave
>  language interpreter as a module to Python.
>
>  This new revision allows dictionaries and lists to be passed to
>   Octave.
>
> Example use
> ===========
>
> Calling Octave code in the interactive Python interpreter:
>
>  >>> import pytave
>  >>> pytave.feval(1, "cos", 0)
> (1.0,)
>
> Goals
> =====
>
> Pytave strives to uphold these points
>
>  * Good out of the box experience
>
>  * Good-natured implicit type conversions, no strange PyApple ->
>    octave_orange -> PyBanana chains
>
> Features
> ========
>
> A short list of what Pytave is capable of
>
>  * Implicit type conversions between Python and Octave.  Supports all
>    Numeric integer, real double (and possibly real float) matrices
>
>  * Architecture independent - no assumption on endian type or integer
>    sizes
>
>  * Supports cell <-> list and struct <-> dict conversions. (NEW)
>
> Project homepage
> ================
>
> https://launchpad.net/pytave
>
> Using/hacking
> =============
>
> You need the Bazaar version control software (bzr).  Branch from trunk
> with:
>
>  $ bzr branch lp:pytave
>
>   You will now have a directory called `pytave' with source code for
> the module.  Read the INSTALL file for building instructions.
>
> _______________________________________________
> Help-octave mailing list
> Help-octave@...
> https://www-old.cae.wisc.edu/mailman/listinfo/help-octave
>

Excellent! I just built pytave with the development Octave on
OpenSUSE/x86_64, Python 2.5.2, and all seems OK.
Great job. Hopefully no more pipes for calling Octave from Python... I
must find time to inspect the code.

cheers

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by Michael Creel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


David Grundberg wrote:
Announcing Pytave

An Octave module for Python
===========================

  Pytave enables Python scripts to use existing m-files (Octave/Matlab
  scripts) for numerical calculations.  Pytave embeds the Octave
  language interpreter as a module to Python.
...
Can .oct files also be called?
Thanks, Michael

Re: Octave as a module for Python

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, May 6, 2009 at 10:02 AM, Michael Creel <michael.creel@...> wrote:

>
>
>
> David Grundberg wrote:
>>
>> Announcing Pytave
>>
>> An Octave module for Python
>> ===========================
>>
>>   Pytave enables Python scripts to use existing m-files (Octave/Matlab
>>   scripts) for numerical calculations.  Pytave embeds the Octave
>>   language interpreter as a module to Python.
>> ...
>>
>
> Can .oct files also be called?
> Thanks, Michael
>

Yes, anything callable with "feval".


--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by Michael Creel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, May 6, 2009 at 10:25 AM, Jaroslav Hajek <highegg@...> wrote:

> On Wed, May 6, 2009 at 10:02 AM, Michael Creel <michael.creel@...> wrote:
>>
>>
>>
>> David Grundberg wrote:
>>>
>>> Announcing Pytave
>>>
>>> An Octave module for Python
>>> ===========================
>>>
>>>   Pytave enables Python scripts to use existing m-files (Octave/Matlab
>>>   scripts) for numerical calculations.  Pytave embeds the Octave
>>>   language interpreter as a module to Python.
>>> ...
>>>
>>
>> Can .oct files also be called?
>> Thanks, Michael
>>
>
> Yes, anything callable with "feval".
>
>
> --
> RNDr. Jaroslav Hajek
> computing expert & GNU Octave developer
> Aeronautical Research and Test Institute (VZLU)
> Prague, Czech Republic
> url: www.highegg.matfyz.cz
>

Thanks, that's what I suspected.
M.

_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, May 5, 2009 at 9:32 PM, David Grundberg <c04dgg@...> wrote:

> Announcing Pytave
>
> An Octave module for Python
> ===========================
>
>  Pytave enables Python scripts to use existing m-files (Octave/Matlab
>  scripts) for numerical calculations.  Pytave embeds the Octave
>  language interpreter as a module to Python.
>
>  This new revision allows dictionaries and lists to be passed to
>   Octave.
>
> Example use
> ===========
>
> Calling Octave code in the interactive Python interpreter:
>
>  >>> import pytave
>  >>> pytave.feval(1, "cos", 0)
> (1.0,)
>
> Goals
> =====
>
> Pytave strives to uphold these points
>
>  * Good out of the box experience
>
>  * Good-natured implicit type conversions, no strange PyApple ->
>    octave_orange -> PyBanana chains
>
> Features
> ========
>
> A short list of what Pytave is capable of
>
>  * Implicit type conversions between Python and Octave.  Supports all
>    Numeric integer, real double (and possibly real float) matrices
>
>  * Architecture independent - no assumption on endian type or integer
>    sizes
>
>  * Supports cell <-> list and struct <-> dict conversions. (NEW)
>
> Project homepage
> ================
>
> https://launchpad.net/pytave
>
> Using/hacking
> =============
>
> You need the Bazaar version control software (bzr).  Branch from trunk
> with:
>
>  $ bzr branch lp:pytave
>
>   You will now have a directory called `pytave' with source code for
> the module.  Read the INSTALL file for building instructions.
>
> _______________________________________________
> Help-octave mailing list
> Help-octave@...
> https://www-old.cae.wisc.edu/mailman/listinfo/help-octave
>
Hi David,

I have wrapped also the "eval" function into pytave - see the attached
patch (created using bzr diff). How should I go about it? Should
contributions be reported as bugs using the launchpad tracker? Sorry I
have no experience with neither bazaar nor launchpad.

summary:
"eval" is provided as a wrapper to eval_string (parse.h). In
principle, this could be achieved more simply using feval("eval", but
the advantages are:
1. faster (avoids double call and double conversion of code string)
2. explicit control of printing rather than implicitly with nargout (as in eval)
3. a separate exception class for parse error

regards

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

[pytave_eval.diff]

=== modified file 'exceptions.cc'
--- exceptions.cc 2008-10-18 10:28:00 +0000
+++ exceptions.cc 2009-05-06 09:21:59 +0000
@@ -25,6 +25,7 @@
  PyObject *octave_error_exception::excclass = NULL;
  PyObject *value_convert_exception::excclass = NULL;
  PyObject *object_convert_exception::excclass = NULL;
+ PyObject *octave_parse_exception::excclass = NULL;
 
 }
 

=== modified file 'exceptions.h'
--- exceptions.h 2009-05-03 18:24:48 +0000
+++ exceptions.h 2009-05-06 09:28:18 +0000
@@ -55,6 +55,26 @@
 
    };
 
+   class octave_parse_exception {
+      public:
+         static bool init() {
+            excclass = PyErr_NewException(
+               const_cast<char*>("pytave.ParseError"),
+               PyExc_RuntimeError, NULL);
+            return excclass != NULL;
+         };
+         static void translate_exception(octave_parse_exception const &py_ex) {
+            PyErr_SetString(excclass, py_ex.error.c_str());
+         }
+         static PyObject *excclass;
+
+         octave_parse_exception(std::string err) { error = err; };
+
+      private:
+         std::string error;
+
+   };
+
    class value_convert_exception {
       public:
          static bool init() {

=== modified file 'package/pytave.py'
--- package/pytave.py 2009-05-03 18:50:25 +0000
+++ package/pytave.py 2009-05-06 09:46:58 +0000
@@ -96,6 +96,62 @@
 
  return _pytave.feval(nargout, funcname, arguments)
 
+def eval(nargout, code, silent=True):
+
+ """Executes a given Octave code.
+
+ The expression is expected to return nargout values. Returned
+ values are stored in a tuple. If the nargout argument is less than
+ or equal to 0, an empty tuple is returned.
+
+ All normal scope and function search rules apply. If silent is
+ true (default), the result is not auto-printed, as if a semicolon
+ was appended. Otherwise, auto-printing is enabled.
+
+ See also the Octave documentation for the builtin Octave function
+ eval.
+
+ Type conversions
+ ****************
+
+ The following type conversions are supported:
+
+ Octave to Python
+ ================
+
+ Scalar values to objects:
+ bool                bool
+ real scalar         float (64-bit)
+ any string*         str
+ struct              dict
+ cell*               list
+
+ * Cell arrays must be one-dimensional (row vector) and
+                  character matrices must only have one row.  Any
+                  other form will raise a ValueConvertError.
+
+ Matrix values to Numeric arrays:
+ int64               LONG
+ int32, uint32       INT, UINT
+ int16, uint16       SHORT, USHORT
+ int8, unint8        SBYTE, UBYTE
+
+ All other values causes a pytave.ValueConvertError to be
+ raised. This exception inherits TypeError.
+
+ Errors
+ ******
+
+ Octave runtime errors are encapsulated into
+ pytave.OctaveError exceptions, base class RuntimeError.
+
+ If the code can't be parsed, a
+ pytave.ParseError exception occurs.
+
+ """
+
+ return _pytave.eval(nargout, code, silent)
+
 def addpath(*arguments):
  """See Octave documentation"""
  return _pytave.feval(1, "addpath", arguments)[0]

=== modified file 'pytave.cc'
--- pytave.cc 2009-05-03 18:24:48 +0000
+++ pytave.cc 2009-05-06 09:46:02 +0000
@@ -48,7 +48,8 @@
 
       if (!octave_error_exception::init()
           || !value_convert_exception::init()
-          || !object_convert_exception::init()) {
+          || !object_convert_exception::init()
+          || !octave_parse_exception::init()) {
          PyErr_SetString(PyExc_ImportError, "_pytave: init failed");
          return;
       }
@@ -77,8 +78,40 @@
                                   object_convert_exception::excclass)));
    }
 
+   string make_error_message (const Octave_map& map) {
+      ostringstream exceptionmsg;
+      string message = map.stringfield("message", "");
+      string identifier = map.stringfield("identifier", "");
+      Cell stackCell = map.contents("stack");
+
+      // Trim trailing new lines
+      message = message.substr(0, message.find_last_not_of("\r\n") + 1);
+
+      if (!stackCell.is_empty() && stackCell(0).is_map()) {
+         // The struct element is called "stack" but only contain
+         // info about the top frame.
+         Octave_map stack = stackCell(0).map_value();
+         string file = stack.stringfield("file", "");
+         string name = stack.stringfield("name", "");
+         int line = stack.intfield("line", 1);
+         int column = stack.intfield("column", 2);
+
+         exceptionmsg << file << ":" << line << ":" << column << ": ";
+         if (!name.empty())
+            exceptionmsg << "in '" << name << "': ";
+      }
+
+      if (!identifier.empty()) {
+         exceptionmsg << "(identifier: " << identifier << ") ";
+      }
+      exceptionmsg << message;
+
+      return exceptionmsg.str ();
+   }
+
+    
    boost::python::tuple func_eval(const int nargout,
-                                  const std::string &funcname,
+                                  const string &funcname,
                                   const boost::python::tuple &arguments) {
 
       octave_value_list octave_args, retval;
@@ -102,35 +135,52 @@
          octave_value_list lasterror = eval_string("lasterror",
                                                    true, parse_status, 1);
          if (!lasterror.empty() && lasterror(0).is_map()) {
-            ostringstream exceptionmsg;
-            Octave_map map = lasterror(0).map_value();
-            string message = map.stringfield("message", "");
-            string identifier = map.stringfield("identifier", "");
-            Cell stackCell = map.contents("stack");
-
-            // Trim trailing new lines
-            message = message.substr(0, message.find_last_not_of("\r\n") + 1);
-
-            if (!stackCell.is_empty() && stackCell(0).is_map()) {
-               // The struct element is called "stack" but only contain
-               // info about the top frame.
-               Octave_map stack = stackCell(0).map_value();
-               string file = stack.stringfield("file", "");
-               string name = stack.stringfield("name", "");
-               int line = stack.intfield("line", 1);
-               int column = stack.intfield("column", 2);
-
-               exceptionmsg << file << ":" << line << ":" << column << ": ";
-               if (!name.empty())
-                  exceptionmsg << "in '" << name << "': ";
-            }
-
-            if (!identifier.empty()) {
-               exceptionmsg << "(identifier: " << identifier << ") ";
-            }
-            exceptionmsg << message;
-
-            throw octave_error_exception(exceptionmsg.str());
+            string exceptionmsg = make_error_message (lasterror(0).map_value ());
+            throw octave_error_exception(exceptionmsg);
+         } else
+            throw octave_error_exception("No Octave error available");
+      }
+
+      if (nargout > 0) {
+         boost::python::tuple pytuple;
+         octlist_to_pytuple(pytuple, retval);
+         return pytuple;
+      } else {
+         // Return () if nargout <= 0.
+         return make_tuple();
+      }
+   }
+
+   boost::python::tuple str_eval(int nargout,
+                                 const string &code,
+                                 bool silent) {
+
+      octave_value_list retval;
+      int parse_status;
+
+      reset_error_handler();
+      buffer_error_messages++;
+      
+      Py_BEGIN_ALLOW_THREADS
+      retval = eval_string(code, silent, parse_status, nargout);
+      Py_END_ALLOW_THREADS
+
+      if (parse_status != 0 || error_state != 0) {
+// error_state values:
+// -2 error without traceback
+// -1 traceback
+//  1 general error
+         int parse_status1 = 0;
+         reset_error_handler();
+         octave_value_list lasterror = eval_string("lasterror",
+                                                   true, parse_status1, 1);
+         if (!lasterror.empty() && lasterror(0).is_map()) {
+            string exceptionmsg = make_error_message (lasterror(0).map_value ());
+
+            if (parse_status != 0)
+               throw octave_parse_exception(exceptionmsg);
+            else
+               throw octave_error_exception(exceptionmsg);
          } else
             throw octave_error_exception("No Octave error available");
       }
@@ -151,6 +201,7 @@
 
    def("init", pytave::init);
    def("feval", pytave::func_eval);
+   def("eval", pytave::str_eval);
    def("get_exceptions", pytave::get_exceptions);
 
    register_exception_translator<pytave::pytave_exception>(
@@ -159,6 +210,9 @@
    register_exception_translator<pytave::octave_error_exception>(
       pytave::octave_error_exception::translate_exception);
 
+   register_exception_translator<pytave::octave_parse_exception>(
+      pytave::octave_parse_exception::translate_exception);
+
    register_exception_translator<pytave::object_convert_exception>(
       pytave::object_convert_exception::translate_exception);
 



_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by David Grundberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jaroslav Hajek skrev:

> On Tue, May 5, 2009 at 9:32 PM, David Grundberg <c04dgg@...> wrote:
>  
>> Announcing Pytave
>
> Hi David,
>
> I have wrapped also the "eval" function into pytave - see the attached
> patch (created using bzr diff). How should I go about it? Should
> contributions be reported as bugs using the launchpad tracker? Sorry I
> have no experience with neither bazaar nor launchpad.
>
> summary:
> "eval" is provided as a wrapper to eval_string (parse.h). In
> principle, this could be achieved more simply using feval("eval", but
> the advantages are:
> 1. faster (avoids double call and double conversion of code string)
> 2. explicit control of printing rather than implicitly with nargout (as in eval)
> 3. a separate exception class for parse error
>
> regards
>
>  
Hi Jaroslav,

Glad to see you improving my software! As your patch is of a manageable
size, you might as well open a bug report and attach your patch.

I have some comments

1. As the code stands, it is not possible to catch pytave.ParseError.
([module pytave has] "no attribute 'ParseError'") In order to be
correctly declared, the octave_parse_exception will have to be returned
by the _pytave::get_exceptions function and correctly assigned to a
symbol named ParseError in pytave.py.
2. It's unnecessary to duplicate the value conversion documentation, I
think it'll be easier to maintain if it just referred to feval.

I'm attaching a modified patch as a suggestion. I modified the semantics
of the nargout parameter since 0 is valid input.

Furthermore, I see that the builtin eval function accepts a second code
string, CATCH. What are the purpose of this argument, and why did you
not include it?

sincerely,
David

=== modified file 'exceptions.cc'
--- exceptions.cc 2008-10-18 10:28:00 +0000
+++ exceptions.cc 2009-05-06 11:42:53 +0000
@@ -25,6 +25,7 @@
  PyObject *octave_error_exception::excclass = NULL;
  PyObject *value_convert_exception::excclass = NULL;
  PyObject *object_convert_exception::excclass = NULL;
+ PyObject *octave_parse_exception::excclass = NULL;
 
 }
 

=== modified file 'exceptions.h'
--- exceptions.h 2009-05-03 18:24:48 +0000
+++ exceptions.h 2009-05-06 12:13:29 +0000
@@ -55,6 +55,25 @@
 
    };
 
+   class octave_parse_exception {
+      public:
+         static bool init() {
+            excclass = PyErr_NewException(
+               const_cast<char*>("pytave.ParseError"),
+               PyExc_RuntimeError, NULL);
+            return excclass != NULL;
+         };
+         static void translate_exception(octave_parse_exception const &py_ex) {
+            PyErr_SetString(excclass, py_ex.error.c_str());
+         }
+         static PyObject *excclass;
+
+         octave_parse_exception(std::string err) { error = err; };
+
+      private:
+         std::string error;
+   };
+
    class value_convert_exception {
       public:
          static bool init() {

=== modified file 'package/pytave.py'
--- package/pytave.py 2009-05-03 18:50:25 +0000
+++ package/pytave.py 2009-05-06 12:24:27 +0000
@@ -22,16 +22,16 @@
 import _pytave
 
 _pytave.init()
-(OctaveError, ValueConvertError, ObjectConvertError) \
+(OctaveError, ValueConvertError, ObjectConvertError, ParseError) \
   = _pytave.get_exceptions();
 
 def feval(nargout, funcname, *arguments):
 
  """Executes an Octave function called funcname.
 
- The function is set to return nargout values. Returned values are
- stored in a tuple. If the nargout argument is less than or equal
- to 0, an empty tuple is returned.
+ The function is set to return nargout values. Returned values
+ are stored in a tuple. If the nargout argument is less than 0,
+ an empty tuple is returned.
 
  M-files are searched for in the Octave path.
 
@@ -96,6 +96,41 @@
 
  return _pytave.feval(nargout, funcname, arguments)
 
+def eval(nargout, code, silent=True):
+
+ """Executes a given Octave code.
+
+ The expression is expected to return nargout values. Returned
+ values are stored in a tuple. If the nargout argument is less
+ than 0, an empty tuple is returned.
+
+ All normal scope and function search rules apply. If silent is
+ true (default), the result is not auto-printed, as if a
+ semicolon was appended. Otherwise, auto-printing is enabled.
+
+ See also the Octave documentation for the builtin Octave
+ function eval.
+
+ For information about returned value conversion, see
+ pytave.feval.
+
+ Errors
+ ******
+
+ If the code cannot be parsed, a pytave.ParseError exception
+ occurs.
+
+ Octave runtime errors are encapsulated into pytave.OctaveError
+ exceptions, base class RuntimeError.
+
+ If the resulting values cannot be converted, a
+ pytave.ValueConvertError is raised. This exception inherits
+ TypeError.
+
+ """
+
+ return _pytave.eval(nargout, code, silent)
+
 def addpath(*arguments):
  """See Octave documentation"""
  return _pytave.feval(1, "addpath", arguments)[0]

=== modified file 'pytave.cc'
--- pytave.cc 2009-05-03 18:24:48 +0000
+++ pytave.cc 2009-05-06 12:23:34 +0000
@@ -48,7 +48,8 @@
 
       if (!octave_error_exception::init()
           || !value_convert_exception::init()
-          || !object_convert_exception::init()) {
+          || !object_convert_exception::init()
+          || !octave_parse_exception::init()) {
          PyErr_SetString(PyExc_ImportError, "_pytave: init failed");
          return;
       }
@@ -74,11 +75,45 @@
                         object(handle<PyObject>(
                                   value_convert_exception::excclass)),
                         object(handle<PyObject>(
-                                  object_convert_exception::excclass)));
-   }
-
+                                  object_convert_exception::excclass)),
+                        object(handle<PyObject>(
+                                  octave_parse_exception::excclass)));
+   }
+
+   string make_error_message (const Octave_map& map) {
+      ostringstream exceptionmsg;
+      string message = map.stringfield("message", "");
+      string identifier = map.stringfield("identifier", "");
+      Cell stackCell = map.contents("stack");
+
+      // Trim trailing new lines
+      message = message.substr(0, message.find_last_not_of("\r\n") + 1);
+
+      if (!stackCell.is_empty() && stackCell(0).is_map()) {
+         // The struct element is called "stack" but only contain
+         // info about the top frame.
+         Octave_map stack = stackCell(0).map_value();
+         string file = stack.stringfield("file", "");
+         string name = stack.stringfield("name", "");
+         int line = stack.intfield("line", 1);
+         int column = stack.intfield("column", 2);
+
+         exceptionmsg << file << ":" << line << ":" << column << ": ";
+         if (!name.empty())
+            exceptionmsg << "in '" << name << "': ";
+      }
+
+      if (!identifier.empty()) {
+         exceptionmsg << "(identifier: " << identifier << ") ";
+      }
+      exceptionmsg << message;
+
+      return exceptionmsg.str ();
+   }
+
+    
    boost::python::tuple func_eval(const int nargout,
-                                  const std::string &funcname,
+                                  const string &funcname,
                                   const boost::python::tuple &arguments) {
 
       octave_value_list octave_args, retval;
@@ -89,7 +124,7 @@
       buffer_error_messages++;
       
       Py_BEGIN_ALLOW_THREADS
-      retval = feval(funcname, octave_args, nargout);
+      retval = feval(funcname, octave_args, (nargout >= 0) ? nargout : 0);
       Py_END_ALLOW_THREADS
 
       if (error_state != 0) {
@@ -102,45 +137,63 @@
          octave_value_list lasterror = eval_string("lasterror",
                                                    true, parse_status, 1);
          if (!lasterror.empty() && lasterror(0).is_map()) {
-            ostringstream exceptionmsg;
-            Octave_map map = lasterror(0).map_value();
-            string message = map.stringfield("message", "");
-            string identifier = map.stringfield("identifier", "");
-            Cell stackCell = map.contents("stack");
-
-            // Trim trailing new lines
-            message = message.substr(0, message.find_last_not_of("\r\n") + 1);
-
-            if (!stackCell.is_empty() && stackCell(0).is_map()) {
-               // The struct element is called "stack" but only contain
-               // info about the top frame.
-               Octave_map stack = stackCell(0).map_value();
-               string file = stack.stringfield("file", "");
-               string name = stack.stringfield("name", "");
-               int line = stack.intfield("line", 1);
-               int column = stack.intfield("column", 2);
-
-               exceptionmsg << file << ":" << line << ":" << column << ": ";
-               if (!name.empty())
-                  exceptionmsg << "in '" << name << "': ";
-            }
-
-            if (!identifier.empty()) {
-               exceptionmsg << "(identifier: " << identifier << ") ";
-            }
-            exceptionmsg << message;
-
-            throw octave_error_exception(exceptionmsg.str());
-         } else
-            throw octave_error_exception("No Octave error available");
-      }
-
-      if (nargout > 0) {
-         boost::python::tuple pytuple;
-         octlist_to_pytuple(pytuple, retval);
-         return pytuple;
-      } else {
-         // Return () if nargout <= 0.
+            string exceptionmsg = make_error_message(lasterror(0).map_value ());
+            throw octave_error_exception(exceptionmsg);
+         } else
+            throw octave_error_exception("No Octave error available");
+      }
+
+      if (nargout >= 0) {
+         boost::python::tuple pytuple;
+         octlist_to_pytuple(pytuple, retval);
+         return pytuple;
+      } else {
+         // Return () if nargout < 0.
+         return make_tuple();
+      }
+   }
+
+   boost::python::tuple str_eval(int nargout,
+                                 const string &code,
+                                 bool silent) {
+
+      octave_value_list retval;
+      int parse_status;
+
+      reset_error_handler();
+      buffer_error_messages++;
+      
+      Py_BEGIN_ALLOW_THREADS
+      retval = eval_string(code, silent, parse_status,
+         (nargout >= 0) ? nargout : 0);
+      Py_END_ALLOW_THREADS
+
+      if (parse_status != 0 || error_state != 0) {
+// error_state values:
+// -2 error without traceback
+// -1 traceback
+//  1 general error
+         int parse_status1 = 0;
+         reset_error_handler();
+         octave_value_list lasterror = eval_string("lasterror",
+                                                   true, parse_status1, 1);
+         if (!lasterror.empty() && lasterror(0).is_map()) {
+            string exceptionmsg = make_error_message (lasterror(0).map_value ());
+
+            if (parse_status != 0)
+               throw octave_parse_exception(exceptionmsg);
+            else
+               throw octave_error_exception(exceptionmsg);
+         } else
+            throw octave_error_exception("No Octave error available");
+      }
+
+      if (nargout >= 0) {
+         boost::python::tuple pytuple;
+         octlist_to_pytuple(pytuple, retval);
+         return pytuple;
+      } else {
+         // Return () if nargout < 0.
          return make_tuple();
       }
    }
@@ -151,6 +204,7 @@
 
    def("init", pytave::init);
    def("feval", pytave::func_eval);
+   def("eval", pytave::str_eval);
    def("get_exceptions", pytave::get_exceptions);
 
    register_exception_translator<pytave::pytave_exception>(
@@ -159,6 +213,9 @@
    register_exception_translator<pytave::octave_error_exception>(
       pytave::octave_error_exception::translate_exception);
 
+   register_exception_translator<pytave::octave_parse_exception>(
+      pytave::octave_parse_exception::translate_exception);
+
    register_exception_translator<pytave::object_convert_exception>(
       pytave::object_convert_exception::translate_exception);
 

=== modified file 'test/test.py'
--- test/test.py 2009-05-05 18:57:24 +0000
+++ test/test.py 2009-05-06 12:26:38 +0000
@@ -86,12 +86,28 @@
  except Exception, e:
  print "FAIL", (value,), e
 
+def testparseerror(*value):
+ try:
+ print pytave.eval(*value);
+ print "FAIL:", (value,)
+ except pytave.ParseError:
+ pass
+ except Exception, e:
+ print "FAIL", (value,), e
+
 def testvalueok(*value):
  try:
  pytave.feval(1, *value);
  except Exception, e:
  print "FAIL", (value,), e
 
+def testevalexpect(numargout, code, expectations):
+ try:
+ results = pytave.eval(numargout, code);
+ if results != expectations:
+ print "FAIL: eval: ", code, " because", results, " != ", expectations, ","
+ except Exception, e:
+ print "FAIL: eval:", code, ":", e
 def testcellinvariant(value):
  pass
 
@@ -200,4 +216,7 @@
 if result.shape != (3, 1):
  print "FAIL: expected 3x1 matrix"
 
-
+testparseerror(1, "endfunction")
+testevalexpect(1, "2 + 2", (4,))
+testevalexpect(0, "{2}", ([2],))
+testevalexpect(2, "struct('foo', 2)", ({'foo': [2]},))


_______________________________________________
Help-octave mailing list
Help-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/help-octave

Re: Octave as a module for Python

by Michael Creel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I have this built, and the tests work. I can't seem to get it to evaluate an .m file, though. Could I get an example of python code that evaluates the file hello.m which contains the single line

printf("Hello, world\n");

please?  Thanks. If I get going a little bit I'll direct my questions to Lauchpad.
Thanks again, Michael