Mercurial > pytave
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