Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
163 changes: 160 additions & 3 deletions src/embed_tests/QCTest.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Python.Runtime;

namespace Python.EmbeddingTest
{
class QCTests
{
private static dynamic pythonSuperInitInt;
private static dynamic pythonSuperInitDefault;
private static dynamic pythonSuperInitNone;
private static dynamic pythonSuperInitNotCallingBase;

private static dynamic withArgs_PythonSuperInitNotCallingBase;
private static dynamic withArgs_PythonSuperInitDefault;
private static dynamic withArgs_PythonSuperInitInt;

private static dynamic pureCSharpConstruction;

private static dynamic containsTest;
private static dynamic module;
private static string testModule = @"
from clr import AddReference
AddReference(""System"")
AddReference(""Python.EmbeddingTest"")
from Python.EmbeddingTest import Algo, Insight
from Python.EmbeddingTest import *
class PythonModule(Algo):
def TestA(self):
try:
Expand All @@ -28,6 +37,37 @@ def ContainsTest(key, collection):
if key in collection.Keys:
return True
return False

class WithArgs_PythonSuperInitNotCallingBase(SuperInit):
def __init__(self, jose):
return

class WithArgs_PythonSuperInitDefault(SuperInit):
def __init__(self, jose):
super().__init__()

class WithArgs_PythonSuperInitInt(SuperInit):
def __init__(self, jose):
super().__init__(jose)

class PythonSuperInitNotCallingBase(SuperInit):
def __init__(self):
return

class PythonSuperInitDefault(SuperInit):
def __init__(self):
super().__init__()

class PythonSuperInitInt(SuperInit):
def __init__(self):
super().__init__(1)

class PythonSuperInitNone(SuperInit):
def jose(self):
return 1

def PureCSharpConstruction():
return SuperInit(1)
";

[OneTimeSetUp]
Expand All @@ -37,6 +77,17 @@ public void Setup()
var pyModule = PyModule.FromString("module", testModule);
containsTest = pyModule.GetAttr("ContainsTest");
module = pyModule.GetAttr("PythonModule").Invoke();

pythonSuperInitInt = pyModule.GetAttr("PythonSuperInitInt");
pythonSuperInitDefault = pyModule.GetAttr("PythonSuperInitDefault");
pythonSuperInitNone = pyModule.GetAttr("PythonSuperInitNone");
pythonSuperInitNotCallingBase = pyModule.GetAttr("PythonSuperInitNotCallingBase");

withArgs_PythonSuperInitNotCallingBase = pyModule.GetAttr("WithArgs_PythonSuperInitNotCallingBase");
withArgs_PythonSuperInitDefault = pyModule.GetAttr("WithArgs_PythonSuperInitDefault");
withArgs_PythonSuperInitInt = pyModule.GetAttr("WithArgs_PythonSuperInitInt");

pureCSharpConstruction = pyModule.GetAttr("PureCSharpConstruction");
}

[OneTimeTearDown]
Expand All @@ -62,6 +113,98 @@ public void ContainsTest(string key, bool expected)
var dic = new Dictionary<string, object> { { "SPY", new object() } };
Assert.AreEqual(expected, (bool)containsTest(key, dic));
}

[Test]
public void PureCSharpConstruction()
{
using (Py.GIL())
{
var instance = pureCSharpConstruction();
Assert.AreEqual(1, (int)instance.CalledInt);
Assert.AreEqual(1, (int)instance.CalledDefault);
}
}

[Test]
public void WithArgs_NoBaseConstructorCall()
{
using (Py.GIL())
{
var instance = withArgs_PythonSuperInitNotCallingBase(1);
Assert.AreEqual(0, (int)instance.CalledInt);
// we call the constructor always
Assert.AreEqual(1, (int)instance.CalledDefault);
}
}

[Test]
public void WithArgs_IntConstructor()
{
using (Py.GIL())
{
var instance = withArgs_PythonSuperInitInt(1);
Assert.AreEqual(1, (int)instance.CalledInt);
Assert.AreEqual(1, (int)instance.CalledDefault);
}
}

[Test]
public void WithArgs_DefaultConstructor()
{
using (Py.GIL())
{
var instance = withArgs_PythonSuperInitDefault(1);
Assert.AreEqual(0, (int)instance.CalledInt);
Assert.AreEqual(2, (int)instance.CalledDefault);
}
}

[Test]
public void NoArgs_NoBaseConstructorCall()
{
using (Py.GIL())
{
var instance = pythonSuperInitNotCallingBase();
Assert.AreEqual(0, (int)instance.CalledInt);
// this is true because we call the default constructor always
Assert.AreEqual(1, (int)instance.CalledDefault);
}
}

[Test]
public void NoArgs_IntConstructor()
{
using (Py.GIL())
{
var instance = pythonSuperInitInt();
Assert.AreEqual(1, (int)instance.CalledInt);
// this is true because we call the default constructor always
Assert.AreEqual(1, (int)instance.CalledDefault);
}
}

[Test]
public void NoArgs_DefaultConstructor()
{
using (Py.GIL())
{
var instance = pythonSuperInitNone();
Assert.AreEqual(0, (int)instance.CalledInt);
Assert.AreEqual(2, (int)instance.CalledDefault);
}
}

[Test]
public void NoArgs_NoConstructor()
{
using (Py.GIL())
{
var instance = pythonSuperInitDefault.Invoke();

Assert.AreEqual(0, (int)instance.CalledInt);
Assert.AreEqual(2, (int)instance.CalledDefault);
}
}
}

public class Algo
Expand All @@ -83,6 +226,20 @@ public void EmitInsights(params Insight[] insights)

}

public class SuperInit
{
public int CalledInt { get; private set; }
public int CalledDefault { get; private set; }
public SuperInit(int a)
{
CalledInt++;
}
public SuperInit()
{
CalledDefault++;
}
}

public class Insight
{
public string info;
Expand Down
4 changes: 2 additions & 2 deletions src/perf_tests/Python.PerformanceTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.*" />
<PackageReference Include="quantconnect.pythonnet" Version="2.0.14" GeneratePathProperty="true">
<PackageReference Include="quantconnect.pythonnet" Version="2.0.15" GeneratePathProperty="true">
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
Expand All @@ -25,7 +25,7 @@
</Target>

<Target Name="CopyBaseline" AfterTargets="Build">
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.14\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.15\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
</Target>

<Target Name="CopyNewBuild" AfterTargets="Build">
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
[assembly: InternalsVisibleTo("Python.EmbeddingTest, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
[assembly: InternalsVisibleTo("Python.Test, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]

[assembly: AssemblyVersion("2.0.14")]
[assembly: AssemblyFileVersion("2.0.14")]
[assembly: AssemblyVersion("2.0.15")]
[assembly: AssemblyFileVersion("2.0.15")]
2 changes: 1 addition & 1 deletion src/runtime/Python.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<RootNamespace>Python.Runtime</RootNamespace>
<AssemblyName>Python.Runtime</AssemblyName>
<PackageId>QuantConnect.pythonnet</PackageId>
<Version>2.0.14</Version>
<Version>2.0.15</Version>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/pythonnet/pythonnet</RepositoryUrl>
Expand Down
29 changes: 26 additions & 3 deletions src/runtime/Types/ClassObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ namespace Python.Runtime
[Serializable]
internal class ClassObject : ClassBase
{
private ConstructorInfo[] constructors;
internal readonly int NumCtors = 0;

internal ClassObject(Type tp) : base(tp)
{
var _ctors = type.Value.GetConstructors();
NumCtors = _ctors.Length;
constructors = type.Value.GetConstructors();
NumCtors = constructors.Length;
}


Expand Down Expand Up @@ -110,8 +111,30 @@ static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, Bo
}

object obj = FormatterServices.GetUninitializedObject(type);
var pythonObj = self.NewObjectToPython(obj, tp);

return self.NewObjectToPython(obj, tp);
try
{
var binder = new MethodBinder();
for (int i = 0; i < self.constructors.Length; i++)
{
binder.AddMethod(self.constructors[i]);
}

using var tuple = Runtime.PyTuple_New(0);
var binding = binder.Bind(pythonObj.Borrow(), tuple.Borrow(), null);
if (binding != null)
{
binding.info.Invoke(obj, BindingFlags.Default, null, binding.args, null);
}
}
catch (Exception)
{
Exceptions.Clear();
// we try our best to call the base constructor but don't let it stop us
}

return pythonObj;
}

protected virtual void SetTypeNewSlot(BorrowedReference pyType, SlotsHolder slotsHolder)
Expand Down