Skip to content
This repository was archived by the owner on Jul 22, 2023. It is now read-only.

Commit 3203457

Browse files
committed
Merge branch 'master' into soft-shutdown
2 parents 3a17f36 + f808166 commit 3203457

21 files changed

+391
-191
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,4 @@
7979
- ([@stonebig](https://github.com/stonebig))
8080
- ([@testrunner123](https://github.com/testrunner123))
8181
- ([@DanBarzilian](https://github.com/DanBarzilian))
82+
- ([@alxnull](https://github.com/alxnull))

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,21 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1515
details about the cause of the failure
1616
- `clr.AddReference` no longer adds ".dll" implicitly
1717
- `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method
18+
- Return values from .NET methods that return an interface are now automatically
19+
wrapped in that interface. This is a breaking change for users that rely on being
20+
able to access members that are part of the implementation class, but not the
21+
interface. Use the new __implementation__ or __raw_implementation__ properties to
22+
if you need to "downcast" to the implementation class.
1823

1924
### Fixed
2025

2126
- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash
2227
- Fix incorrect dereference in params array handling
2328
- Fix `object[]` parameters taking precedence when should not in overload resolution
2429
- Fixed a bug where all .NET class instances were considered Iterable
30+
- Fix incorrect choice of method to invoke when using keyword arguments.
31+
- Fix non-delegate types incorrectly appearing as callable.
32+
- Indexers can now be used with interface objects
2533

2634
## [2.5.0][] - 2020-06-14
2735

src/runtime/arrayobject.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
4141
/// <summary>
4242
/// Implements __getitem__ for array types.
4343
/// </summary>
44-
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
44+
public new static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
4545
{
4646
var obj = (CLRObject)GetManagedObject(ob);
47+
var arrObj = (ArrayObject)GetManagedObjectType(ob);
4748
var items = obj.inst as Array;
48-
Type itemType = obj.inst.GetType().GetElementType();
49+
Type itemType = arrObj.type.GetElementType();
4950
int rank = items.Rank;
5051
int index;
5152
object value;
@@ -133,7 +134,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
133134
/// <summary>
134135
/// Implements __setitem__ for array types.
135136
/// </summary>
136-
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
137+
public static new int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
137138
{
138139
var obj = (CLRObject)GetManagedObject(ob);
139140
var items = obj.inst as Array;

src/runtime/classbase.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,5 +327,129 @@ protected override void OnLoad(InterDomainContext context)
327327
gcHandle = AllocGCHandle();
328328
Marshal.WriteIntPtr(pyHandle, TypeOffset.magic(), (IntPtr)gcHandle);
329329
}
330+
331+
332+
/// <summary>
333+
/// Implements __getitem__ for reflected classes and value types.
334+
/// </summary>
335+
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
336+
{
337+
IntPtr tp = Runtime.PyObject_TYPE(ob);
338+
var cls = (ClassBase)GetManagedObject(tp);
339+
340+
if (cls.indexer == null || !cls.indexer.CanGet)
341+
{
342+
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
343+
return IntPtr.Zero;
344+
}
345+
346+
// Arg may be a tuple in the case of an indexer with multiple
347+
// parameters. If so, use it directly, else make a new tuple
348+
// with the index arg (method binders expect arg tuples).
349+
IntPtr args = idx;
350+
var free = false;
351+
352+
if (!Runtime.PyTuple_Check(idx))
353+
{
354+
args = Runtime.PyTuple_New(1);
355+
Runtime.XIncref(idx);
356+
Runtime.PyTuple_SetItem(args, 0, idx);
357+
free = true;
358+
}
359+
360+
IntPtr value;
361+
362+
try
363+
{
364+
value = cls.indexer.GetItem(ob, args);
365+
}
366+
finally
367+
{
368+
if (free)
369+
{
370+
Runtime.XDecref(args);
371+
}
372+
}
373+
return value;
374+
}
375+
376+
377+
/// <summary>
378+
/// Implements __setitem__ for reflected classes and value types.
379+
/// </summary>
380+
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
381+
{
382+
IntPtr tp = Runtime.PyObject_TYPE(ob);
383+
var cls = (ClassBase)GetManagedObject(tp);
384+
385+
if (cls.indexer == null || !cls.indexer.CanSet)
386+
{
387+
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
388+
return -1;
389+
}
390+
391+
// Arg may be a tuple in the case of an indexer with multiple
392+
// parameters. If so, use it directly, else make a new tuple
393+
// with the index arg (method binders expect arg tuples).
394+
IntPtr args = idx;
395+
var free = false;
396+
397+
if (!Runtime.PyTuple_Check(idx))
398+
{
399+
args = Runtime.PyTuple_New(1);
400+
Runtime.XIncref(idx);
401+
Runtime.PyTuple_SetItem(args, 0, idx);
402+
free = true;
403+
}
404+
405+
// Get the args passed in.
406+
var i = Runtime.PyTuple_Size(args);
407+
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
408+
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
409+
var temp = i + numOfDefaultArgs;
410+
IntPtr real = Runtime.PyTuple_New(temp + 1);
411+
for (var n = 0; n < i; n++)
412+
{
413+
IntPtr item = Runtime.PyTuple_GetItem(args, n);
414+
Runtime.XIncref(item);
415+
Runtime.PyTuple_SetItem(real, n, item);
416+
}
417+
418+
// Add Default Args if needed
419+
for (var n = 0; n < numOfDefaultArgs; n++)
420+
{
421+
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
422+
Runtime.XIncref(item);
423+
Runtime.PyTuple_SetItem(real, n + i, item);
424+
}
425+
// no longer need defaultArgs
426+
Runtime.XDecref(defaultArgs);
427+
i = temp;
428+
429+
// Add value to argument list
430+
Runtime.XIncref(v);
431+
Runtime.PyTuple_SetItem(real, i, v);
432+
433+
try
434+
{
435+
cls.indexer.SetItem(ob, real);
436+
}
437+
finally
438+
{
439+
Runtime.XDecref(real);
440+
441+
if (free)
442+
{
443+
Runtime.XDecref(args);
444+
}
445+
}
446+
447+
if (Exceptions.ErrorOccurred())
448+
{
449+
return -1;
450+
}
451+
452+
return 0;
453+
}
330454
}
331455
}

src/runtime/classobject.cs

Lines changed: 0 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -153,162 +153,5 @@ public override IntPtr type_subscript(IntPtr idx)
153153
}
154154
return Exceptions.RaiseTypeError("unsubscriptable object");
155155
}
156-
157-
158-
/// <summary>
159-
/// Implements __getitem__ for reflected classes and value types.
160-
/// </summary>
161-
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
162-
{
163-
//ManagedType self = GetManagedObject(ob);
164-
IntPtr tp = Runtime.PyObject_TYPE(ob);
165-
var cls = (ClassBase)GetManagedObject(tp);
166-
167-
if (cls.indexer == null || !cls.indexer.CanGet)
168-
{
169-
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
170-
return IntPtr.Zero;
171-
}
172-
173-
// Arg may be a tuple in the case of an indexer with multiple
174-
// parameters. If so, use it directly, else make a new tuple
175-
// with the index arg (method binders expect arg tuples).
176-
IntPtr args = idx;
177-
var free = false;
178-
179-
if (!Runtime.PyTuple_Check(idx))
180-
{
181-
args = Runtime.PyTuple_New(1);
182-
Runtime.XIncref(idx);
183-
Runtime.PyTuple_SetItem(args, 0, idx);
184-
free = true;
185-
}
186-
187-
IntPtr value;
188-
189-
try
190-
{
191-
value = cls.indexer.GetItem(ob, args);
192-
}
193-
finally
194-
{
195-
if (free)
196-
{
197-
Runtime.XDecref(args);
198-
}
199-
}
200-
return value;
201-
}
202-
203-
204-
/// <summary>
205-
/// Implements __setitem__ for reflected classes and value types.
206-
/// </summary>
207-
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
208-
{
209-
//ManagedType self = GetManagedObject(ob);
210-
IntPtr tp = Runtime.PyObject_TYPE(ob);
211-
var cls = (ClassBase)GetManagedObject(tp);
212-
213-
if (cls.indexer == null || !cls.indexer.CanSet)
214-
{
215-
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
216-
return -1;
217-
}
218-
219-
// Arg may be a tuple in the case of an indexer with multiple
220-
// parameters. If so, use it directly, else make a new tuple
221-
// with the index arg (method binders expect arg tuples).
222-
IntPtr args = idx;
223-
var free = false;
224-
225-
if (!Runtime.PyTuple_Check(idx))
226-
{
227-
args = Runtime.PyTuple_New(1);
228-
Runtime.XIncref(idx);
229-
Runtime.PyTuple_SetItem(args, 0, idx);
230-
free = true;
231-
}
232-
233-
// Get the args passed in.
234-
var i = Runtime.PyTuple_Size(args);
235-
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
236-
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
237-
var temp = i + numOfDefaultArgs;
238-
IntPtr real = Runtime.PyTuple_New(temp + 1);
239-
for (var n = 0; n < i; n++)
240-
{
241-
IntPtr item = Runtime.PyTuple_GetItem(args, n);
242-
Runtime.XIncref(item);
243-
Runtime.PyTuple_SetItem(real, n, item);
244-
}
245-
246-
// Add Default Args if needed
247-
for (var n = 0; n < numOfDefaultArgs; n++)
248-
{
249-
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
250-
Runtime.XIncref(item);
251-
Runtime.PyTuple_SetItem(real, n + i, item);
252-
}
253-
// no longer need defaultArgs
254-
Runtime.XDecref(defaultArgs);
255-
i = temp;
256-
257-
// Add value to argument list
258-
Runtime.XIncref(v);
259-
Runtime.PyTuple_SetItem(real, i, v);
260-
261-
try
262-
{
263-
cls.indexer.SetItem(ob, real);
264-
}
265-
finally
266-
{
267-
Runtime.XDecref(real);
268-
269-
if (free)
270-
{
271-
Runtime.XDecref(args);
272-
}
273-
}
274-
275-
if (Exceptions.ErrorOccurred())
276-
{
277-
return -1;
278-
}
279-
280-
return 0;
281-
}
282-
283-
284-
/// <summary>
285-
/// This is a hack. Generally, no managed class is considered callable
286-
/// from Python - with the exception of System.Delegate. It is useful
287-
/// to be able to call a System.Delegate instance directly, especially
288-
/// when working with multicast delegates.
289-
/// </summary>
290-
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
291-
{
292-
//ManagedType self = GetManagedObject(ob);
293-
IntPtr tp = Runtime.PyObject_TYPE(ob);
294-
var cb = (ClassBase)GetManagedObject(tp);
295-
296-
if (cb.type != typeof(Delegate))
297-
{
298-
Exceptions.SetError(Exceptions.TypeError, "object is not callable");
299-
return IntPtr.Zero;
300-
}
301-
302-
var co = (CLRObject)GetManagedObject(ob);
303-
var d = co.inst as Delegate;
304-
BindingFlags flags = BindingFlags.Public |
305-
BindingFlags.NonPublic |
306-
BindingFlags.Instance |
307-
BindingFlags.Static;
308-
309-
MethodInfo method = d.GetType().GetMethod("Invoke", flags);
310-
var binder = new MethodBinder(method);
311-
return binder.Invoke(ob, args, kw);
312-
}
313156
}
314157
}

src/runtime/constructorbinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info)
9090
// any extra args are intended for the subclass' __init__.
9191

9292
IntPtr eargs = Runtime.PyTuple_New(0);
93-
binding = Bind(inst, eargs, kw);
93+
binding = Bind(inst, eargs, IntPtr.Zero);
9494
Runtime.XDecref(eargs);
9595

9696
if (binding == null)

src/runtime/converter.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,21 @@ internal static IntPtr ToPython(object value, Type type)
173173
}
174174
}
175175

176+
if (type.IsInterface)
177+
{
178+
var ifaceObj = (InterfaceObject)ClassManager.GetClass(type);
179+
return ifaceObj.WrapObject(value);
180+
}
181+
182+
// We need to special case interface array handling to ensure we
183+
// produce the correct type. Value may be an array of some concrete
184+
// type (FooImpl[]), but we want access to go via the interface type
185+
// (IFoo[]).
186+
if (type.IsArray && type.GetElementType().IsInterface)
187+
{
188+
return CLRObject.GetInstHandle(value, type);
189+
}
190+
176191
// it the type is a python subclass of a managed type then return the
177192
// underlying python object rather than construct a new wrapper object.
178193
var pyderived = value as IPythonDerivedType;

0 commit comments

Comments
 (0)