Skip to content

Commit

Permalink
Merge pull request #93 from jhonabreul/bug-snake-cased-arguments-cons…
Browse files Browse the repository at this point in the history
…tructors

Constructors with arguments snake-cased version
  • Loading branch information
jhonabreul authored May 24, 2024
2 parents 8fb227a + c799b7e commit a685c20
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 15 deletions.
103 changes: 103 additions & 0 deletions src/embed_tests/TestMethodBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,34 @@ public string ImplicitConversionSameArgumentCount2(string symbol, decimal quanti
{
return "ImplicitConversionSameArgumentCount2 2";
}

// ----

public string VariableArgumentsMethod(params CSharpModel[] paramsParams)
{
return "VariableArgumentsMethod(CSharpModel[])";
}

public string VariableArgumentsMethod(params PyObject[] paramsParams)
{
return "VariableArgumentsMethod(PyObject[])";
}

public string ConstructorMessage { get; set; }

public OverloadsTestClass(params CSharpModel[] paramsParams)
{
ConstructorMessage = "OverloadsTestClass(CSharpModel[])";
}

public OverloadsTestClass(params PyObject[] paramsParams)
{
ConstructorMessage = "OverloadsTestClass(PyObject[])";
}

public OverloadsTestClass()
{
}
}

[TestCase("Method1('abc', namedArg1=10, namedArg2=321)", "Method1 Overload 1")]
Expand Down Expand Up @@ -898,6 +926,75 @@ def call_method(instance):
Assert.IsFalse(Exceptions.ErrorOccurred());
}

[Test]
public void BindsConstructorToSnakeCasedArgumentsVersion([Values] bool useCamelCase, [Values] bool passOptionalArgument)
{
using var _ = Py.GIL();

var argument1Name = useCamelCase ? "someArgument" : "some_argument";
var argument2Name = useCamelCase ? "anotherArgument" : "another_argument";
var argument2Code = passOptionalArgument ? $", {argument2Name}=\"another argument value\"" : "";

var module = PyModule.FromString("BindsConstructorToSnakeCasedArgumentsVersion", @$"
from clr import AddReference
AddReference(""System"")
from Python.EmbeddingTest import *
def create_instance():
return TestMethodBinder.CSharpModel({argument1Name}=1{argument2Code})
");
var exception = Assert.Throws<ClrBubbledException>(() => module.GetAttr("create_instance").Invoke());
var sourceException = exception.InnerException;
Assert.IsInstanceOf<NotImplementedException>(sourceException);

var expectedMessage = passOptionalArgument
? "Constructor with arguments: someArgument=1. anotherArgument=\"another argument value\""
: "Constructor with arguments: someArgument=1. anotherArgument=\"another argument default value\"";
Assert.AreEqual(expectedMessage, sourceException.Message);
}

[Test]
public void PyObjectArrayHasPrecedenceOverOtherTypeArrays()
{
using var _ = Py.GIL();

var module = PyModule.FromString("PyObjectArrayHasPrecedenceOverOtherTypeArrays", @$"
from clr import AddReference
AddReference(""System"")
from Python.EmbeddingTest import *
class PythonModel(TestMethodBinder.CSharpModel):
pass
def call_method():
return TestMethodBinder.OverloadsTestClass().VariableArgumentsMethod(PythonModel(), PythonModel())
");

var result = module.GetAttr("call_method").Invoke().As<string>();
Assert.AreEqual("VariableArgumentsMethod(PyObject[])", result);
}

[Test]
public void PyObjectArrayHasPrecedenceOverOtherTypeArraysInConstructors()
{
using var _ = Py.GIL();

var module = PyModule.FromString("PyObjectArrayHasPrecedenceOverOtherTypeArrays", @$"
from clr import AddReference
AddReference(""System"")
from Python.EmbeddingTest import *
class PythonModel(TestMethodBinder.CSharpModel):
pass
def get_instance():
return TestMethodBinder.OverloadsTestClass(PythonModel(), PythonModel())
");

var instance = module.GetAttr("get_instance").Invoke();
Assert.AreEqual("OverloadsTestClass(PyObject[])", instance.GetAttr("ConstructorMessage").As<string>());
}


// Used to test that we match this function with Py DateTime & Date Objects
public static int GetMonth(DateTime test)
Expand All @@ -918,6 +1015,12 @@ public CSharpModel()
new TestImplicitConversion()
};
}

public CSharpModel(int someArgument, string anotherArgument = "another argument default value")
{
throw new NotImplementedException($"Constructor with arguments: someArgument={someArgument}. anotherArgument=\"{anotherArgument}\"");
}

public void TestList(List<TestImplicitConversion> conversions)
{
if (!conversions.Any())
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.37" GeneratePathProperty="true">
<PackageReference Include="quantconnect.pythonnet" Version="2.0.38" 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.37\lib\net6.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.38\lib\net6.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
</Target>

<Target Name="CopyNewBuild" AfterTargets="Build">
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/ClassManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,11 @@ void AddMember(string name, string snakeCasedName, bool isStaticReadonlyCallable
methodList = methods[name] = new ();
}
methodList.Add(ctor, true);
// Same constructor, but with snake-cased arguments
if (ctor.GetParameters().Any(pi => pi.Name?.ToSnakeCase() != pi.Name))
{
methodList.Add(ctor, false);
}
continue;

case MemberTypes.Property:
Expand Down
20 changes: 10 additions & 10 deletions src/runtime/MethodBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,16 @@ internal static int ArgPrecedence(Type t, MethodInformation mi)
return -1;
}

if (t.IsArray)
{
Type e = t.GetElementType();
if (e == objectType)
{
return 2500;
}
return 100 + ArgPrecedence(e, mi);
}

TypeCode tc = Type.GetTypeCode(t);
// TODO: Clean up
switch (tc)
Expand Down Expand Up @@ -406,16 +416,6 @@ internal static int ArgPrecedence(Type t, MethodInformation mi)
return 40;
}

if (t.IsArray)
{
Type e = t.GetElementType();
if (e == objectType)
{
return 2500;
}
return 100 + ArgPrecedence(e, mi);
}

return 2000;
}

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.37")]
[assembly: AssemblyFileVersion("2.0.37")]
[assembly: AssemblyVersion("2.0.38")]
[assembly: AssemblyFileVersion("2.0.38")]
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.37</Version>
<Version>2.0.38</Version>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/pythonnet/pythonnet</RepositoryUrl>
Expand Down

0 comments on commit a685c20

Please sign in to comment.