[Python.NET] Re: Wrap in interface (#1240)
Mohamed Koubaa <[email protected]> Mon, 8 Feb 2021 19:18:42 +0000
| Newsgroups | gmane.comp.python.dotnet |
|---|---|
| Message-ID | <SN6PR01MB497662EB218106862672133C998F9@SN6PR01MB4976.prod.exchangelabs.com> |
--===============5566050003740487892== Content-Language: en-US Content-Type: multipart/related; boundary="_004_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_"; type="multipart/alternative" --_004_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_ Content-Type: multipart/alternative; boundary="_000_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_" --_000_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_ Content-Type: text/plain; charset="Windows-1252" Content-Transfer-Encoding: quoted-printable Victor, Our API is C# and some of our users actually directly use C# to access them= and don't use python. We don't intend to change the API. Of course, user= s may have to change their scripts to be python3 compatible when they opt i= nto using our API from CPython, but we expect most anything unrelated to 2t= o3 to continue to work. My expectation is that if a method/property returns an object using the int= erface but the concrete class which it returns implements a given method, t= hen hasattr should find it. I think options 4&5 do what I need (but isn't = option 4 what we had prior to #1240?) Thanks, Mohamed ________________________________ From: Victor =93LOST=94 Milovanov <[email protected]> Sent: Monday, February 8, 2021 12:56 PM To: A list for users and developers of Python.NET <[email protected]> Subject: [Python.NET] Re: Wrap in interface (#1240) [External Sender] A dump of thoughts on the matter: 1. IronPython is Python 2 only, Python.NET 3.0+ is Python 3 only. Why no= t use 2.5.x until you are comfortable to change API? 2. Flag is possible, but I would not recommend that approach, because it= makes combining multiple libraries that use different global flags problem= atic. 3. Perhaps we could allow codecs to handle instances of wrapped interfac= es (actually, isn=92t that currently allowed?) 4. IronPython apparently allows explicit interface implementations to be= called (instead of returning interface-wrapped instances), if there=92s no= conflict with regular methods. Perhaps we should consider this as an optio= n. 5. Alternatively, we can keep wrapped instances, but allow to resolve pu= blic members too if the method is not found in the interface. I like this o= ption better than 4, because actual type of an element in ISomething[] won= =92t change behavior of invoking interface member. It might still affect `h= asattr`, but this is somewhat expected. Regards, Victor From: Mohamed Koubaa<mailto:[email protected]> Sent: Monday, February 8, 2021 8:34 AM To: A list for users and developers of Python.NET<mailto:[email protected]= rg> Subject: [Python.NET] Re: Wrap in interface (#1240) Victor, Sorry for the late response. I think what I would need is some kind of fla= g in the python runtime to choose the old behavior (without having to have = my own branch). Of course there is a workaround but we've invested a lot o= f time in designing the API for both CPython & IronPython and it would be i= deal if they did not differ in this way. This could be a global flag on the runtime and/or an attribute on a class/i= nterface to decide on a granular level whether the specific class/interface= will use interface method binding or instance method binding. Thoughts? Thanks! Mohamed From: Victor =93LOST=94 Milovanov <[email protected]> Sent: Monday, November 2, 2020 8:35 PM To: A list for users and developers of Python.NET <[email protected]> Subject: [Python.NET] Re: Wrap in interface (#1240) [External Sender] The original bug report described a similar problem, except the behavior wi= thout defaulting to stricter interface types is very unintuitive. Imagine y= ou have a well documented library, that exposes property Prop of type IInte= rface. When specific class implements some Method in IInterface explicitly= (which arguably is a very minor implementation detail), and you call Prop.= Method() in Python, it can fail with AttributeError despite the documentati= on claiming this method exists on the interface. This is very confusing. IM= HO, more confusing, than inability to get Length of an element of IShape[]. We could try to improve the situation for Python folks by allowing interfac= e instance wrappers to fall back to the original class instance in case the= attribute is not found in the interface itself. I think this might still b= e problematic, as it would make the behavior of hasattr and other similar f= unctions a bit surprising. Regardless, there=92s a workaround for the scenario you described which is = just doing m.GetShape(1).__raw_implementation__.Length or m.GetShape(1).__implementation__.Length depending if you need an encoded in= stance. Regards, Victor Milovanov From: Mohamed Koubaa<mailto:[email protected]> Sent: Monday, November 2, 2020 6:15 PM To: [email protected]<mailto:[email protected]> Subject: [Python.NET] Wrap in interface (#1240) Hello, This PR<https://nam10.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2= Fgithub.com%2Fpythonnet%2Fpythonnet%2Fpull%2F1240&data=3D04%7C01%7Cmohamed.= koubaa%40ansys.com%7C4b457216f75446301a4508d8cc634c3b%7C34c6ce6715b84eff80e= 952da8be89706%7C0%7C0%7C637484074196952423%7CUnknown%7CTWFpbGZsb3d8eyJWIjoi= MC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=3Dc= AFUSSzeNl11sru%2B1ZNS8EjdoqhST%2FAGvY73dUQgV9U%3D&reserved=3D0> changed beh= avior of pythonnet to use stricter typing when a method returns an interfac= e. I'd like a way to opt-out of this behavior, and I'll share a representa= tive 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" a= nd less 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_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_ Content-Type: text/html; charset="Windows-1252" Content-Transfer-Encoding: quoted-printable <html> <head> <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DWindows-1= 252"> <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);"> Victor,</div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> <br> </div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> <span style=3D"background-color:rgb(255, 255, 255);display:inline !importan= t">Our API is C# and some of our users actually directly use C# to access t= hem and don't use python.<span> We don't intend to change the API</sp= an></span>. Of course, users may have to change their scripts to be python3 compatible when they opt into using = our API from CPython, but we expect most anything unrelated to 2to3 to cont= inue to work.</div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> <br> </div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> My expectation is that if a method/property returns an object using the int= erface but the concrete class which it returns implements a given method, t= hen hasattr should find it. I think options 4&5 do what I need (b= ut isn't option 4 what we had prior to #1240?)</div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> <br> </div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> Thanks,</div> <div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size= : 12pt; color: rgb(0, 0, 0);"> Mohamed</div> <div id=3D"appendonsend"></div> <hr style=3D"display:inline-block;width:98%" tabindex=3D"-1"> <div id=3D"divRplyFwdMsg" dir=3D"ltr"><font face=3D"Calibri, sans-serif" st= yle=3D"font-size:11pt" color=3D"#000000"><b>From:</b> Victor =93LOST=94 Mil= ovanov <[email protected]><br> <b>Sent:</b> Monday, February 8, 2021 12:56 PM<br> <b>To:</b> A list for users and developers of Python.NET <pythonnet@pyth= on.org><br> <b>Subject:</b> [Python.NET] Re: Wrap in interface (#1240)</font> <div> </div> </div> <style> <!-- @font-face {font-family:"Cambria Math"} @font-face {font-family:Calibri} p.x_MsoNormal, li.x_MsoNormal, div.x_MsoNormal {margin:0in; font-size:11.0pt; font-family:"Calibri",sans-serif} a:link, span.x_MsoHyperlink {color:blue; text-decoration:underline} p.x_MsoListParagraph, li.x_MsoListParagraph, div.x_MsoListParagraph {margin-top:0in; margin-right:0in; margin-bottom:0in; margin-left:.5in; font-size:11.0pt; font-family:"Calibri",sans-serif} p.x_xmsonormal, li.x_xmsonormal, div.x_xmsonormal {margin:0in; font-size:11.0pt; font-family:"Calibri",sans-serif} .x_MsoChpDefault {} @page WordSection1 {margin:1.0in 1.0in 1.0in 1.0in} div.x_WordSection1 {} ol {margin-bottom:0in} ul {margin-bottom:0in} --> </style> <div lang=3D"EN-US" link=3D"blue" vlink=3D"#954F72" style=3D"word-wrap:brea= k-word"> <div style=3D"border:solid #9C6500 1.0pt; padding:2.0pt 2.0pt 2.0pt 2.0pt"> <p style=3D"line-height:12.0pt; background:#FFEB9C"><b><span lang=3D"EN-US"= style=3D"font-size:10.0pt; color:red">[External Sender]</span></b></p> </div> <div> <div class=3D"x_WordSection1"> <p class=3D"x_MsoNormal">A dump of thoughts on the matter:</p> <p class=3D"x_MsoNormal"> </p> <ol start=3D"1" type=3D"1" style=3D"margin-top:0in"> <li class=3D"x_MsoListParagraph" style=3D"margin-left:0in">IronPython is Py= thon 2 only, Python.NET 3.0+ is Python 3 only. Why not use 2.5.x until you = are comfortable to change API?</li><li class=3D"x_MsoListParagraph" style= =3D"margin-left:0in">Flag is possible, but I would not recommend that appro= ach, because it makes combining multiple libraries that use different globa= l flags problematic.</li><li class=3D"x_MsoListParagraph" style=3D"margin-l= eft:0in">Perhaps we could allow codecs to handle instances of wrapped inter= faces (actually, isn=92t that currently allowed?)</li><li class=3D"x_MsoLis= tParagraph" style=3D"margin-left:0in">IronPython apparently allows explicit= interface implementations to be called (instead of returning interface-wra= pped instances), if there=92s no conflict with regular methods. Perhaps we = should consider this as an option.</li><li class=3D"x_MsoListParagraph" style=3D"margin-left:0i= n">Alternatively, we can keep wrapped instances, but allow to resolve publi= c members too if the method is not found in the interface. I like this opti= on better than 4, because actual type of an element in ISomething[] won=92t change behavior of invoking interface member. It migh= t still affect `hasattr`, but this is somewhat expected.</li></ol> <p class=3D"x_MsoNormal"> </p> <p class=3D"x_MsoNormal">Regards,</p> <p class=3D"x_MsoNormal">Victor</p> <p class=3D"x_MsoNormal"> </p> <div style=3D"border:none; border-top:solid #E1E1E1 1.0pt; padding:3.0pt 0i= n 0in 0in"> <p class=3D"x_MsoNormal" style=3D"border:none; padding:0in"><b>From: </b><a= href=3D"mailto:[email protected]">Mohamed Koubaa</a><br> <b>Sent: </b>Monday, February 8, 2021 8:34 AM<br> <b>To: </b><a href=3D"mailto:[email protected]">A list for users and dev= elopers of Python.NET</a><br> <b>Subject: </b>[Python.NET] Re: Wrap in interface (#1240)</p> </div> <p class=3D"x_MsoNormal"> </p> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Vict= or,</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs= p;</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Sorr= y for the late response. I think what I would need is some kind of fl= ag in the python runtime to choose the old behavior (without having to have= my own branch). Of course there is a workaround but we've invested a lot of time in designing the API for both CPython &am= p; IronPython and it would be ideal if they did not differ in this way.&nbs= p; </span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs= p;</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">This= could be a global flag on the runtime and/or an attribute on a class/inter= face to decide on a granular level whether the specific class/interface wil= l use interface method binding or instance method binding.</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs= p;</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Thou= ghts?</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs= p;</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Than= ks!</span></p> </div> <div> <p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Moha= med</span></p> </div> <p class=3D"x_MsoNormal"><img border=3D"0" width=3D"694" height=3D"2" id=3D= "x_Horizontal_x0020_Line_x0020_1" style=3D"width:7.2291in; height:.0208in" = data-outlook-trace=3D"F:1|T:1" src=3D"cid:image001.png-CFHuyTl/[email protected]"><= /p> <div id=3D"x_divRplyFwdMsg"> <p class=3D"x_MsoNormal"><b><span style=3D"color:black">From:</span></b><sp= an style=3D"color:black"> Victor =93LOST=94 Milovanov <lostfreeman@gmail= .com><br> <b>Sent:</b> Monday, November 2, 2020 8:35 PM<br> <b>To:</b> A list for users and developers of Python.NET <pythonnet@pyth= on.org><br> <b>Subject:</b> [Python.NET] Re: Wrap in interface (#1240)</span> </p> <div> <p class=3D"x_MsoNormal"> </p> </div> </div> <div> <div style=3D"border:solid #9C6500 1.0pt; padding:2.0pt 2.0pt 2.0pt 2.0pt"> <p style=3D"line-height:12.0pt; background:#FFEB9C"><b><span style=3D"font-= size:10.0pt; color:red">[External Sender]</span></b></p> </div> <div> <div> <p class=3D"x_xmsonormal">The original bug report described a similar probl= em, except the behavior without defaulting to stricter interface types is v= ery unintuitive. Imagine you have a well documented library, that exposes p= roperty <b>Prop</b> of type <b>IInterface</b>. When specific class implements some = <b>Method</b> in <b>IInterface</b> explicitly (which arguably is a very minor implementation= detail), and you call <b>Prop.Method()</b> in Python, it can fail with AttributeError despite the= documentation claiming this method exists on the interface. This is very c= onfusing. IMHO, more confusing, than inability to get Length of an element = of <b>IShape[]</b>.</p> <p class=3D"x_xmsonormal"> </p> <p class=3D"x_xmsonormal">We could try to improve the situation for Python = folks by allowing interface instance wrappers to fall back to the original = class instance in case the attribute is not found in the interface itself. = I think this might still be problematic, as it would make the behavior of hasattr and other similar functions a bit= surprising.</p> <p class=3D"x_xmsonormal"> </p> <p class=3D"x_xmsonormal">Regardless, there=92s a workaround for the scenar= io you described which is just doing <b>m.GetShape(1).__raw_implementation__.Length </b>or </p> <p class=3D"x_xmsonormal"><b>m.GetShape(1).__implementation__.Length </b>de= pending if you need an encoded instance.</p> <p class=3D"x_xmsonormal"> </p> <p class=3D"x_xmsonormal">Regards,</p> <p class=3D"x_xmsonormal">Victor Milovanov</p> <p class=3D"x_xmsonormal"> </p> <div style=3D"border:none; border-top:solid #E1E1E1 1.0pt; padding:3.0pt 0i= n 0in 0in"> <p class=3D"x_xmsonormal"><b>From: </b><a href=3D"mailto:Mohamed.Koubaa@ans= ys.com">Mohamed Koubaa</a><br> <b>Sent: </b>Monday, November 2, 2020 6:15 PM<br> <b>To: </b><a href=3D"mailto:[email protected]">[email protected]</a>= <br> <b>Subject: </b>[Python.NET] Wrap in interface (#1240)</p> </div> <p class=3D"x_xmsonormal"> </p> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">Hel= lo,</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">Thi= s <a href=3D"https://nam10.safelinks.protection.outlook.com/?url=3Dhttps%3A= %2F%2Fgithub.com%2Fpythonnet%2Fpythonnet%2Fpull%2F1240&data=3D04%7C01%7= Cmohamed.koubaa%40ansys.com%7C4b457216f75446301a4508d8cc634c3b%7C34c6ce6715= b84eff80e952da8be89706%7C0%7C0%7C637484074196952423%7CUnknown%7CTWFpbGZsb3d= 8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&= amp;sdata=3DcAFUSSzeNl11sru%2B1ZNS8EjdoqhST%2FAGvY73dUQgV9U%3D&reserved= =3D0" originalsrc=3D"https://github.com/pythonnet/pythonnet/pull/1240" shas= h=3D"g+OMDHa6fQBKO3G0Kt50iK94uCcZcWmnrUSPWrQKXrWRegJgPJMRnpMcVcJFhdaSG7IVD+= vkH7fsWmy9JR6otCRCiVmQ/BBPhzAt4OComDtsJSFrf9k3Uf3K9bdVrixnu1KdLewjccx+0mEWx= 2ObgqBJYCcOhW3UB1Cb4YnEtz4=3D" title=3D"https://github.com/pythonnet/python= net/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.</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">***= * C# code ****</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black">namespace Example1</span><span style=3D"f= ont-size:12.0pt; color:black"> </span></p> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black">{</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public enum ShapeType</span= ></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> Square,</span= ></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> Circle</span>= </p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public interface IShape</sp= an></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> void Draw();<= /span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> double Area {= get; }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> ShapeType Typ= e { get; }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public class Square : IShap= e</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public double= Length { get; }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public Square= (double length)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = Length =3D length;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public void D= raw() {}</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public double= Area { get { return Length * Length; } }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public ShapeT= ype Type { get { return ShapeType.Square; } }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public class Circle : IShap= e</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public double= Radius { get; }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public Circle= (double radius)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = Radius =3D radius;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public void D= raw() {}</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public double= Area { get { return Math.PI * Radius * Radius; } }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public ShapeT= ype Type { get { return ShapeType.Circle; } }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public class ShapeDataModel= </span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> private Dicti= onary<int, IShape> _shapes =3D new Dictionary<int, IShape>();</= span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> private int _= nextId =3D 1;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public int Ad= dShape(IShape shape)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = int id =3D _nextId;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = _shapes[id] =3D shape;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = _nextId++;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = return id;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> public IShape= GetShape(int id)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> {</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> = return _shapes[id];</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black"> }</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black">}</span></p> </div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black">&nb= sp;</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black; bac= kground:#181A1B">**** Python code ****</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> import c= lr</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> clr.AddR= eference("Example1")</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> import E= xample1</span></p> </div> <div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> sq1 =3D = Example1.Square(2.)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> ci1 =3D = Example1.Circle(1.3)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> sq2 =3D = Example1.Square(2.5)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m =3D Ex= ample1.ShapeDataModel()</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.AddSha= pe(sq1)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">1</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.AddSha= pe(sq2)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">2</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.AddSha= pe(ci1)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">3</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.GetSha= pe(2)</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516"><Example1.IShape o= bject at 0x000002A3448A09A0></span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.GetSha= pe(2).Area</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">6.25</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">>>> m.GetSha= pe(2).Length</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:black; background:#131516">Traceback (most recen= t call last):</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:#ED5C57; background:#131516"> File "&= lt;stdin>", line 1, in <module></span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; font-family:&quo= t;Courier New"; color:#ED5C57; background:#131516">AttributeError: 'IS= hape' object has no attribute 'Length'</span></p> </div> </div> <div> <p class=3D"x_xmsonormal" style=3D"margin-bottom:12.0pt"> </p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black; bac= kground:#131516">**** summary ****</span></p> </div> <div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black; bac= kground:#131516">This factory and/or datamodel pattern is very common in my= codebase and probably also lots of object oriented systems. The ment= ioned PR breaks this common design pattern in C# objects wrapped by pythonnet, and I would like a way to opt-out of i= t. Maybe an attribute on the method which returns an interface can be= used, or maybe something global to switch this behavior. I think per= haps the original bug might also have been fixed in a different way. </span></p> </div> <div> <p class=3D"x_xmsonormal" style=3D"margin-bottom:12.0pt"> </p> </div> <p class=3D"x_xmsonormal"><span style=3D"font-size:12.0pt; color:black; bac= kground:#131516">Thanks!<br> Mohamed</span></p> </div> </div> </div> <p class=3D"x_xmsonormal"> </p> <p class=3D"x_MsoNormal"> </p> </div> </div> </div> </body> </html> --_000_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_-- --_004_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_ Content-Type: image/png; name="C081996CDAA945DBACD618306EE5771E.png" Content-Description: C081996CDAA945DBACD618306EE5771E.png Content-Disposition: inline; filename="C081996CDAA945DBACD618306EE5771E.png"; size=144; creation-date="Mon, 08 Feb 2021 18:56:59 GMT"; modification-date="Mon, 08 Feb 2021 18:56:59 GMT" Content-ID: <image001.png-CFHuyTl/[email protected]> Content-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAArYAAAACCAYAAACtx5+mAAAAAXNSR0IArs4c6QAAAARnQU1BAACx jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAlSURBVFhH7cMBDQAABAAw/UtJIIEw5GD/9gAA gBeyelRV9faeBRsQNwwY9nKzAAAAAElFTkSuQmCC --_004_SN6PR01MB497662EB218106862672133C998F9SN6PR01MB4976prod_-- --===============5566050003740487892== 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] --===============5566050003740487892==--