comparison @pyobject/subsref.m @ 260:daf1aff501f1

indexing: fix off-by-one with dicts (fixes issue #10) Also, dogfood pyobject a bit more instead of just generating strings of code and using pyexec. * @pyobject/subsref.m: Improve {} indexing.
author Colin Macdonald <cbm@m.fsf.org>
date Tue, 26 Jul 2016 20:32:24 -0700
parents 2e4c9ce0c83c
children 0a8983533192
comparison
equal deleted inserted replaced
251:c8da556b6793 260:daf1aff501f1
42 case "." 42 case "."
43 assert (ischar (t.subs)) 43 assert (ischar (t.subs))
44 r = pycall ("getattr", x, t.subs); 44 r = pycall ("getattr", x, t.subs);
45 45
46 case "{}" 46 case "{}"
47 subsstrs = {}; 47 ## Subtract one from index: do this for lists, numpy arrays, etc
48 for j = 1:length (t.subs) 48 pyexec ("import collections")
49 thissub = t.subs{j}; 49 pyexec ("import numpy")
50 if (ischar (thissub) && strcmp (thissub, ":")) 50 x_is_list = pycall (pyeval (
51 subsstrs{j} = ":"; 51 "lambda (x): isinstance(x, (collections.Sequence, numpy.ndarray))"),
52 elseif (ischar (thissub)) 52 x);
53 subsstrs{j} = ["'" thissub "'"]; 53 for i = 1:length(t.subs)
54 elseif (isnumeric (thissub) && isscalar (thissub)) 54 j = t.subs{i};
55 ## note: python indexed from 0 55 if (isindex (j) && isnumeric (j) && x_is_list)
56 subsstrs{j} = num2str (thissub - 1); 56 t.subs{i} = cast (j, class (sizemax ())) - 1;
57 else
58 thissub
59 error ("@pyobject/subsref: subs not supported")
60 endif 57 endif
61 endfor 58 endfor
62 s = ["[" strjoin(subsstrs, ", ") "]"]; 59
63 ## XXX: can we use .__getitem__ here? 60 if (isscalar (t.subs))
64 r = pyeval (sprintf ("__InOct__['%s']%s", x.id, s)); 61 ind = t.subs{1};
62 else
63 ## XXX: after #26, #27, I think its just:
64 #ind = pycall ("tuple", t.subs);
65 pyexec (["global _temp\n" ...
66 "def pystoretemp(x):\n" ...
67 " global _temp\n" ...
68 " _temp = x"]);
69 pycall ("pystoretemp", t.subs);
70 pyexec ("_temp = tuple(_temp[0])");
71 ind = pyobject.fromPythonVarName ("_temp");
72 endif
73 gi = pycall ("getattr", x, "__getitem__"); # x.__getitem__
74 r = pycall (gi, ind);
65 75
66 otherwise 76 otherwise
67 t 77 t
68 error ("@pyobject/subsref: not implemented") 78 error ("@pyobject/subsref: not implemented")
69 endswitch 79 endswitch
86 %! pyexec ("L = [10, 20]") 96 %! pyexec ("L = [10, 20]")
87 %! L = pyobject.fromPythonVarName ("L"); 97 %! L = pyobject.fromPythonVarName ("L");
88 %! assert (L{1}, 10) 98 %! assert (L{1}, 10)
89 %! assert (L{2}, 20) 99 %! assert (L{2}, 20)
90 100
91 %!test 101 %!xtest
92 %! % list indexing 102 %! % list indexing, slice
93 %! pyexec ("L = [10, 20, [30, 40]]") 103 %! pyexec ("L = [10, 20, [30, 40]]")
94 %! L = pyobject.fromPythonVarName ("L"); 104 %! L = pyobject.fromPythonVarName ("L");
95 %! L2 = L{:}; 105 %! L2 = L{:};
96 %! assert (L2{1}, 10) 106 %! assert (L2{1}, 10)
97 %! assert (L2{2}, 20) 107 %! assert (L2{2}, 20)
125 %! % dict: integer key access 135 %! % dict: integer key access
126 %! pyexec ("d = {5:42, 6:42}") 136 %! pyexec ("d = {5:42, 6:42}")
127 %! d = pyobject.fromPythonVarName ("d"); 137 %! d = pyobject.fromPythonVarName ("d");
128 %! assert (d{6}, 42) 138 %! assert (d{6}, 42)
129 139
130 %!xtest 140 %!test
131 %! % dict: integer key should not subtract one (FIXME: Issue #10) 141 %! % dict: integer key should not subtract one
132 %! pyexec ("d = {5:40, 6:42}") 142 %! pyexec ("d = {5:40, 6:42}")
133 %! d = pyobject.fromPythonVarName ("d"); 143 %! d = pyobject.fromPythonVarName ("d");
134 %! assert (d{6}, 42) 144 %! assert (d{6}, 42)
145
146 %!test
147 %! % dict: floating point keys should work
148 %! pyexec ("d = {5.5:'ok'}")
149 %! d = pyobject.fromPythonVarName ("d");
150 %! assert (d{5.5}, "ok")
151
152 %!test
153 %! % dict: make sure key ":" doesn't break anything
154 %! pyexec ("d = {'a':1, ':':2}")
155 %! d = pyobject.fromPythonVarName ("d");
156 %! assert (d{'a'}, 1)
157 %! assert (d{':'}, 2)
135 158
136 %!test 159 %!test
137 %! % method call with args 160 %! % method call with args
138 %! s = pyeval ("set({1, 2})"); 161 %! s = pyeval ("set({1, 2})");
139 %! s.add (42) 162 %! s.add (42)