Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee9b958

Browse files
committed
Make indexers work for interface objects
Makes the following work instead of throwing an exception: ```python from System.Collections.Generic import Dictionary, IDictionary d = IDictionary[str, str](Dictionary[str, str]()) d["one"] = "1" assert d["one"] == "1" ```
1 parent 50d947f commit ee9b958

File tree

5 files changed

+134
-128
lines changed

5 files changed

+134
-128
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ details about the cause of the failure
2828
- Fix `object[]` parameters taking precedence when should not in overload resolution
2929
- Fixed a bug where all .NET class instances were considered Iterable
3030
- Fix incorrect choice of method to invoke when using keyword arguments.
31+
- Indexers can now be used with interface objects
3132

3233
## [2.5.0][] - 2020-06-14
3334

src/runtime/arrayobject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
4040
/// <summary>
4141
/// Implements __getitem__ for array types.
4242
/// </summary>
43-
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
43+
public new static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
4444
{
4545
var obj = (CLRObject)GetManagedObject(ob);
4646
var arrObj = (ArrayObject)GetManagedObjectType(ob);
@@ -133,7 +133,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
133133
/// <summary>
134134
/// Implements __setitem__ for array types.
135135
/// </summary>
136-
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
136+
public static new int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
137137
{
138138
var obj = (CLRObject)GetManagedObject(ob);
139139
var items = obj.inst as Array;

src/runtime/classbase.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,5 +302,129 @@ public static void tp_dealloc(IntPtr ob)
302302
Runtime.XDecref(self.tpHandle);
303303
self.gcHandle.Free();
304304
}
305+
306+
307+
/// <summary>
308+
/// Implements __getitem__ for reflected classes and value types.
309+
/// </summary>
310+
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
311+
{
312+
IntPtr tp = Runtime.PyObject_TYPE(ob);
313+
var cls = (ClassBase)GetManagedObject(tp);
314+
315+
if (cls.indexer == null || !cls.indexer.CanGet)
316+
{
317+
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
318+
return IntPtr.Zero;
319+
}
320+
321+
// Arg may be a tuple in the case of an indexer with multiple
322+
// parameters. If so, use it directly, else make a new tuple
323+
// with the index arg (method binders expect arg tuples).
324+
IntPtr args = idx;
325+
var free = false;
326+
327+
if (!Runtime.PyTuple_Check(idx))
328+
{
329+
args = Runtime.PyTuple_New(1);
330+
Runtime.XIncref(idx);
331+
Runtime.PyTuple_SetItem(args, 0, idx);
332+
free = true;
333+
}
334+
335+
IntPtr value;
336+
337+
try
338+
{
339+
value = cls.indexer.GetItem(ob, args);
340+
}
341+
finally
342+
{
343+
if (free)
344+
{
345+
Runtime.XDecref(args);
346+
}
347+
}
348+
return value;
349+
}
350+
351+
352+
/// <summary>
353+
/// Implements __setitem__ for reflected classes and value types.
354+
/// </summary>
355+
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
356+
{
357+
IntPtr tp = Runtime.PyObject_TYPE(ob);
358+
var cls = (ClassBase)GetManagedObject(tp);
359+
360+
if (cls.indexer == null || !cls.indexer.CanSet)
361+
{
362+
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
363+
return -1;
364+
}
365+
366+
// Arg may be a tuple in the case of an indexer with multiple
367+
// parameters. If so, use it directly, else make a new tuple
368+
// with the index arg (method binders expect arg tuples).
369+
IntPtr args = idx;
370+
var free = false;
371+
372+
if (!Runtime.PyTuple_Check(idx))
373+
{
374+
args = Runtime.PyTuple_New(1);
375+
Runtime.XIncref(idx);
376+
Runtime.PyTuple_SetItem(args, 0, idx);
377+
free = true;
378+
}
379+
380+
// Get the args passed in.
381+
var i = Runtime.PyTuple_Size(args);
382+
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
383+
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
384+
var temp = i + numOfDefaultArgs;
385+
IntPtr real = Runtime.PyTuple_New(temp + 1);
386+
for (var n = 0; n < i; n++)
387+
{
388+
IntPtr item = Runtime.PyTuple_GetItem(args, n);
389+
Runtime.XIncref(item);
390+
Runtime.PyTuple_SetItem(real, n, item);
391+
}
392+
393+
// Add Default Args if needed
394+
for (var n = 0; n < numOfDefaultArgs; n++)
395+
{
396+
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
397+
Runtime.XIncref(item);
398+
Runtime.PyTuple_SetItem(real, n + i, item);
399+
}
400+
// no longer need defaultArgs
401+
Runtime.XDecref(defaultArgs);
402+
i = temp;
403+
404+
// Add value to argument list
405+
Runtime.XIncref(v);
406+
Runtime.PyTuple_SetItem(real, i, v);
407+
408+
try
409+
{
410+
cls.indexer.SetItem(ob, real);
411+
}
412+
finally
413+
{
414+
Runtime.XDecref(real);
415+
416+
if (free)
417+
{
418+
Runtime.XDecref(args);
419+
}
420+
}
421+
422+
if (Exceptions.ErrorOccurred())
423+
{
424+
return -1;
425+
}
426+
427+
return 0;
428+
}
305429
}
306430
}

src/runtime/classobject.cs

Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -154,132 +154,6 @@ public override IntPtr type_subscript(IntPtr idx)
154154
}
155155

156156

157-
/// <summary>
158-
/// Implements __getitem__ for reflected classes and value types.
159-
/// </summary>
160-
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
161-
{
162-
//ManagedType self = GetManagedObject(ob);
163-
IntPtr tp = Runtime.PyObject_TYPE(ob);
164-
var cls = (ClassBase)GetManagedObject(tp);
165-
166-
if (cls.indexer == null || !cls.indexer.CanGet)
167-
{
168-
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
169-
return IntPtr.Zero;
170-
}
171-
172-
// Arg may be a tuple in the case of an indexer with multiple
173-
// parameters. If so, use it directly, else make a new tuple
174-
// with the index arg (method binders expect arg tuples).
175-
IntPtr args = idx;
176-
var free = false;
177-
178-
if (!Runtime.PyTuple_Check(idx))
179-
{
180-
args = Runtime.PyTuple_New(1);
181-
Runtime.XIncref(idx);
182-
Runtime.PyTuple_SetItem(args, 0, idx);
183-
free = true;
184-
}
185-
186-
IntPtr value;
187-
188-
try
189-
{
190-
value = cls.indexer.GetItem(ob, args);
191-
}
192-
finally
193-
{
194-
if (free)
195-
{
196-
Runtime.XDecref(args);
197-
}
198-
}
199-
return value;
200-
}
201-
202-
203-
/// <summary>
204-
/// Implements __setitem__ for reflected classes and value types.
205-
/// </summary>
206-
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
207-
{
208-
//ManagedType self = GetManagedObject(ob);
209-
IntPtr tp = Runtime.PyObject_TYPE(ob);
210-
var cls = (ClassBase)GetManagedObject(tp);
211-
212-
if (cls.indexer == null || !cls.indexer.CanSet)
213-
{
214-
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
215-
return -1;
216-
}
217-
218-
// Arg may be a tuple in the case of an indexer with multiple
219-
// parameters. If so, use it directly, else make a new tuple
220-
// with the index arg (method binders expect arg tuples).
221-
IntPtr args = idx;
222-
var free = false;
223-
224-
if (!Runtime.PyTuple_Check(idx))
225-
{
226-
args = Runtime.PyTuple_New(1);
227-
Runtime.XIncref(idx);
228-
Runtime.PyTuple_SetItem(args, 0, idx);
229-
free = true;
230-
}
231-
232-
// Get the args passed in.
233-
var i = Runtime.PyTuple_Size(args);
234-
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
235-
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
236-
var temp = i + numOfDefaultArgs;
237-
IntPtr real = Runtime.PyTuple_New(temp + 1);
238-
for (var n = 0; n < i; n++)
239-
{
240-
IntPtr item = Runtime.PyTuple_GetItem(args, n);
241-
Runtime.XIncref(item);
242-
Runtime.PyTuple_SetItem(real, n, item);
243-
}
244-
245-
// Add Default Args if needed
246-
for (var n = 0; n < numOfDefaultArgs; n++)
247-
{
248-
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
249-
Runtime.XIncref(item);
250-
Runtime.PyTuple_SetItem(real, n + i, item);
251-
}
252-
// no longer need defaultArgs
253-
Runtime.XDecref(defaultArgs);
254-
i = temp;
255-
256-
// Add value to argument list
257-
Runtime.XIncref(v);
258-
Runtime.PyTuple_SetItem(real, i, v);
259-
260-
try
261-
{
262-
cls.indexer.SetItem(ob, real);
263-
}
264-
finally
265-
{
266-
Runtime.XDecref(real);
267-
268-
if (free)
269-
{
270-
Runtime.XDecref(args);
271-
}
272-
}
273-
274-
if (Exceptions.ErrorOccurred())
275-
{
276-
return -1;
277-
}
278-
279-
return 0;
280-
}
281-
282-
283157
/// <summary>
284158
/// This is a hack. Generally, no managed class is considered callable
285159
/// from Python - with the exception of System.Delegate. It is useful

src/tests/test_interface.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,10 @@ def test_implementation_access():
120120
assert 100 == i.__implementation__
121121
assert clrVal == i.__raw_implementation__
122122
assert i.__implementation__ != i.__raw_implementation__
123+
124+
def test_indexer():
125+
"""Test that indexers can be accessed through interfaces"""
126+
from System.Collections.Generic import Dictionary, IDictionary
127+
d = IDictionary[str, str](Dictionary[str, str]())
128+
d["one"] = "1"
129+
assert d["one"] == "1"

0 commit comments

Comments
 (0)