-
Notifications
You must be signed in to change notification settings - Fork 747
Provide hook to implement __repr__ #808
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 #808 +/- ##
==========================================
- Coverage 76.91% 76.62% -0.29%
==========================================
Files 64 64
Lines 5935 5973 +38
Branches 976 986 +10
==========================================
+ Hits 4565 4577 +12
- Misses 1040 1059 +19
- Partials 330 337 +7
Continue to review full report at Codecov.
|
@koubaa one error here:
|
@denfromufa How do I run the tests locally? I want to make sure they work before pushing. (I just tested manually in the console and tried to follow the pattern) |
I figured it out (took longer than I'll admit!) |
One test fails because the repr of System.OverflowException went from I'll need to figure out how the old behavior was working to see why its broken now. |
@koubaa were you able to run the tests locally? If not, then I can search if we have instructions somewhere. |
@denfromufa yes I can run locally now. I have vs2017 installed and ran this to build: python setup.py install --xplat then this to test: python -m pytest Should this be in the README? |
This is only partial tests, there are also embedding tests run through
nunit.
Documentation improvements are welcome, probably this one should go into
wiki.
…On Tue, Jan 22, 2019, 6:43 PM Mohamed Koubaa ***@***.***> wrote:
@denfromufa <https://github.com/denfromufa> yes I can run locally now. I
have vs2017 installed and ran this to build:
python setup.py install --xplat
then this to test:
python -m pytest
Should this be in the README?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#808 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHgZ5RkZgmBsugyNIIRfmhr349PPwytMks5vF7BCgaJpZM4aJb9z>
.
|
@denfromufa sounds good. I didn't see any embedded test fails in previous CI runs so I'm OK running these partial tests for now. I tried to find where OverflowException repr is coming from (on master) and actually no breakpoints in tp_repr defined were hit. So I really don't know (1) how else to look for it and (2) how I could test that its an exception in classbase tp_repr and fallback to python defaults. |
@denfromufa I am back from a vacation so I looked at this again. I found this change which removed My plan is to re-implement repr in |
859f80b
to
8f6bdce
Compare
I just edited the wiki with what I know about so far. |
python tests now pass in CI. Embedded tests pass locally (on windows) but not in CI, so I'm adding some logging statements to see where. |
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.
Thanks already for your contribution. I have to think a bit about whether the "new" __str__
behaviour is how I would expect things to work.
Issue: 680
I'm having a lot of trouble with these CI tests.
Since all of the appveyor py3.4 are failing in setuptools it seems to me that its fallen out of maintenance. The 1 hour hangs concern me most since everything is queued and it delays other tests. |
@filmor we can probably make python 3.4 optional in CI tests as a temporary solution until we drop it? |
I'll have a look into this this weekend. Could you please remove the debug output? |
done |
Seems better but its hard to determine what's wrong with x64 2.7. It says python tests failed but no indication which ones. |
From the logs I think that the issue is aimply the casing of the |
@filmor done. Hopefully this works. Do you agree with the new str behavior()? |
Each dot indicates a successful test, so you can just count ;) I'll have a look into this as soon as I have finally finished the 2.4.0 release. |
Codecov Report
@@ Coverage Diff @@
## master #808 +/- ##
==========================================
- Coverage 86.71% 84.05% -2.66%
==========================================
Files 1 1
Lines 301 301
==========================================
- Hits 261 253 -8
- Misses 40 48 +8
Continue to review full report at Codecov.
|
Looks like the problems were magically fixed :) |
src/runtime/classbase.cs
Outdated
} | ||
|
||
//If the object defines __repr__, call it. | ||
System.Reflection.MethodInfo reprMethodInfo = instType.GetMethod("__repr__"); |
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.
Since all .NET types have ToString
, why does it even try __repr__
? If somebody really needs it, they can do override string ToString() => __repr__()
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.
That's not the same, though. ToString
is more akin to __str__
, there is no real equivalent to __repr__
in .NET.
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.
Yeah, this is the tp_str
implementation. tp_repr
is below
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.
@lostmsu See the comment:
//The return value must be a string object. If a class defines repr() but not str(),
//then repr() is also used when an “informal” string representation of instances of that
//class is required.
This sentence comes straight from the python manual, I didn't make it up
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.
@koubaa the default inheritance hierarchy for C# classes from Python's point of view is Python's object
<- System.Object
<- CustomCSharpClass
.
Since for all .NET classes overriding ToString
is how you implement __str__
, I don't see why it should be different for System.Object
. Hence I think .NET classes should just always call ToString
for tp_str
.
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.
@lostmsu I took a look. I agree some kind of consensus between interface vs reflection for dunder methods should be reached and applied throughout the code base. One argument for reflection is that you can use extension methods to add these. If I take an existing C# codebase and write some extension methods in a separate assembly, I can provide __repr__
and __getattr__
to it. What do you think?
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.
@koubaa, extension methods would be hard to find. You'd have to enumerate all types in all assemblies. GetMethods
won't return them.
In addition to that, what would be the semantics of multiple assemblies defining an extension method with the same signature?
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.
@lostmsu ah, didn't know that.
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.
@lostmsu I am still not convinced about the interface approach. It would require a hard build dependency on C# libraries onto PythonNet. It seems like a tough sell for some of the mature C# libraries out there.
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.
@lostmsu I changed this as you requested. I don't think I can capture the repr function in a Func object since this is a static method.
src/runtime/classbase.cs
Outdated
} | ||
|
||
//If the object defines __repr__, call it. | ||
System.Reflection.MethodInfo reprMethodInfo = instType.GetMethod("__repr__"); |
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.
Yeah, this is the tp_str
implementation. tp_repr
is below
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.
Looks like the problems were magically fixed :)
This is equal parts annoying and relieving
src/runtime/classbase.cs
Outdated
} | ||
|
||
//If the object defines __repr__, call it. | ||
System.Reflection.MethodInfo reprMethodInfo = instType.GetMethod("__repr__"); |
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.
@lostmsu See the comment:
//The return value must be a string object. If a class defines repr() but not str(),
//then repr() is also used when an “informal” string representation of instances of that
//class is required.
This sentence comes straight from the python manual, I didn't make it up
To help you in disagreeing, I propose the another style: We add a new generic abstract class (or interface with default methods when we convert to C#8)
Now this means that we would need to link |
@filmor not sure I understood your proposal. |
Hey, can this go in yet? |
It can, thanks a lot for your contribution :) |
Runtime.PyTuple_SetItem(args, 0, ob); | ||
IntPtr reprFunc = Runtime.PyObject_GetAttrString(Runtime.PyBaseObjectType, "__repr__"); | ||
var output = Runtime.PyObject_Call(reprFunc, args, IntPtr.Zero); | ||
Runtime.XDecref(args); |
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.
Decreasing args reference count actually decreases ob reference count, which marks it as garbage for the GC!
After a while GC frees the object which causes the program to crash if the object is used again.
One fix for this can be adding the line:
Runtime.XIncref(ob);
at line 269 (before setting ob to the tuple's first argument).
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.
Thanks a lot for catching this. Would you prepare a small PR?
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.
Done
1160
Provide hook to implement __repr__
Issue: 680
What does this implement/fix? Explain your changes.
This allows C# types to provide
__repr__
implementationsDoes this close any currently open issues?
680
Any other comments?
Please confirm my expections in the test I added. Inheritance hierarchies in particular were tricky to get right.
Checklist
Check all those that are applicable and complete.
AUTHORS
CHANGELOG