8000 Merge branch 'master' into intern-string · pythonnet/pythonnet@49e3340 · GitHub
[go: up one dir, main page]

Skip to content

Commit 49e3340

Browse files
committed
Merge branch 'master' into intern-string
2 parents ac50675 + 7f4f77b commit 49e3340

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+847
-872
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ python:
55
- 3.8
66
- 3.7
77
- 3.6
8-
- 3.5
98

109
env:
1110
matrix:

AUTHORS.md

Lines changed: 2 additions & 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))
@@ -78,3 +79,4 @@
7879
- ([@stonebig](https://github.com/stonebig))
7980
- ([@testrunner123](https://github.com/testrunner123))
8081
- ([@DanBarzilian](https://github.com/DanBarzilian))
82+
- ([@alxnull](https://github.com/alxnull))

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,27 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1010
### Added
1111

1212
### Changed
13-
- Drop support for Python 2
13+
- Drop support for Python 2, 3.4, and 3.5
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
28+
- 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.
31+
- Fix non-delegate types incorrectly appearing as callable.
32+
- Indexers can now be used with interface objects
33+
- Fixed a bug where indexers could not be used if they were inherited
2234

2335
## [2.5.0][] - 2020-06-14
2436

appveyor.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@ environment:
2020
BUILD_OPTS: --xplat
2121
- PYTHON_VERSION: 3.6
2222
BUILD_OPTS: --xplat
23-
- PYTHON_VERSION: 3.5
24-
BUILD_OPTS: --xplat
2523
- PYTHON_VERSION: 3.8
2624
- PYTHON_VERSION: 3.7
2725
- PYTHON_VERSION: 3.6
28-
- PYTHON_VERSION: 3.5
2926
- PYTHON_VERSION: 3.7
3027
PYTHONNET_SHUTDOWN_MODE: Soft
3128
- PYTHON_VERSION: 3.8

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,6 @@ def run(self):
637637
"License :: OSI Approved :: MIT License",
638638
"Programming Language :: C#",
639639
"Programming Language :: Python :: 3",
640-
"Programming Language :: Python :: 3.5",
641640
"Programming Language :: Python :: 3.6",
642641
"Programming Language :: Python :: 3.7",
643642
"Programming Language :: Python :: 3.8",

src/embed_tests/TestFinalizer.cs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using NUnit.Framework;
22
using Python.Runtime;
33
using System;
4+
using System.Collections.Generic;
5+
using System.ComponentModel;
6+
using System.Diagnostics;
47
using System.Linq;
58
using System.Threading;
69

@@ -25,10 +28,22 @@ public void TearDown()
2528
PythonEngine.Shutdown();
2629
}
2730

28-
private static void FullGCCollect()
31+
private static bool FullGCCollect()
2932
{
3033
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
31-
GC.WaitForPendingFinalizers();
34+
try
35+
{
36+
return GC.WaitForFullGCComplete() == GCNotificationStatus.Succeeded;
37+
}
38+
catch (NotImplementedException)
39+
{
40+
// Some clr runtime didn't implement GC.WaitForFullGCComplete yet.
41+
return false;
42+
}
43+
finally
44+
{
45+
GC.WaitForPendingFinalizers();
46+
}
3247
}
3348

3449
[Test]
@@ -87,12 +102,34 @@ public void CollectBasicObject()
87102
Assert.GreaterOrEqual(objectCount, 1);
88103
}
89104

90-
private static void MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
105+
[Test]
106+
[Ignore("Ignore temporarily")]
107+
public void CollectOnShutdown()
108+
{
109+
IntPtr op = MakeAGarbage(out var shortWeak, out var longWeak);
110+
int hash = shortWeak.Target.GetHashCode();
111+
List<WeakReference> garbage;
112+
if (!FullGCCollect())
113+
{
114+
Assert.IsTrue(WaitForCollected(op, hash, 10000));
115+
}
116+
Assert.IsFalse(shortWeak.IsAlive);
117+
garbage = Finalizer.Instance.GetCollectedObjects();
118+
Assert.IsNotEmpty(garbage, "The garbage object should be collected");
119+
Assert.IsTrue(garbage.Any(r => ReferenceEquals(r.Target, longWeak.Target)),
120+
"Garbage should contains the collected object");
121+
122+
PythonEngine.Shutdown();
123+
garbage = Finalizer.Instance.GetCollectedObjects();
124+
Assert.IsEmpty(garbage);
125+
}
126+
127+
private static IntPtr MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
91128
{
92129
PyLong obj = new PyLong(1024);
93130
shortWeak = new WeakReference(obj);
94131
longWeak = new WeakReference(obj, true);
95-
obj = null;
132+
return obj.Handle;
96133
}
97134

98135
private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale)
@@ -249,5 +286,28 @@ private static IntPtr CreateStringGarbage()
249286
return s1.Handle;
250287
}
251288

289+
private static bool WaitForCollected(IntPtr op, int hash, int milliseconds)
290+
{
291+
var stopwatch = Stopwatch.StartNew();
292+
do
293+
{
294+
var garbage = Finalizer.Instance.GetCollectedObjects();
295+
foreach (var item in garbage)
296+
{
297+
// The validation is not 100% precise,
298+
// but it's rare that two conditions satisfied but they're still not the same object.
299+
if (item.Target.GetHashCode() != hash)
300+
{
301+
continue;
302+
}
303+
var obj = (IPyDisposable)item.Target;
304+
if (obj.GetTrackedHandles().Contains(op))
305+
{
306+
return true;
307+
}
308+
}
309+
} while (stopwatch.ElapsedMilliseconds < milliseconds);
310+
return false;
311+
}
252312
}
253313
}

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/BorrowedReference.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ readonly ref struct BorrowedReference
1010
readonly IntPtr pointer;
1111
public bool IsNull => this.pointer == IntPtr.Zero;
1212

13+
1314
/// <summary>Gets a raw pointer to the Python object</summary>
14-
public IntPtr DangerousGetAddress() => this.pointer;
15+
public IntPtr DangerousGetAddress()
16+
=> this.IsNull ? throw new NullReferenceException() : this.pointer;
1517

1618
/// <summary>
1719
/// Creates new instance of <see cref="BorrowedReference"/> from raw pointer. Unsafe.

src/runtime/Python.Runtime.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,6 @@
166166
<Compile Include="$(PythonInteropFile)" />
167167
</ItemGroup>
168168
<ItemGroup Condition=" '$(PythonInteropFile)' == '' ">
169-
<Compile Include="interop34.cs" />
170-
<Compile Include="interop35.cs" />
171169
<Compile Include="interop36.cs" />
172170
<Compile Include="interop37.cs" />
173171
<Compile Include="interop38.cs" />

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/classmanager.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,25 @@ private static ClassInfo GetClassInfo(Type type)
461461
ci.members[name] = ob;
462462
}
463463

464+
if (ci.indexer == null && type.IsClass)
465+
{
466+
// Indexer may be inherited.
467+
var parent = type.BaseType;
468+
while (parent != null && ci.indexer == null)
469+
{
470+
foreach (var prop in parent.GetProperties()) {
471+
var args = prop.GetIndexParameters();
472+
if (args.GetLength(0) > 0)
473+
{
474+
ci.indexer = new Indexer();
475+
ci.indexer.AddProperty(prop);
476+
break;
477+
}
478+
}
479+
parent = parent.BaseType;
480+
}
481+
}
482+
464483
return ci;
465484
}
466485

0 commit comments

Comments
 (0)
0