- Notifications
You must be signed in to change notification settings - Fork748
Wrap returned objects in interface if method return type is interface#1240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Conversation
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
codecov-commenter commentedSep 25, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov Report
@@ Coverage Diff @@## master #1240 +/- ##======================================= Coverage 86.25% 86.25% ======================================= Files 1 1 Lines 291 291 ======================================= Hits 251 251 Misses 40 40
Flags with carried forward coverage won't be shown.Click here to find out more. Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I am actually unfamiliar with that side of Python.NET, but if we make this change, can users then somehow cast the interface back to the class? If that is not so yet, such capability must be added (perhaps as a Python property?)
@filmor , do you know if you can unwrapInterfaceObject
from Python?
Uh oh!
There was an error while loading.Please reload this page.
I also found that I have failed to handle array subscription. If a method returns a |
10158f4
to010c290
CompareI've addressed the issue with returning arrays of interface objects. What remains is the ability to "downcast"/unwrap objects, as@lostmsu mentioned. As far as I have been able to see, there is no way of doing that today. One could add a property as@lostmsu suggests - the question then becomes how to name that so that the risk of colliding with one of the interface members is minimized. Perhaps there is a subset of names that would be valid in Python, but not in .NET so one can avoid collisions completely? |
Another approach would be to provide a service class that can be used for downcasting/unwrapping. A simple implementation of that today is: namespacePython.Test{publicclassCast{publicstaticobjectDowncast(objectinput)// note the return type!{returninput;}}} Which you then can use like this: fromPython.TestimportCastob=Cast.Downcast(iface_obj) The reason I bring this to attention is that it highlights the incompleteness of my approach in this PR. I have tried to make sure that whenever a .NET method returns an interface, the interface is all that Python sees (proper implementation hiding). However, I have done nothing about the corresponding case for classes. If a method is declared to return a value of type Either we should apply implementation hiding everywhere (like done for interfaces in this PR), or nowhere (which is the case today). The former is more in line with what you would get in C#. The latter is perhaps what users of Python.NET wants (?), since that is the behavior that is currently there. I'd be happy to hear your thoughts on what is the right way forward. |
@danabr completeness is not necessary. If there's a bug around C# The problem with no hiding is that it makes calling certain overloads potentially impossible due to name conflicts. @filmor do you know if we have anything like If not, I suggest |
dbc89a4
tod5308fc
CompareI've added the requested properties What remains now is properly documenting that the properties are available. Should that be done somewhere in this repo, or on the wiki, or on pythonnet.github.io? I also need to make a note of the changes in the CHANGELOG, and make it clear that this is a breaking change. |
lostmsu commentedSep 30, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@danabr to test pythonnet.github.io seems to have only basic example, so you might want to create a new wiki page for the interface objects. Yeah, a note in CHANGELOG would be helpful. |
d5308fc
toa7d2829
Compare
Great idea! I used that to add a test. I've also updated the CHANGELOG. I'll have a look at updating the Wiki if this gets merged. Thanks for all the help and guidance,@lostmsu! |
@danabr seems like a few tests are failing because the |
Argh, I wonder how come I did not notice before. I do run the tests locally. But now I can reproduce it. I'll look into it. |
a7d2829
toa604b3d
CompareIt was an unexpected interaction with the work in one of my other PRs. I must have forgotten to run the tests after rebasing on master. Now all tests pass locally. Hopefully they will pass in CI as well. |
src/runtime/interfaceobject.cs Outdated
Runtime.PyObject_SetAttrString(objPtr, "__implementation__", Converter.ToPython(impl)); | ||
Runtime.PyObject_SetAttrString(objPtr, "__raw_implementation__", CLRObject.GetInstHandle(impl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
These two must be computed only on demand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
OK. I fixed it by implementingtp_getattro
. Note that the propertiesdo not show up when you dodir
on an interface object. If that is desired I should probably go the long route viatp_getset
.
Uh oh!
There was an error while loading.Please reload this page.
This allows callers to call all methods of an interface, regardless ofwhether the method was implemented implicitly or explicitly. Before thischange, you had to make an explicit cast to the interface to be able tocall the explicitly implemented method. Consider the following code:```C#namespace Python.Test { public interface ITestInterface { void Foo(); void Bar(); } public class TestImpl : ITestInterface { public void Foo() { }; public void ITestInterface.Bar() { }; public void Baz() { }; public static ITestInterface GetInterface() { return new TestImpl(); } }}```And the following Python code, demonstrating the behavior before thischange:```pythonfrom Python.Test import TestImpl, ITestInterfacetest = TestImpl.GetInterface()test.Foo() # workstest.Bar() # AttributeError: 'TestImpl' object has no attribute 'Bar'test.Baz() # works! - baz```After this change, the behavior is as follows:```test = TestImpl.GetInterface()test.Foo() # workstest.Bar() # workstest.Baz() # AttributeError: 'ITestInterface' object has no attribute 'Baz'```This is a breaking change due to that `Baz` is no longer visible inPython.
Even when a method is declared to return an array of interfaces, the CLRmay use an array of the concrete type. Keep track of the intended typein `ArrayObject` so that elements of the array can be properly wrapped in`InterfaceObject` when accessed.
33ed60f
toc46ab75
CompareReflect PR#8 MISSING CONVERTER.CS L516-528 ChangesReflect PR#14Reflect PR#15Reflect PR#19Reflect PR#25Reflect PR#34Reflect PR#35Implement List Conversion, Reflect PR#37 TestsReflect PR#38 Partial: Assembly Manager ImprovementsReflect PR#38Reflect PR#42 KeyValuePairEnumerableObjectReflect PR#10 Runtime DecimalTypeAdd TimeDelta and DateTime testsFix DecimalConversion test for float conversionConverter mod tweaksAdjust a few broken PyTestsUse _pydecimal to not interfere with Lean/decimal.pyAdd MethodBinder testsMethodBinder implicit resolutionFix bad cherry pickRefactoring precedence resolutionDeal with operator bindingFix `TestNoOverloadException` unit testFix for DomainReload testsAdd InEquality Operator TestDont PyObjects precedence in Operator methodsRevert "Merge pull requestpythonnet#1240 from danabr/auto-cast-ret-val-to-interface"This reverts commit50d947f, reversingchanges made tod44f1da.Fix Primitive Conversion to IntPost rebase fixAdd PrimitiveIntConversion testAdd test for interface derived classesAdd to Authors.mdLoad in current directory into Python PathInclude Python Lib in packageUpdate as QuantConnect.PythonNet; include console exe in packageDrop MaybeType from ClassManager for performancePackage nPython from same configurationAddress KWargs and Params; also cleanupAdd unit testsAdd pytest params unit test to testrunnerRemove testing case from TestRuntime.csFix HandleParamsArrayTest caseVersion bumpUpdate QC TestsRefactor Params FixFix assembly infoHandle breaking PyTestsCleanupOptimize Params HandlingFirst reflection improvementsAdd TypeAccessor improvements and a bunch more testsMore improvementsBump version to 2.0.2Revert ClassManager changesRemove readonlyReplace FastMember with FasterflectAdd global MemberGetter/MemberSetter cacheMinor changesMake Fasterflect work with all regression testsFix performance regressionsRevert accidental pythonnet/runtime/.gitkeep removalHandle sending a python list to an enumerable expecting method- Converter with handle sending a python List to a method expecting a csharp enumerable. Adding unit testBump version to 2.0.3Update to net5.0- Updating all projects to target net.50- Remove domain test since it's not supported in net5.0Bump pythonNet version 2.0.4Add reproducing testApply fixCatch implicit conversion throwCleanup solutionCleanup V2Assert Error messageSmall performance improvementDrop print statement from unit testBump version to 2.0.5Bump references to new versionFix for methods with different numerical precision overloads - Fix for methods with different numerical precision overloads. Method precedence will give higher priority to higher resolution numerical arguments. Adding unit testVersion bump to 2.0.6KeyValuePair conversion and performance- Improve DateTime conversion performance- Add support for KeyValuePair conversions- Minor improvements for convertions and method binderTypeManager and decimal improvementsReduce unrequired castingVersion bump to 2.0.7Apply fixesProject fix for linux systemsAdd unit testConverter cleanupMore adjustments and fixesAdd additional Py test & cleanupUse the generic match when others failAdd test for non-generic choiceAddress reviewCleanupVersion bump 2.0.8Add performance test, also add cachingMake Cache static to apply to all bindersMake adjustments from testingAdd test where overload exists with an already typed generic parameteruse `ContainsGenericParameters` to check for unassigned genericsImplement fixAdd accompanying testAdd additional testsFix minor issue with py Date -> DateTimeRefactor solution, use margs directly convert in ResolveGenericMethodVersion Bump 2.0.9Add missing exception clearing. Adding unit testVersion bump 2.0.10Handle readonly conversion to list. Adding unit testsBump version to 2.0.11
Uh oh!
There was an error while loading.Please reload this page.
What does this implement/fix? Explain your changes.
This allows callers to call all methods of an interface, regardless of
whether the method was implemented implicitly or explicitly. Before this
change, you had to make an explicit cast to the interface to be able to
call the explicitly implemented method. Consider the following code:
And the following Python code, demonstrating the behavior before this
change:
After this change, the behavior is as follows:
This is a breaking change due to that
Baz
is no longer visible inPython.
Does this close any currently open issues?
No.
Any other comments?
See#1233 for an alternative approach, that exposes methods of explictly implemented interfaces without need to cast the object first.
Checklist
Check all those that are applicable and complete.
AUTHORS
CHANGELOG