changeset 322:2461b86cb8fb

pyobject.subsref: support indexing into Python array objects * @pyobject/subsref.m: Add support for sequence indexing into Python array objects. Clean up detection of Python types and protocols that can be indexed. Add %!tests for array indexing and improved type detection.
author Mike Miller <mtmiller@octave.org>
date Fri, 12 Aug 2016 00:45:39 -0700
parents 3afd890fff6d
children a511d43e1fc0
files @pyobject/subsref.m
diffstat 1 files changed, 26 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/@pyobject/subsref.m	Thu Aug 11 22:35:19 2016 -0700
+++ b/@pyobject/subsref.m	Fri Aug 12 00:45:39 2016 -0700
@@ -44,22 +44,28 @@
       r = pycall ("getattr", x, t.subs);
 
     case "{}"
-      ## Subtract one from index: do this for lists, numpy arrays, etc
-      pyexec ("import collections")
-      pyexec ("import numpy")
-      x_is_list = pycall (pyeval (
-        "lambda x: isinstance(x, (collections.Sequence, numpy.ndarray))"),
-        x);
+      ## Determine the types and protocols that we are able to index into
+      x_is_mapping = pycall (pyeval (
+        "lambda x: isinstance(x, __import__('collections').Mapping)"), x);
+      x_is_sequence = pycall (pyeval (
+        ["lambda x: isinstance(x, (__import__('collections').Sequence, " ...
+                                  "__import__('array').array, " ...
+                                  "__import__('numpy').ndarray))"]), x);
+
+      if (! (x_is_mapping || x_is_sequence))
+        error ("subsref: cannot index Python object, not sequence or mapping");
+      endif
+
+      ## Subtract one from index: do this for lists, arrays, numpy arrays, etc
       for i = 1:length(t.subs)
         j = t.subs{i};
-        if (isindex (j) && isnumeric (j) && x_is_list)
+        if (isindex (j) && isnumeric (j) && x_is_sequence)
           t.subs{i} = cast (j, class (sizemax ())) - 1;
         endif
       endfor
 
       if (ischar (t.subs{1}) && strcmp (t.subs{1}, ":"))
-        is_map = pyeval ("lambda x: isinstance(x, collections.Mapping)");
-        if (pycall (is_map, x))
+        if (x_is_mapping)
           ind = ":";
         else
           ind = int32 ([1:length(x)] - 1);
@@ -141,6 +147,13 @@
 %! assert (A{2, 1}, 3)
 %! assert (A{1, 2}, 2)
 
+## Test element indexing on array.array types
+%!test
+%! a = pycall ("array.array", "d", {11, 12, 13, 14});
+%! assert (a{1}, 11)
+%! assert (a{2}, 12)
+%! assert (a{end}, 14)
+
 %!test
 %! % dict: str key access
 %! d = pyeval ("{'one':1, 5:5, 6:6}");
@@ -238,6 +251,10 @@
 %! a = L{2};
 %! assert (char (a), "None")
 
+%!error <cannot index Python object>
+%! f = pyeval ("abs");
+%! f{1}
+
 %!error <outputs must match>
 %! % multiple return values: too many outputs
 %! f = pyeval ("lambda: (1, 2)");