changeset 71:af96f7e819e2 pytave-task

Merge with trunk
author David Grundberg <individ@acc.umu.se>
date Wed, 01 Jul 2009 13:08:48 +0200
parents 11cff59bc932 (current diff) e3de0f6f1552 (diff)
children e9834fd34416
files
diffstat 9 files changed, 262 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Jun 08 21:26:56 2009 +0200
+++ b/ChangeLog	Wed Jul 01 13:08:48 2009 +0200
@@ -1,3 +1,41 @@
+2009-06-19  Jaroslav Hajek  <highegg@gmail.com>
+
+	* configure.ac: Support --enable-numpy
+	* setup.py.in: Dynamically determine NumPy include path.
+	* pytave.cc (get_module_name): New function.
+	* octave_to_python.cc (octvalue_to_pyarrobj): 
+	Support bool arrays with NumPy.
+	* python_to_octave.cc (pyarr_to_octvalue, 
+	copy_pyarrobj_to_octarray_boot): Likewise.
+	* package/pytave.py: Dynamically import Numeric,
+	forward to numpy.oldnumeric if run with NumPy.
+	* test/test.py: Update some tests.
+
+2009-06-17  Jaroslav Hajek  <highegg@gmail.com>
+
+	* package/pytave.py (stripdict): New function.
+	(narrowlist): New function.
+	(simplify): New function.
+
+2009-06-16  Jaroslav Hajek  <highegg@gmail.com>
+
+	* octave_to_python.cc 
+	(createPyArr): Don't simplify row vectors to 1D arrays.
+	(octvalue_to_pyarrobj): Simplify, don't special-case scalars.
+	(octcell_to_pyobject): Remove.
+	(octmap_to_pyobject): Simplify, return uniform results.
+	(is_1xn_or_0x0): Remove.
+	* python_to_octave.cc
+	(pydict_to_octmap): Revert to the former behaviour aka Octave's
+	`struct'.
+	* package/pytave.py (canonicalize): Remove.
+	* test/test.py: Update tests.
+
+2009-06-09  Jaroslav Hajek  <highegg@gmail.com>
+
+	* package/pytave.py (canonicalize): New function.
+	(feval): Update doc string.
+
 2009-06-08  David Grundberg  <individ@acc.umu.se>
 
 	* pytave.cc (func_eval, str_eval): Reread changed files.
--- a/arrayobjectdefs.h	Mon Jun 08 21:26:56 2009 +0200
+++ b/arrayobjectdefs.h	Wed Jul 01 13:08:48 2009 +0200
@@ -29,7 +29,16 @@
 #endif
 #define PY_ARRAY_UNIQUE_SYMBOL pytave_array_symbol
 #include <Python.h>
+#ifdef HAVE_NUMPY
+#include <numpy/oldnumeric.h>
+#include <numpy/old_defines.h>
+// Avoid deprecation warnings from NumPy
+#undef PyArray_FromDims 
+#define PyArray_FromDims PyArray_SimpleNew
+#else
 #include <Numeric/arrayobject.h>
+typedef int npy_intp;
+#endif
 
 /* Emacs
  * Local Variables:
--- a/configure.ac	Mon Jun 08 21:26:56 2009 +0200
+++ b/configure.ac	Wed Jul 01 13:08:48 2009 +0200
@@ -17,6 +17,17 @@
 
 AC_PRESERVE_HELP_ORDER
 
+AC_ARG_ENABLE(numpy,
+	      [AS_HELP_STRING([--enable-numpy],
+			      [use NumPy module (experimental)
+			      @<:@default=no@:>@])],
+			      [pytave_enable_numpy="$enableval"],
+			      [pytave_enable_numpy=no]) dnl TODO: Check?
+ 
+if test "$pytave_enable_numpy" == "yes" ; then
+	AC_DEFINE([HAVE_NUMPY], 1, [Define if using NumPy])
+fi
+
 pytave_libs_ok=
 
 AX_OCTAVE([], [], [pytave_libs_ok=no])
@@ -85,6 +96,7 @@
 PYTAVE_OCTAVE_RPATH="$OCTAVE_LIBRARYDIR"
 AC_SUBST(PYTAVE_OCTAVE_RPATH)
 AC_SUBST(PYTAVE_MODULE_INSTALL_PATH)
+AC_SUBST(pytave_enable_numpy) 
 
 # Substitutes for the Jamfile. XXX: Replace lib*.so with OS independent name.
 AC_SUBST(JAM_LIBOCTAVE, $OCTAVE_LIBRARYDIR/liboctave.so)
--- a/octave_to_python.cc	Mon Jun 08 21:26:56 2009 +0200
+++ b/octave_to_python.cc	Wed Jul 01 13:08:48 2009 +0200
@@ -108,15 +108,10 @@
    static PyArrayObject *createPyArr(const dim_vector &dims,
                                      int pyarrtype) {
       int len = dims.length();
-      int dimensions[len];
+      npy_intp dimensions[len];
       for (int i = 0; i < dims.length(); i++) {
          dimensions[i] = dims(i);
       }
-      // Simplify row vectors to 1d arrays.
-      if (len == 2 && dimensions[0] == 1) {
-         dimensions[0] = dimensions[1];
-         len = 1;
-      }
 
       return (PyArrayObject *)PyArray_FromDims(
          len, dimensions, pyarrtype);
@@ -246,6 +241,17 @@
          return create_sint_array<int8NDArray, sizeof(int8_t)>(
             matrix.int8_array_value());
       }
+      if (matrix.is_bool_type()) {
+#ifdef HAVE_NUMPY
+         // NumPY has logical arrays, and even provides an old-style #define.
+         return create_array<bool, boolNDArray>(
+            matrix.bool_array_value(), PyArray_BOOL);
+#else
+         // Numeric does not support bools, use uint8.
+         return create_uint_array<uint8NDArray, sizeof(uint8_t)>(
+            matrix.uint8_array_value());
+#endif
+      }
       if (matrix.is_string()) {
          return create_array<char, charNDArray>(
             matrix.char_array_value(), PyArray_CHAR);
@@ -265,43 +271,17 @@
       py_object = object(handle<PyObject>((PyObject *)pyarr));
    }
 
-   static inline bool is_1xn_or_0x0(const dim_vector& dv) {
-      return (dv.length() == 2 && (dv(0) == 1 || (dv(0) == 0 && dv(1) == 0)));
-   }
-
-   static void octcell_to_pyobject(boost::python::object &py_object,
-                                   const Cell& cell) {
-      if (is_1xn_or_0x0 (cell.dims ())) {
-         py_object = boost::python::list();
-
-         for(octave_idx_type i = 0 ; i < cell.length(); i++) {
-            boost::python::object py_val;
-
-            octvalue_to_pyobj(py_val, cell.elem(i));
-
-            ((boost::python::list&)py_object).insert(i, py_val);
-         }
-      } else {
-         octvalue_to_pyarr (py_object, octave_value (cell));
-      }
-   }
-
    static void octmap_to_pyobject(boost::python::object &py_object,
                                   const Octave_map& map) {
       py_object = boost::python::dict();
       string_vector keys = map.keys();
-      bool scalar = map.dims().all_ones();
 
       for(octave_idx_type i = 0 ; i < keys.length(); i++) {
          boost::python::object py_val;
 
          const Cell c = map.contents(keys[i]);
 
-         if (scalar) {
-            octvalue_to_pyobj(py_val, c(0));
-         } else {
-            octcell_to_pyobject(py_val, c);
-         }
+         octvalue_to_pyarr(py_val, c);
 
          py_object[keys[i]] = py_val;
       }
@@ -309,33 +289,14 @@
 
    void octvalue_to_pyobj(boost::python::object &py_object,
                           const octave_value& octvalue) {
-      if (octvalue.is_undefined())
+      if (octvalue.is_undefined()) {
          throw value_convert_exception(
             "Octave value `undefined'. Can not convert to a Python object");
-      else if (octvalue.is_scalar_type()) {
-         if (octvalue.is_bool_type())
-            py_object = object(octvalue.bool_value());
-         else if (octvalue.is_real_scalar())
-            py_object = object(octvalue.double_value());
-         else if (octvalue.is_complex_scalar())
-            py_object = object(octvalue.complex_value());
-         else if (octvalue.is_integer_type())
-            py_object = object(octvalue.int_value());
-         else
-            throw value_convert_exception(
-               "Conversion for this scalar not implemented");
-      } else if (octvalue.is_string()) {
-         if (is_1xn_or_0x0 (octvalue.dims ())) {
-            py_object = object(octvalue.string_value());
-         } else {
-            octvalue_to_pyarr(py_object, octvalue);
-         }
-      } else if (octvalue.is_matrix_type()) {
+      } else if (octvalue.is_numeric_type() || octvalue.is_string()
+                 || octvalue.is_cell()) {
          octvalue_to_pyarr(py_object, octvalue);
       } else if (octvalue.is_map()) {
          octmap_to_pyobject(py_object, octvalue.map_value());
-      } else if (octvalue.is_cell()) {
-         octcell_to_pyobject(py_object, octvalue.cell_value());
       } else
          throw value_convert_exception(
             "Conversion from Octave value not implemented");
--- a/package/pytave.py	Mon Jun 08 21:26:56 2009 +0200
+++ b/package/pytave.py	Wed Jul 01 13:08:48 2009 +0200
@@ -23,7 +23,7 @@
 import _pytave
 import UserDict
 import sys
-import Numeric
+
 
 arg0 = sys.argv[0]
 interactive = sys.stdin.isatty() and (arg0 == '' or arg0 == '-')
@@ -32,6 +32,18 @@
 (OctaveError, ValueConvertError, ObjectConvertError, ParseError, \
  VarNameError) = _pytave.get_exceptions();
 
+# Dynamic import. *Must* go after _pytave.init() !
+__modname__ = _pytave.get_module_name()
+if __modname__ == 'numpy':
+    from numpy import oldnumeric as Numeric
+elif __modname__ == 'Numeric':
+    import Numeric
+elif __modname__ == 'numarray':
+    # FIXME: Is this OK?
+    import numarray as Numeric
+else:
+    raise ImportError("Failed to import module: %s" % __modname__)
+
 def feval(nargout, funcname, *arguments):
 
 	"""Executes an Octave function called funcname.
@@ -73,18 +85,16 @@
 	raised. This exception inherits TypeError.
 
 	When dicts are converted, all keys must be strings and
-	constitute valid Octave identifiers. By default, scalar
-	structures are created. However, when all values evaluate
-	to cell arrays with matching dimensions, an Octave struct
-	array is created.
+	constitute valid Octave identifiers. The behavior is
+	analogical to the Octave "struct" function: values that
+	evaluate to cells must have matching dimensions, singleton
+	cells and non-cell values are expanded.
 	
 	Octave to Python
 	================
 	
-	Scalar values to objects:
-		bool                bool
-		real scalar         float (64-bit)
-		struct              dict
+        All scalar values are regarded as 1x1 matrices, as they are in
+	Octave.
 
 	Matrix values to Numeric arrays:
 	   	double              DOUBLE
@@ -94,8 +104,11 @@
 		int32, uint32       INT, UINT
 		int16, uint16       SHORT, USHORT
 		int8, unint8        SBYTE, UBYTE
-		char                CHAR (if native = False)
-		cell                OBJECT (if native = False)
+		char                CHAR
+		cell                OBJECT
+
+	Structs are converted to dicts, where each value is an OBJECT
+	array.
 
 	All other values causes a pytave.ValueConvertError to be
 	raised. This exception inherits TypeError.
@@ -145,6 +158,63 @@
 
 	return _pytave.eval(nargout, code, silent)
 
+def stripdict(dictarray):
+    """A helper function to convert structures obtained from Octave.
+    Because in Octave, all structs are also arrays, they are returned
+    as dicts of object arrays. In the common case of a 1x1 struct, 
+    stripdict strips the values."""
+    
+    sdict = {}
+    for key in dictarray:
+	sdict[key] = dictarray[key][0,0]
+    return sdict
+
+def narrowlist(objarray):
+    """A helper function to convert cell arrays obtained from Octave.
+    Octave cells are returned as Numeric object arrays. This function
+    will flatten the array and convert it into a 1D list."""
+
+    return Numeric.ravel(objarray).tolist()
+
+def simplify(obj):
+    """A helper function to convert results obtained from Octave.
+    This will convert all 1x1 arrays to scalars, vectors to 1D arrays,
+    1xN and 0x0 character arrays to strings, 1xN, Nx1 and 0x0 cell
+    arrays to lists, and strip scalar dicts. It will work recursively."""
+
+    def vectordims(dims,column_allowed = True):
+	return (len(dims) == 2 and 
+		((dims[0] == 1 or (column_allowed and dims[1] == 1)) or
+		(dims[0] == 0 and dims[1] == 0)))
+
+    if isinstance(obj,Numeric.ArrayType):
+	tc = obj.typecode()
+	if tc == 'O':
+	    if vectordims(Numeric.shape(obj)):
+		return map(simplify,narrowlist(obj))
+	elif tc == 'c':
+	    if vectordims(Numeric.shape(obj), False):
+		return obj.tostring()
+	else:
+	    dims = Numeric.shape(obj)
+	    if dims == (1,1):
+		return obj.toscalar()
+	    elif vectordims(dims):
+		return Numeric.ravel(obj)
+    elif isinstance(obj,dict):
+	sobj = {}
+	for key in obj:
+	    sval = simplify(obj[key])
+	    if isinstance(sval,list) and len(sval) == 1:
+		sval = sval[0]
+	    sobj[key] = sval
+	return sobj
+    elif isinstance(obj,tuple):
+	return tuple(map(simplify,obj))
+    ## default.
+    return obj
+
+
 def addpath(*arguments):
 	"""See Octave documentation"""
 	return _pytave.feval(1, "addpath", arguments)[0]
--- a/pytave.cc	Mon Jun 08 21:26:56 2009 +0200
+++ b/pytave.cc	Wed Jul 01 13:08:48 2009 +0200
@@ -80,6 +80,13 @@
       // This is actually a macro that becomes a block expression. If an error
       // occurs, e.g. Numeric Array not installed, an exception is set.
       import_array()
+#ifdef HAVE_NUMPY
+      numeric::array::set_module_and_type ("numpy", "ndarray");
+#endif
+   }
+
+   string get_module_name () {
+      return numeric::array::get_module_name ();
    }
 
    boost::python::tuple get_exceptions() {
@@ -301,6 +308,7 @@
    using namespace boost::python;
 
    def("init", pytave::init);
+   def("get_module_name", pytave::get_module_name);
    def("feval", pytave::func_eval);
    def("eval", pytave::str_eval);
    def("getvar", pytave::getvar);
--- a/python_to_octave.cc	Mon Jun 08 21:26:56 2009 +0200
+++ b/python_to_octave.cc	Wed Jul 01 13:08:48 2009 +0200
@@ -179,6 +179,10 @@
          /* Commonly Numeric.array(..., Numeric.Complex) */
          ARRAYCASE(PyArray_CDOUBLE, Complex)
 
+#ifdef HAVE_NUMPY
+         ARRAYCASE(PyArray_BOOL, bool)
+#endif
+
          ARRAYCASE(PyArray_OBJECT, PyObject *)
 
          default:
@@ -271,6 +275,11 @@
             // FIXME: is the following needed?
             octvalue = octvalue.convert_to_str(true, true, '"');
             break;
+#ifdef HAVE_NUMPY
+         case PyArray_BOOL:
+            pyarrobj_to_octvalueNd<boolNDArray>(octvalue, pyarr, dims);
+            break;
+#endif
          case PyArray_OBJECT:
             pyarrobj_to_octvalueNd<Cell>(octvalue, pyarr, dims);
             break;
@@ -310,8 +319,6 @@
 
       dim_vector dims = dim_vector(1, 1);
 
-      bool dims_match = true;
-
       Array<octave_value> vals (length);
       Array<std::string> keys (length);
 
@@ -346,15 +353,13 @@
 
          pyobj_to_octvalue(val, tuple[1]);
 
-         if(dims_match && val.is_cell()) {
-            dim_vector dv = val.dims();
+         if(val.is_cell()) {
             if(i == 0) {
-               dims = dv;
-            } else {
-               dims_match = dims == dv;
+               dims = val.dims();
+            } else if (val.numel() != 1 && val.dims() != dims){
+               throw object_convert_exception(
+                  "Dimensions of the struct fields do not match");
             }
-         } else {
-            dims_match = false;
          }
       }
 
@@ -365,10 +370,15 @@
          std::string& key = keys(i);
          octave_value val = vals(i);
 
-         if(dims_match) {
-            map.assign(key, val.cell_value ());
+         if(val.is_cell()) {
+            const Cell c = val.cell_value();
+            if (c.numel () == 1) {
+               map.assign(key, Cell(dims, c(0)));
+            } else {
+               map.assign(key, c);
+            }
          } else {
-            map.assign(key, val);
+            map.assign(key, Cell(dims, val));
          }
       }
       oct_value = map;
--- a/setup.py.in	Mon Jun 08 21:26:56 2009 +0200
+++ b/setup.py.in	Wed Jul 01 13:08:48 2009 +0200
@@ -2,7 +2,19 @@
 # -*- coding: utf-8; c-basic-offset: 3; indent-tabs-mode: nil; tab-width: 3; -*-
 # @configure_input@
 
-from distutils.core import setup, Extension
+from distutils.core import setup, Extension, DistutilsModuleError
+
+include_dirs = ['/usr/local/include/octave-3.1.55', 
+	        '/home/hajek/devel/pytave-repo/pytave', '.'] # Python always included.
+
+# check for numpy. If it exists, define the path.
+
+if '@pytave_enable_numpy@' == 'yes':
+    try:
+        from numpy import get_include
+        include_dirs.append(get_include())
+    except ImportError:
+        raise DistutilsModuleError("could not found numpy")
 
 setup(
    name = 'pytave',
@@ -31,8 +43,8 @@
          
          # TODO: Check whether paths work on Windows or not.
          # The file separator might be wrong. (Must be / in setup.cfg)
-         include_dirs = ['@OCTAVE_INCLUDEDIR@', '@abs_builddir@', '@srcdir@'], # Python always included.
-         define_macros = [('HAVE_CONFIG_H', '1')],
+         include_dirs = include_dirs,
+	 define_macros = [('HAVE_CONFIG_H', '1')],
          library_dirs = ['@OCTAVE_LIBRARYDIR@'],
          runtime_library_dirs = ['@PYTAVE_OCTAVE_RPATH@'],
          libraries = ['octinterp', 'octave', 'cruft', '@BOOST_PYTHON_LIB@']
--- a/test/test.py	Mon Jun 08 21:26:56 2009 +0200
+++ b/test/test.py	Wed Jul 01 13:08:48 2009 +0200
@@ -2,7 +2,7 @@
 # -*- coding:utf-8 -*-
 
 import pytave
-import Numeric
+from pytave import Numeric
 import traceback
 
 print "No messages indicates test pass."
@@ -10,28 +10,28 @@
 arr0_0 = Numeric.zeros((0,0));
 arr0_1 = Numeric.zeros((0,1));
 arr1_0 = Numeric.zeros((1,0));
-number = Numeric.array([1.32], Numeric.Float32)
+number = Numeric.array([[1.32]], Numeric.Float32)
 arr1fT = Numeric.array([[1.32], [2], [3], [4]], Numeric.Float32)
-arr1fT2 = Numeric.array([1.32, 2, 3, 4], Numeric.Float32)
-arr1f = Numeric.array([1.32, 2, 3, 4], Numeric.Float32)
-arr1b = Numeric.array([8, 2, 3, 256], Numeric.Int8)
-arr1i = Numeric.array([17, 2, 3, 4], Numeric.Int)
-arr1i32 = Numeric.array([32, 2, 3, 4], Numeric.Int32)
-arr1a = Numeric.array([1, 2, 3, 4])
+arr1fT2 = Numeric.array([[1.32, 2, 3, 4]], Numeric.Float32)
+arr1f = Numeric.array([[1.32, 2, 3, 4]], Numeric.Float32)
+arr1b = Numeric.array([[8, 2, 3, 256]], Numeric.Int8)
+arr1i = Numeric.array([[17, 2, 3, 4]], Numeric.Int)
+arr1i32 = Numeric.array([[32, 2, 3, 4]], Numeric.Int32)
+arr1a = Numeric.array([[1, 2, 3, 4]])
 arr2f = Numeric.array([[1.32, 2, 3, 4],[5,6,7,8]], Numeric.Float32)
 arr2d = Numeric.array([[1.17, 2, 3, 4],[5,6,7,8]], Numeric.Float)
 arr3f = Numeric.array([[[1.32, 2, 3, 4],[5,6,7,8]],[[9, 10, 11, 12],[13,14,15,16]]], Numeric.Float32)
-arr1c = Numeric.array([1+2j, 3+4j, 5+6j, 7+0.5j], Numeric.Complex)
-arr1fc = Numeric.array([1+2j, 3+4j, 5+6j, 7+0.5j], Numeric.Complex32)
-arr1ch = Numeric.array("abc",Numeric.Character)
+arr1c = Numeric.array([[1+2j, 3+4j, 5+6j, 7+0.5j]], Numeric.Complex)
+arr1fc = Numeric.array([[1+2j, 3+4j, 5+6j, 7+0.5j]], Numeric.Complex32)
+arr1ch = Numeric.array(["abc"],Numeric.Character)
 arr2ch = Numeric.array(["abc","def"],Numeric.Character)
-arr1o = Numeric.array([1.0,"abc",2+3j],Numeric.PyObject)
+arr1o = Numeric.array([[1.0,"abc",2+3j]],Numeric.PyObject)
 arr2o = Numeric.array([[1.0,"abc",2+3j],[4.0,arr1i,"def"]],Numeric.PyObject)
 
-alimit_int32 = Numeric.array([-2147483648, 2147483647], Numeric.Int32);
-alimit_int16 = Numeric.array([-32768, 32767, -32769, 32768], Numeric.Int16);
-alimit_int8 = Numeric.array([-128, 127, -129, 128], Numeric.Int8);
-alimit_uint8 = Numeric.array([0, 255, -1, 256], Numeric.UnsignedInt8);
+alimit_int32 = Numeric.array([[-2147483648, 2147483647]], Numeric.Int32);
+alimit_int16 = Numeric.array([[-32768, 32767, -32769, 32768]], Numeric.Int16);
+alimit_int8 = Numeric.array([[-128, 127, -129, 128]], Numeric.Int8);
+alimit_uint8 = Numeric.array([[0, 255, -1, 256]], Numeric.UnsignedInt8);
 
 
 # This eval call is not to be seen as a encouragement to use Pytave
@@ -40,6 +40,9 @@
 
 pytave.feval(1, "test_return", 1)
 
+def equals(a,b):
+    return Numeric.alltrue(Numeric.ravel(a == b))
+
 def fail(msg, exc=None):
 	print "FAIL:", msg
 	traceback.print_stack()
@@ -50,7 +53,7 @@
 def testequal(value):
 	try:
 		nvalue, = pytave.feval(1, "test_return", value)
-		if nvalue != value:
+		if not equals(value, nvalue):
 			fail("as %s != %s" % (value, nvalue))
 	except TypeError, e:
 		fail(value, e)
@@ -58,7 +61,7 @@
 def testexpect(value, expected):
 	try:
 		nvalue, = pytave.feval(1, "test_return", value)
-		if nvalue != expected:
+		if not equals(value, nvalue):
 			fail("sent in %s, expecting %s, got %s", (value, expected, nvalue))
 	except TypeError, e:
 		fail(value, e)
@@ -66,9 +69,11 @@
 def testmatrix(value):
 	try:
 		nvalue, = pytave.feval(1, "test_return", value)
-		class1 = pytave.feval(1, "class", value)
-		class2 = pytave.feval(1, "class", nvalue)
-		if nvalue != value:
+		class1, = pytave.feval(1, "class", value)
+		class1 = class1.tostring()
+		class2, = pytave.feval(1, "class", nvalue)
+		class2 = class2.tostring()
+		if not equals(value, nvalue):
 			fail("as %s != %s" % (value, nvalue))
 		if value.shape != nvalue.shape:
 			fail("Size check failed for: %s. Expected shape %s, got %s  with shape %s" \
@@ -115,7 +120,7 @@
 def testevalexpect(numargout, code, expectations):
 	try:
 		results = pytave.eval(numargout, code);
-		if results != expectations:
+		if not equals(results, expectations):
 			fail("eval: %s : because %s != %s" % (code, results, expectations))
 	except Exception, e:
 		fail("eval: %s" % code, e)
@@ -145,12 +150,14 @@
     def sloppy_factorial(x):
 	pytave.locals["x"] = x
 	xm1, = pytave.eval(1,"x-1")
+	xm1 = xm1.toscalar()
 	if xm1 > 0:
 	    fxm1 = sloppy_factorial(xm1)
 	else:
 	    fxm1 = 1
 	pytave.locals["fxm1"] = fxm1
 	fx, = pytave.eval(1,"x * fxm1")
+	fx = fx.toscalar()
 	return fx
 
     try:
@@ -163,20 +170,25 @@
     except Exception, e:
 	fail("testlocalscope: %s" % (x,), e)
 
+def objarray(obj):
+    return Numeric.array(obj,Numeric.PyObject)
+
+def charray(obj):
+    return Numeric.array(obj,Numeric.Character)
+
+
 testmatrix(alimit_int32)
 testmatrix(alimit_int16)
 testmatrix(alimit_int8)
 
 # Strings
-# Multi-row character matrix cannot be returned
 
-testequal("mystring")
-testequal("mystringåäöÅÄÖ")
+testequal(["mystring"])
+testequal(["mystringåäöÅÄÖ"])
 
-testequal(1)
-testequal(1L)
-testequal(1.2)
-testequal(1.2)
+testexpect(1,Numeric.array([[1]],Numeric.Int))
+testexpect(1L,Numeric.array([[1]],Numeric.Int64))
+testexpect(1.0,Numeric.array([[1]],Numeric.Float))
 
 # Vector arrays
 testmatrix(arr1a)
@@ -201,12 +213,11 @@
 
 testmatrix(arr0_0)
 testmatrix(arr0_1)
+testmatrix(arr1_0)
 
 # Lists
-testequal([1, 2])
-testequal([[1, 2], [3, 4]])
-testequal([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
-testequal([])
+testexpect([1, 2],objarray([[1,2]]))
+testexpect([],objarray([[]]))
 
 # Return cells with OK dimensions
 testvalueok("cell", 1, 3);
@@ -217,19 +228,20 @@
 
 # Dictionaries
 
+
 # Simple dictionary tests
-testequal({"foo": 1, "bar": 2})
-testequal({"x": [1, 3], "y": [2, 4]})
-testequal({"x": [1, "baz"], "y": [2, "foobar"]})
-testequal({"x": [arr1f], "y": [arr1i]})
+testexpect({"foo": 1, "bar": 2},
+	   {"foo": objarray([[1]]), "bar": objarray([[2]])})
+testexpect({"x": [1, 3], "y": [2, 4]},
+	   {"x": objarray([[1,3]]), "y": objarray([[2,4]])})
+# just constructing the second value with Numeric 24.2!
+#testexpect({"x": [1, "baz"], "y": [2, "foobar"]},
+#          {"x": objarray([[1, charray(["baz"])]]), 
+#	   "y": objarray([[2, charray(["foobar"])]])})
+
+testequal({"x": objarray([[arr1f]]), "y": objarray([[arr1i]])})
 testequal({})
-testequal({"foo": arr1f,    "bar": arr2f})
-testequal({"foo": 1,        "bar": [2]})
-testexpect({"foo": [[1,2]],        "bar": [[3,2]]},
-	   {"foo": [1,2],        "bar": [3,2]})
-
-# Try some odd dictionaries
-# The implicit conversion makes Pytave return cell-wrapped results.
+testequal({"foo": arr2o,    "bar": arr2o})
 
 # Try some invalid keys
 testobjecterror({"this is not an Octave identifier": 1})
@@ -241,7 +253,7 @@
 testobjecterror(())
 
 result, = pytave.feval(1, "eval", "[1, 1, 1]")
-if result.shape != (3,):
+if result.shape != (1,3):
 	print "FAIL: expected length-3 vector"
 
 result, = pytave.feval(1, "eval", "[1; 2; 3]");
@@ -250,11 +262,11 @@
 
 testparseerror(1, "endfunction")
 testevalexpect(1, "2 + 2", (4,))
-testevalexpect(1, "{2}", ([2],))
-testevalexpect(1, "struct('foo', 2)", ({'foo': 2},))
+testevalexpect(1, "{2}", (objarray([[2]]),))
+testevalexpect(1, "struct('foo', 2)", ({'foo': objarray([[2]])},))
 
-testsetget(pytave.locals, "xxx", [1,2,3])
-testsetget(pytave.globals, "xxx", [1,2,3])
+testsetget(pytave.locals, "xxx", arr1f)
+testsetget(pytave.globals, "xxx", arr2o)
 
 def func():
 	pytave.locals["this is not a valid Octave identifier"] = 1