Hello,
This PR<https://github.com/pythonnet/pythonnet/pull/1240> changed behavior of pythonnet to use stricter typing when a method returns an interface. I'd like a way to opt-out of this behavior, and I'll share a representative use-case below. The tl;dr is that python is a dynamic language and I expect the C# objects which pythonnet wraps to behave more like "dynamic" and less like the static types on the interface.
**** C# code ****
namespace Example1
{
public enum ShapeType
…
[View More] {
Square,
Circle
}
public interface IShape
{
void Draw();
double Area { get; }
ShapeType Type { get; }
}
public class Square : IShape
{
public double Length { get; }
public Square(double length)
{
Length = length;
}
public void Draw() {}
public double Area { get { return Length * Length; } }
public ShapeType Type { get { return ShapeType.Square; } }
}
public class Circle : IShape
{
public double Radius { get; }
public Circle(double radius)
{
Radius = radius;
}
public void Draw() {}
public double Area { get { return Math.PI * Radius * Radius; } }
public ShapeType Type { get { return ShapeType.Circle; } }
}
public class ShapeDataModel
{
private Dictionary<int, IShape> _shapes = new Dictionary<int, IShape>();
private int _nextId = 1;
public int AddShape(IShape shape)
{
int id = _nextId;
_shapes[id] = shape;
_nextId++;
return id;
}
public IShape GetShape(int id)
{
return _shapes[id];
}
}
}
**** Python code ****
>>> import clr
>>> clr.AddReference("Example1")
>>> import Example1
>>> sq1 = Example1.Square(2.)
>>> ci1 = Example1.Circle(1.3)
>>> sq2 = Example1.Square(2.5)
>>> m = Example1.ShapeDataModel()
>>> m.AddShape(sq1)
1
>>> m.AddShape(sq2)
2
>>> m.AddShape(ci1)
3
>>> m.GetShape(2)
<Example1.IShape object at 0x000002A3448A09A0>
>>> m.GetShape(2).Area
6.25
>>> m.GetShape(2).Length
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'IShape' object has no attribute 'Length'
**** summary ****
This factory and/or datamodel pattern is very common in my codebase and probably also lots of object oriented systems. The mentioned PR breaks this common design pattern in C# objects wrapped by pythonnet, and I would like a way to opt-out of it. Maybe an attribute on the method which returns an interface can be used, or maybe something global to switch this behavior. I think perhaps the original bug might also have been fixed in a different way.
Thanks!
Mohamed
[View Less]
Hello, guys here is a prototype code:
exAsseblyRef = clr.AddReference("C:\ExamRecordHelper")
from ExamRecordHelper import *
loaderObj = ExamRecordLoader( 'MyBinaryFile.bin') <<<<<< Exception here.
On the 3d line the C# constructor ExamRecordLoader(String) is called - it can't create the object.
The actual exception is: "Column requires a valid DataType."
However, the same binary file used with native C# code: ExamRecordLoader( 'MyBinaryFile.bin') works with no errors.
…
[View More]Obviously something is happening when the binary file is being used by the C# class...
Any suggestions?
Thanks,
Alex.
[View Less]
(I think I forgot to send out the previous meeting notes - you can find them in the Google doc linked at the bottom of this message)
Attendees: Benedikt, Mark, Victor, Benoit, Felix, Amos
Agenda
Review last week's action items:
Benedikt will fix 32-bit issues
Benedikt to add test that loads unicode function names
Felix will submit PR for #1333 (function delegates)
Felix will submit PR that rewrites import hook to use pure Python (see #1096 & #727)
Notes:
32-bit issues
nothing done yet, …
[View More]Benedikt will look into this
test that loads unicode function names
merged! PR #1329
problem was that we need to make sure we always use our own UTF-8 marshaller
we can't use the .NET one because it doesn't exist in all .NET frameworks
PR fixes the issue where Benedikt saw it, but there are possibly other places where the same issue exists
follow-up issue is #1354
let's link all encoding problems to this issue
in Python 3 it's all UTF-8
this particular issue (unicode function names) is fixed
function delegates
merged! PR #1333
rewrite of import hook to use pure Python (see #1096 & #727)
in progress (Felix)
rewrite avoids entering C# unless we absolutely need to, because there's no way to prevent C# from "owning" a thread that calls C#, and once C# owns it domain reload hangs waiting for the thread to exit
fixes a common pattern "try import PySide; except: import PySide2" - previous implementation hits C# on the first import call, even if PySide doesn't exist
internal compiler error (https://github.com/dotnet/roslyn/issues/49760)
still present in latest .NET 5.0.2
might still be a Roslyn point release?
doesn't help because Roslyn likely frozen until .NET 6
Victor will find out when they plan on releasing a fix
required for replacing PInvoke delegates for reference types with using unmanaged function pointers (supposed to work in new C#, but triggers an internal compiler error)
blocking our ability to do a multi-stage startup and dynamically bind to the right Python dll/dso/dylib anywhere but Mono (which supports __Internal as the DllImport string)
helpful for embedding .NET in Python since want to use the statically linked symbols in the python executable - using a dynamic library, even if present, leads to weird problems
we'll find out if a fix is forthcoming and if not, use a workaround
Action items:
Benedikt will fix 32-bit issues
Felix will complete rewrite of import hook to avoid calling C# unless necessary
Victor will find out if there will be a Roslyn release fixing the internal compiler error
The meeting notes google doc is here <https://docs.google.com/document/d/1rJVU84B_dgx58-_EopjRtOJVFAI2WfHJYV0n7uE…>. Feel free to correct or add additional information.
The next meeting will be held on Thursday, January 28 at 12pm EST (click for your time zone) <https://www.google.com/search?q=12:00+pm+EST>.
Mark Visser
Senior Dev Manager, M&E
Unity Technologies - www.unity3d.com <http://www.unity3d.com/>
[View Less]