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

Skip to content

Commit 9c870c1

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 03cf4ac commit 9c870c1

File tree

5 files changed

+135
-128
lines changed

5 files changed

+135
-128
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ details about the cause of the failure
2929
- Fixed a bug where all .NET class instances were considered Iterable
3030
- Fix incorrect choice of method to invoke when using keyword arguments.
3131
- Fix non-delegate types incorrectly appearing as callable.
32+
- Indexers can now be used with interface objects
3233

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

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
@@ -152,131 +152,5 @@ public override IntPtr type_subscript(IntPtr idx)
152152
}
153153
return Exceptions.RaiseTypeError("unsubscriptable object");
154154
}
155-
156-
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-
}
281155
}
282156
}

src/tests/test_indexer.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,11 @@ def test_indexer_abuse():
595595

596596
with pytest.raises(AttributeError):
597597
del ob.__setitem__
598+
599+
600+
def test_indexer_accessed_through_interface():
601+
"""Test that indexers can be accessed through interfaces"""
602+
from System.Collections.Generic import Dictionary, IDictionary
603+
d = IDictionary[str, str](Dictionary[str, str]())
604+
d["one"] = "1"
605+
assert d["one"] == "1"

0 commit comments

Comments
 (0)