Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Track Runtime run number#1074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
filmor merged 9 commits intopythonnet:masterfromlosttech:bugs/1073
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
9 commits
Select commitHold shift + click to select a range
4f657d4
Track Runtime run number. Assert, that PyObjects are only disposed in…
lostmsuMar 3, 2020
62e2fb4
dispose registered codecs and interop configuration during shutdown
lostmsuNov 12, 2021
1897d1b
Finalizer raises FinalizationException when it sees an object from pr…
lostmsuNov 12, 2021
3909639
allow tests to pass when objects are leaking due to being GCed after …
lostmsuNov 12, 2021
60d90c6
removed code testing possiblity to dispose objects after domain restart
lostmsuNov 12, 2021
9e815a6
allow leaking PyObject instances when CLR is stared from Python
lostmsuNov 12, 2021
8611dde
WaitForFullGCComplete was never needed, and was used incorrectly
lostmsuNov 12, 2021
6383a28
remove finalizer assert for raw pointer value; skip collection assert…
lostmsuNov 22, 2021
47b3913
renamed run system property to __pythonnet_run__ to be consistent wit…
lostmsuNov 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletionsrc/embed_tests/Codecs.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -421,13 +421,18 @@ public PyObject TryEncode(object value)
}
}

class InstancelessExceptionDecoder : IPyObjectDecoder
class InstancelessExceptionDecoder : IPyObjectDecoder, IDisposable
{
readonly PyObject PyErr = Py.Import("clr.interop").GetAttr("PyErr");

public bool CanDecode(PyType objectType, Type targetType)
=> PythonReferenceComparer.Instance.Equals(PyErr, objectType);

public void Dispose()
{
PyErr.Dispose();
}

public bool TryDecode<T>(PyObject pyObj, out T value)
{
if (pyObj.HasAttr("value"))
Expand Down
16 changes: 16 additions & 0 deletionssrc/embed_tests/GlobalTestsSetup.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,22 @@ namespace Python.EmbeddingTest
[SetUpFixture]
public partial class GlobalTestsSetup
{
[OneTimeSetUp]
public void GlobalSetup()
{
Finalizer.Instance.ErrorHandler += FinalizerErrorHandler;
}

private void FinalizerErrorHandler(object sender, Finalizer.ErrorArgs e)
{
if (e.Error is RuntimeShutdownException)
{
// allow objects to leak after the python runtime run
// they were created in is gone
e.Handled = true;
}
}

[OneTimeTearDown]
public void FinalCleanup()
{
Expand Down
1 change: 1 addition & 0 deletionssrc/embed_tests/Inheritance.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,6 +24,7 @@ public void SetUp()
[OneTimeTearDown]
public void Dispose()
{
ExtraBaseTypeProvider.ExtraBase.Dispose();
PythonEngine.Shutdown();
}

Expand Down
110 changes: 0 additions & 110 deletionssrc/embed_tests/TestDomainReload.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,116 +179,6 @@ public static void CrossDomainObject()

#endregion

#region Tempary tests

// https://github.com/pythonnet/pythonnet/pull/1074#issuecomment-596139665
[Test]
public void CrossReleaseBuiltinType()
{
void ExecTest()
{
try
{
PythonEngine.Initialize();
var numRef = CreateNumReference();
Assert.True(numRef.IsAlive);
PythonEngine.Shutdown(); // <- "run" 1 ends
PythonEngine.Initialize(); // <- "run" 2 starts

GC.Collect();
GC.WaitForPendingFinalizers(); // <- this will put former `num` into Finalizer queue
Finalizer.Instance.Collect();
// ^- this will call PyObject.Dispose, which will call XDecref on `num.Handle`,
// but Python interpreter from "run" 1 is long gone, so it will corrupt memory instead.
Assert.False(numRef.IsAlive);
}
finally
{
PythonEngine.Shutdown();
}
}

var errorArgs = new List<Finalizer.ErrorArgs>();
void ErrorHandler(object sender, Finalizer.ErrorArgs e)
{
errorArgs.Add(e);
}
Finalizer.Instance.ErrorHandler += ErrorHandler;
try
{
for (int i = 0; i < 10; i++)
{
ExecTest();
}
}
finally
{
Finalizer.Instance.ErrorHandler -= ErrorHandler;
}
Assert.AreEqual(errorArgs.Count, 0);
}

[Test]
public void CrossReleaseCustomType()
{
void ExecTest()
{
try
{
PythonEngine.Initialize();
var objRef = CreateConcreateObject();
Assert.True(objRef.IsAlive);
PythonEngine.Shutdown(); // <- "run" 1 ends
PythonEngine.Initialize(); // <- "run" 2 starts
GC.Collect();
GC.WaitForPendingFinalizers();
Finalizer.Instance.Collect();
Assert.False(objRef.IsAlive);
}
finally
{
PythonEngine.Shutdown();
}
}

var errorArgs = new List<Finalizer.ErrorArgs>();
void ErrorHandler(object sender, Finalizer.ErrorArgs e)
{
errorArgs.Add(e);
}
Finalizer.Instance.ErrorHandler += ErrorHandler;
try
{
for (int i = 0; i < 10; i++)
{
ExecTest();
}
}
finally
{
Finalizer.Instance.ErrorHandler -= ErrorHandler;
}
Assert.AreEqual(errorArgs.Count, 0);
}

private static WeakReference CreateNumReference()
{
var num = 3216757418.ToPython();
Assert.AreEqual(num.Refcount, 1);
WeakReference numRef = new WeakReference(num, false);
return numRef;
}

private static WeakReference CreateConcreateObject()
{
var obj = new Domain.MyClass().ToPython();
Assert.AreEqual(obj.Refcount, 1);
WeakReference numRef = new WeakReference(obj, false);
return numRef;
}

#endregion Tempary tests

/// <summary>
/// This is a magic incantation required to run code in an application
/// domain other than the current one.
Expand Down
16 changes: 12 additions & 4 deletionssrc/embed_tests/pyinitialize.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,8 +40,10 @@ public static void LoadSpecificArgs()
{
using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv")))
{
Assert.AreEqual(args[0], argv[0].ToString());
Assert.AreEqual(args[1], argv[1].ToString());
using var v0 = argv[0];
using var v1 = argv[1];
Assert.AreEqual(args[0], v0.ToString());
Assert.AreEqual(args[1], v1.ToString());
}
}
}
Expand All@@ -54,12 +56,16 @@ public void ImportClassShutdownRefcount()

PyObject ns = Py.Import(typeof(ImportClassShutdownRefcountClass).Namespace);
PyObject cls = ns.GetAttr(nameof(ImportClassShutdownRefcountClass));
BorrowedReference clsRef = cls.Reference;
#pragma warning disable CS0618 // Type or member is obsolete
cls.Leak();
#pragma warning restore CS0618 // Type or member is obsolete
ns.Dispose();

Assert.Less(cls.Refcount, 256);
Assert.Less(Runtime.Runtime.Refcount(clsRef), 256);

PythonEngine.Shutdown();
Assert.Greater(cls.Refcount, 0);
Assert.Greater(Runtime.Runtime.Refcount(clsRef), 0);
}

/// <summary>
Expand DownExpand Up@@ -176,6 +182,7 @@ public static void TestRunExitFuncs()
{
Assert.Fail(msg);
}
PythonEngine.InteropConfiguration = InteropConfiguration.MakeDefault();
return;
}
bool called = false;
Expand All@@ -187,6 +194,7 @@ public static void TestRunExitFuncs()
atexit.Dispose();
Runtime.Runtime.Shutdown();
Assert.True(called);
PythonEngine.InteropConfiguration = InteropConfiguration.MakeDefault();
}
}

Expand Down
11 changes: 10 additions & 1 deletionsrc/runtime/Codecs/DecoderGroup.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ namespace Python.Runtime.Codecs
/// <summary>
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
/// </summary>
public sealed class DecoderGroup: IPyObjectDecoder, IEnumerable<IPyObjectDecoder>
public sealed class DecoderGroup: IPyObjectDecoder, IEnumerable<IPyObjectDecoder>, IDisposable
{
readonly List<IPyObjectDecoder> decoders = new List<IPyObjectDecoder>();

Expand DownExpand Up@@ -46,6 +46,15 @@ public bool TryDecode<T>(PyObject pyObj, out T value)
/// <inheritdoc />
public IEnumerator<IPyObjectDecoder> GetEnumerator() => this.decoders.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => this.decoders.GetEnumerator();

public void Dispose()
{
foreach (var decoder in this.decoders.OfType<IDisposable>())
{
decoder.Dispose();
}
this.decoders.Clear();
}
}

public static class DecoderGroupExtensions
Expand Down
11 changes: 10 additions & 1 deletionsrc/runtime/Codecs/EncoderGroup.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ namespace Python.Runtime.Codecs
/// <summary>
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
/// </summary>
public sealed class EncoderGroup: IPyObjectEncoder, IEnumerable<IPyObjectEncoder>
public sealed class EncoderGroup: IPyObjectEncoder, IEnumerable<IPyObjectEncoder>, IDisposable
{
readonly List<IPyObjectEncoder> encoders = new List<IPyObjectEncoder>();

Expand DownExpand Up@@ -47,6 +47,15 @@ public PyObject TryEncode(object value)
/// <inheritdoc />
public IEnumerator<IPyObjectEncoder> GetEnumerator() => this.encoders.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => this.encoders.GetEnumerator();

public void Dispose()
{
foreach (var encoder in this.encoders.OfType<IDisposable>())
{
encoder.Dispose();
}
this.encoders.Clear();
}
}

public static class EncoderGroupExtensions
Expand Down
12 changes: 11 additions & 1 deletionsrc/runtime/InteropConfiguration.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,10 +2,11 @@ namespace Python.Runtime
{
using System;
using System.Collections.Generic;
using System.Linq;

using Python.Runtime.Mixins;

public sealed class InteropConfiguration
public sealed class InteropConfiguration: IDisposable
{
internal readonly PythonBaseTypeProviderGroup pythonBaseTypeProviders
= new PythonBaseTypeProviderGroup();
Expand All@@ -24,5 +25,14 @@ public static InteropConfiguration MakeDefault()
},
};
}

public void Dispose()
{
foreach (var provider in PythonBaseTypeProviders.OfType<IDisposable>())
{
provider.Dispose();
}
PythonBaseTypeProviders.Clear();
}
}
}
10 changes: 9 additions & 1 deletionsrc/runtime/Mixins/CollectionMixinsProvider.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@

namespace Python.Runtime.Mixins
{
class CollectionMixinsProvider : IPythonBaseTypeProvider
class CollectionMixinsProvider : IPythonBaseTypeProvider, IDisposable
{
readonly Lazy<PyObject> mixinsModule;
public CollectionMixinsProvider(Lazy<PyObject> mixinsModule)
Expand DownExpand Up@@ -86,5 +86,13 @@ static Type[] NewInterfaces(Type type)

static Type GetDefinition(Type type)
=> type.IsGenericType ? type.GetGenericTypeDefinition() : type;

public void Dispose()
{
if (this.mixinsModule.IsValueCreated)
{
this.mixinsModule.Value.Dispose();
}
}
}
}
4 changes: 2 additions & 2 deletionssrc/runtime/converterextensions.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -166,8 +166,8 @@ internal static void Reset()
{
clrToPython.Clear();
pythonToClr.Clear();
encoders.Clear();
decoders.Clear();
encoders.Dispose();
decoders.Dispose();
}
}

Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp