Skip to content

Commit 42697ba

Browse files
authored
Merge branch 'master' into list-codec
2 parents cde2eca + 50d947f commit 42697ba

33 files changed

+460
-188
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- Christoph Gohlke ([@cgohlke](https://github.com/cgohlke))
2929
- Christopher Bremner ([@chrisjbremner](https://github.com/chrisjbremner))
3030
- Christopher Pow ([@christopherpow](https://github.com/christopherpow))
31+
- Daniel Abrahamsson ([@danabr](https://github.com/danabr))
3132
- Daniel Fernandez ([@fdanny](https://github.com/fdanny))
3233
- Daniel Santana ([@dgsantana](https://github.com/dgsantana))
3334
- Dave Hirschfeld ([@dhirschfeld](https://github.com/dhirschfeld))

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1414
- `clr.AddReference` may now throw errors besides `FileNotFoundException`, that provide more
1515
details about the cause of the failure
1616
- `clr.AddReference` no longer adds ".dll" implicitly
17+
- `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.
1723

1824
### Fixed
1925

2026
- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash
2127
- Fix incorrect dereference in params array handling
2228
- Fix `object[]` parameters taking precedence when should not in overload resolution
29+
- Fixed a bug where all .NET class instances were considered Iterable
30+
- Fix incorrect choice of method to invoke when using keyword arguments.
2331

2432
## [2.5.0][] - 2020-06-14
2533

src/embed_tests/TestFinalizer.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ public void CollectBasicObject()
8787
Assert.GreaterOrEqual(objectCount, 1);
8888
}
8989

90+
[Test]
91+
public void CollectOnShutdown()
92+
{
93+
MakeAGarbage(out var shortWeak, out var longWeak);
94+
FullGCCollect();
95+
var garbage = Finalizer.Instance.GetCollectedObjects();
96+
Assert.IsNotEmpty(garbage);
97+
PythonEngine.Shutdown();
98+
garbage = Finalizer.Instance.GetCollectedObjects();
99+
Assert.IsEmpty(garbage);
100+
}
101+
90102
private static void MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
91103
{
92104
PyLong obj = new PyLong(1024);

src/perf_tests/Python.PerformanceTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
</ItemGroup>
2929

3030
<Target Name="GetRuntimeLibBuildOutput" BeforeTargets="Build">
31-
<MSBuild Projects="..\runtime\Python.Runtime.15.csproj" Properties="PYTHONNET_PY3_VERSION=PYTHON35;Configuration=$(Configuration);TargetFramework=net40;Python3Version=PYTHON35;OutputPath=bin\for_perf\">
31+
<MSBuild Projects="..\runtime\Python.Runtime.15.csproj" Properties="PYTHONNET_PY3_VERSION=PYTHON38;Configuration=$(Configuration);TargetFramework=net40;Python3Version=PYTHON38;OutputPath=bin\for_perf\">
3232
<Output TaskParameter="TargetOutputs" ItemName="NewPythonRuntime" />
3333
</MSBuild>
3434
</Target>

src/runtime/arrayobject.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
4343
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
4444
{
4545
var obj = (CLRObject)GetManagedObject(ob);
46+
var arrObj = (ArrayObject)GetManagedObjectType(ob);
4647
var items = obj.inst as Array;
47-
Type itemType = obj.inst.GetType().GetElementType();
48+
Type itemType = arrObj.type.GetElementType();
4849
int rank = items.Rank;
4950
int index;
5051
object value;

src/runtime/constructorbinder.cs

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

9191
IntPtr eargs = Runtime.PyTuple_New(0);
92-
binding = Bind(inst, eargs, kw);
92+
binding = Bind(inst, eargs, IntPtr.Zero);
9393
Runtime.XDecref(eargs);
9494

9595
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;

src/runtime/interfaceobject.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,43 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
7171
return IntPtr.Zero;
7272
}
7373

74-
return CLRObject.GetInstHandle(obj, self.pyHandle);
74+
return self.WrapObject(obj);
75+
}
76+
77+
/// <summary>
78+
/// Wrap the given object in an interface object, so that only methods
79+
/// of the interface are available.
80+
/// </summary>
81+
public IntPtr WrapObject(object impl)
82+
{
83+
var objPtr = CLRObject.GetInstHandle(impl, pyHandle);
84+
return objPtr;
85+
}
86+
87+
/// <summary>
88+
/// Expose the wrapped implementation through attributes in both
89+
/// converted/encoded (__implementation__) and raw (__raw_implementation__) form.
90+
/// </summary>
91+
public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
92+
{
93+
var clrObj = (CLRObject)GetManagedObject(ob);
94+
95+
if (!Runtime.PyString_Check(key))
96+
{
97+
return Exceptions.RaiseTypeError("string expected");
98+
}
99+
100+
string name = Runtime.GetManagedString(key);
101+
if (name == "__implementation__")
102+
{
103+
return Converter.ToPython(clrObj.inst);
104+
}
105+
else if (name == "__raw_implementation__")
106+
{
107+
return CLRObject.GetInstHandle(clrObj.inst);
108+
}
109+
110+
return Runtime.PyObject_GenericGetAttr(ob, key);
75111
}
76112
}
77113
}

src/runtime/managedtype.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@ internal static ManagedType GetManagedObject(IntPtr ob)
4545
return null;
4646
}
4747

48+
/// <summary>
49+
/// Given a Python object, return the associated managed object type or null.
50+
/// </summary>
51+
internal static ManagedType GetManagedObjectType(IntPtr ob)
52+
{
53+
if (ob != IntPtr.Zero)
54+
{
55+
IntPtr tp = Runtime.PyObject_TYPE(ob);
56+
var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
57+
if ((flags & TypeFlags.Managed) != 0)
58+
{
59+
tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
60+
var gc = (GCHandle)tp;
61+
return (ManagedType)gc.Target;
62+
}
63+
}
64+
return null;
65+
}
66+
4867

4968
internal static ManagedType GetManagedObjectErr(IntPtr ob)
5069
{

src/runtime/methodbinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
580580
var match = false;
581581
paramsArray = parameters.Length > 0 ? Attribute.IsDefined(parameters[parameters.Length - 1], typeof(ParamArrayAttribute)) : false;
582582

583-
if (positionalArgumentCount == parameters.Length)
583+
if (positionalArgumentCount == parameters.Length && kwargDict.Count == 0)
584584
{
585585
match = true;
586586
}
@@ -744,7 +744,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i
744744
Type pt = pi[i].ParameterType;
745745
if (pi[i].IsOut || pt.IsByRef)
746746
{
747-
v = Converter.ToPython(binding.args[i], pt);
747+
v = Converter.ToPython(binding.args[i], pt.GetElementType());
748748
Runtime.PyTuple_SetItem(t, n, v);
749749
n++;
750750
}

0 commit comments

Comments
 (0)