[Python.NET] Wrap in interface (#1240)
Mohamed Koubaa <[email protected]> Tue, 3 Nov 2020 02:15:49 +0000
| Newsgroups | gmane.comp.python.dotnet |
|---|---|
| Message-ID | <SN6PR01MB5007657AC4CE6BC4ABBDC78599110@SN6PR01MB5007.prod.exchangelabs.com> |
--===============5251633457715666591==
Content-Language: en-US
Content-Type: multipart/alternative;
boundary="_000_SN6PR01MB5007657AC4CE6BC4ABBDC78599110SN6PR01MB5007prod_"
--_000_SN6PR01MB5007657AC4CE6BC4ABBDC78599110SN6PR01MB5007prod_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
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 u=
se-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 les=
s like the static types on the interface.
**** C# code ****
namespace Example1
{
public enum ShapeType
{
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 =3D 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 =3D 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 =3D new Dictionary<int, ISh=
ape>();
private int _nextId =3D 1;
public int AddShape(IShape shape)
{
int id =3D _nextId;
_shapes[id] =3D shape;
_nextId++;
return id;
}
public IShape GetShape(int id)
{
return _shapes[id];
}
}
}
**** Python code ****
>>> import clr
>>> clr.AddReference("Example1")
>>> import Example1
>>> sq1 =3D Example1.Square(2.)
>>> ci1 =3D Example1.Circle(1.3)
>>> sq2 =3D Example1.Square(2.5)
>>> m =3D 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 pro=
bably also lots of object oriented systems. The mentioned PR breaks this c=
ommon 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 i=
nterface 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 w=
ay.
Thanks!
Mohamed
--_000_SN6PR01MB5007657AC4CE6BC4ABBDC78599110SN6PR01MB5007prod_
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style type=3D"text/css" style=3D"display:none;"> P {margin-top:0;margin-bo=
ttom:0;} </style>
</head>
<body dir=3D"ltr">
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
Hello,</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
This <a href=3D"https://github.com/pythonnet/pythonnet/pull/1240" title=3D"=
https://github.com/pythonnet/pythonnet/pull/1240">
PR</a> changed behavior of pythonnet to use stricter typing when a met=
hod 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 py=
thon 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.</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
**** C# code ****</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"font-family: "Courier New", monospace;">namespace =
Example1</span>
<div><span style=3D"font-family: "Courier New", monospace;">{</sp=
an></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public enum ShapeType</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; Square,</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; Circle</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public interface IShape</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; void Draw();</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; double Area { get; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; ShapeType Type { get; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public class Square : IShape</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public double Length { get; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public Square(double length)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; Length =3D length;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public void Draw() {}</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public double Area { get { return Length * Length; }=
}</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public ShapeType Type { get { return ShapeType.Squar=
e; } }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public class Circle : IShape</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public double Radius { get; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public Circle(double radius)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; Radius =3D radius;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"><br>
</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public void Draw() {}</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public double Area { get { return Math.PI * Radius *=
Radius; } }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public ShapeType Type { get { return ShapeType.Circl=
e; } }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public class ShapeDataModel</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; private Dictionary<int, IShape> _shapes =3D ne=
w Dictionary<int, IShape>();</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; private int _nextId =3D 1;</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public int AddShape(IShape shape)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; int id =3D _nextId;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; _shapes[id] =3D shape;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; _nextId++;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; return id;</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><br>
</div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; public IShape GetShape(int id)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; {</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; return _shapes[id];</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"> =
; }</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">}</sp=
an></div>
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(24, 26, 27); display: inline !importan=
t; --darkreader-inline-bgcolor:#131516;" data-darkreader-inline-bgcolor=3D"=
">**** Python code ****</span><br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111; font-family: "Courier New", monospace;" data-darkread=
er-inline-bgcolor=3D"">>>> import clr</span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111; font-family: "Courier New", monospace;" data-darkread=
er-inline-bgcolor=3D"">>>> clr.AddReference("Example1")<=
/span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111; font-family: "Courier New", monospace;" data-darkread=
er-inline-bgcolor=3D"">>>> import Example1</span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D"">
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> sq1 =3D Example1.Square(2.)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> ci1 =3D Example1.Circle(1.3)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> sq2 =3D Example1.Square(2.5)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m =3D Example1.ShapeDataModel()</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.AddShape(sq1)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">1</sp=
an></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.AddShape(sq2)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">2</sp=
an></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.AddShape(ci1)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">3</sp=
an></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.GetShape(2)</span></div>
<div><span style=3D"font-family: "Courier New", monospace;"><E=
xample1.IShape object at 0x000002A3448A09A0></span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.GetShape(2).Area</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">6.25<=
/span></div>
<div><span style=3D"font-family: "Courier New", monospace;">>&=
gt;> m.GetShape(2).Length</span></div>
<div><span style=3D"font-family: "Courier New", monospace;">Trace=
back (most recent call last):</span></div>
<div><span style=3D"font-family: "Courier New", monospace; color:=
rgb(237, 92, 87); --darkreader-inline-color:#ed605b;" data-darkreader-inli=
ne-color=3D""> File "<stdin>", line 1, in <module&=
gt;</span></div>
<div><span style=3D"font-family: "Courier New", monospace; color:=
rgb(237, 92, 87); --darkreader-inline-color:#ed605b;" data-darkreader-inli=
ne-color=3D"">AttributeError: 'IShape' object has no attribute 'Length'</sp=
an></div>
</span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D""><br>
</span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D"">**** summary ****</span></=
div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D"">This factory and/or datamo=
del 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 switc=
h this behavior. I think perhaps the
original bug might also have been fixed in a different way. </span></=
div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D""><br>
</span></div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0); --darkreader-inline-color:#e8e6e3;" data-darkr=
eader-inline-color=3D"">
<span style=3D"background-color: rgb(19, 21, 22); --darkreader-inline-bgcol=
or:#0f1111;" data-darkreader-inline-bgcolor=3D"">Thanks!<br>
Mohamed</span></div>
</body>
</html>
--_000_SN6PR01MB5007657AC4CE6BC4ABBDC78599110SN6PR01MB5007prod_--
--===============5251633457715666591==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
PythonNet mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/pythonnet.python.org/
Member address: [email protected]
--===============5251633457715666591==--