-
Notifications
You must be signed in to change notification settings - Fork 747
Enable user classes to override how Python.NET processes parameters of their functions #835
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## master #835 +/- ##
========================================
Coverage ? 65.2%
========================================
Files ? 66
Lines ? 5970
Branches ? 994
========================================
Hits ? 3893
Misses ? 1719
Partials ? 358
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.
This is already a huge step forward, thank you very much :)
Regarding your concerns, I can't think of a case where one would want per-instance conversion. In that case I'd rather extend the interface to pass the instance object along s.t. the converter can branch out on its own.
Third party conversion should be quite simple to add, I commented on the respective section.
src/runtime/methodbinder.cs
Outdated
using System.Reflection; | ||
|
||
namespace Python.Runtime | ||
{ | ||
using System.Linq; |
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.
Move this to the top.
src/runtime/methodbinder.cs
Outdated
?? method.DeclaringType?.Assembly | ||
.GetCustomAttributes(typeof(PyArgConverterAttribute), inherit: false) | ||
.OfType<PyArgConverterAttribute>() | ||
.SingleOrDefault(); |
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.
Here you could additionally introduce a "global" (maybe per engine) lookup table (class -> converter
) into which one could register the marshalers even if one can't modify the declaring assembly.
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.
Did not want to overoptimize at first. Weren't there some issues with AppDomains for global caches?
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.
Oh yes, there is plenty of brokenness in that general direction, that's why I put the "(maybe per engine)" there. We have other global data though already, and for the one usecase of multiple AppDomains that I know of (reloading code in Unity) it works because they take down the PythonEngine and restart it, s.t. always exactly one is running. The comment was also more of a "fyi", not a requirement for merging :)
The build is failing, but does not seem to be related to the changes in this PR. |
I've retriggered the build and will have a look at your changes :) |
@filmor I've discovered, that this does not entirely cover my own use case as-is. Perhaps it needs more refining before upstreaming. The use case I have is .NET wrapper classes for Python classes. E.g. classes in .NET, that have interface, that copies some Python class, and a single Problem I faced is that it is unclear what to do when a wrapper class is inherited. // using default arg converter
class Wrapper {
PyObject impl;
public virtual void Overridable(CustomType o) => impl.overridable(o);
public void NonOverridable(CustomType o) => impl.non_overridable(o);
}
[PyArgConverter(typeof(CustomArgConverter))]
class UserDerived: Wrapper {
public override void Overridable(CustomType o) => o.DoSomething();
} Now I send a wrapped instance of In my use case, I can also see an opposite case, when the base class actually relies on using a specific converter. |
Nevermind, I figured it out. It works as is. |
@filmor do not rush this change. After playing a bit with it, I think we might need to change Also, looks like it reformats |
Yeah, this one I saw as well. I just wanted to see how this fares test-wise against master :) |
Hm, the .csproj change seems to be a result of fda9499 |
07c096e
to
cfc9336
Compare
Alrightie. Caught a bug in the original implementation, caused by partial initialization of |
Codecov Report
@@ Coverage Diff @@
## master #835 +/- ##
==========================================
+ Coverage 86.71% 86.75% +0.04%
==========================================
Files 1 1
Lines 301 302 +1
==========================================
+ Hits 261 262 +1
Misses 40 40
Continue to review full report at Codecov.
|
@filmor , any chance you could review this? It is ready for merging. |
Could you rebase it on the current master? There was a change in the MethodBinder in between. |
8126d2f
to
80a9e66
Compare
AppVeyor seems to have succeeded, but for some reason not being picked up: https://ci.appveyor.com/project/pythonnet/pythonnet/builds/28269629 @filmor rebased on master |
@filmor review? |
…f Python objects when calling .NET methods
…g PyArgConverter attribute
…nherited methods using an attribute on a derived class
b7eeb06
to
aaafea8
Compare
Removed from 2.x, will review for 3.x. Might have been superseded by codecs #1022 |
What does this implement/fix? Explain your changes.
This change introduces
IPyArgumentConverter
, that enables hooking into theprocess of converting Python argument values into CLR types when invoking
.NET functions from Python. See an example on the new wiki page.
If a user class needs custom conversion for the parameters of its functions, it can specify
the desired implementation of
IPyArgumentConverter
usingPyArgConverter
attributeeither on the class/struct, or for the entire assembly.
Does this close any currently open issues?
This implements #823
Any other comments?
This is but one option on how to achieve #823 . I am concerned, that it does not let users specify the converter per instance, and does not allow specifying converter for 3rd-party classes.
This change has an additional performance overhead on the first
Bind
call on each instance ofMethodBinder
due to the need to look the attribute up.Checklist
Check all those that are applicable and complete.
AUTHORS
CHANGELOG