-
Notifications
You must be signed in to change notification settings - Fork 751
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
Changes from all commits
351d9ff
d71a391
2a002d7
cf1f1dc
1c0984f
a5b245b
82aea1f
502f0c3
eb4004a
c6ae6a4
0916406
2fb6a43
9fc5b5f
00b55db
accc797
ff5d96c
264c78b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -246,6 +246,44 @@ public static IntPtr tp_str(IntPtr ob) | |
} | ||
} | ||
|
||
public static IntPtr tp_repr(IntPtr ob) | ||
{ | ||
var co = GetManagedObject(ob) as CLRObject; | ||
if (co == null) | ||
{ | ||
return Exceptions.RaiseTypeError("invalid object"); | ||
} | ||
try | ||
{ | ||
//if __repr__ is defined, use it | ||
var instType = co.inst.GetType(); | ||
System.Reflection.MethodInfo methodInfo = instType.GetMethod("__repr__"); | ||
if (methodInfo != null && methodInfo.IsPublic) | ||
{ | ||
var reprString = methodInfo.Invoke(co.inst, null) as string; | ||
return Runtime.PyString_FromString(reprString); | ||
} | ||
|
||
//otherwise use the standard object.__repr__(inst) | ||
IntPtr args = Runtime.PyTuple_New(1); | ||
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 commentThe 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! There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
Runtime.XDecref(reprFunc); | ||
return output; | ||
} | ||
catch (Exception e) | ||
{ | ||
if (e.InnerException != null) | ||
{ | ||
e = e.InnerException; | ||
} | ||
Exceptions.SetError(e); | ||
return IntPtr.Zero; | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Standard dealloc implementation for instances of reflected types. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using System; | ||
using System.Text; | ||
|
||
namespace Python.Test | ||
{ | ||
/// <summary> | ||
/// Supports repr unit tests. | ||
/// </summary> | ||
public class ReprTest | ||
{ | ||
public class Point | ||
{ | ||
public Point(double x, double y) | ||
{ | ||
X = x; | ||
Y = y; | ||
} | ||
|
||
public double X { get; set; } | ||
public double Y { get; set; } | ||
|
||
public override string ToString() | ||
{ | ||
return base.ToString() + ": X=" + X.ToString() + ", Y=" + Y.ToString(); | ||
} | ||
|
||
public string __repr__() | ||
{ | ||
return "Point(" + X.ToString() + "," + Y.ToString() + ")"; | ||
} | ||
} | ||
|
||
public class Foo | ||
{ | ||
public string __repr__() | ||
{ | ||
return "I implement __repr__() but not ToString()!"; | ||
} | ||
} | ||
|
||
public class Bar | ||
{ | ||
public override string ToString() | ||
{ | ||
return "I implement ToString() but not __repr__()!"; | ||
} | ||
} | ||
|
||
public class BazBase | ||
{ | ||
public override string ToString() | ||
{ | ||
return "Base class implementing ToString()!"; | ||
} | ||
} | ||
|
||
public class BazMiddle : BazBase | ||
{ | ||
public override string ToString() | ||
{ | ||
return "Middle class implementing ToString()!"; | ||
} | ||
} | ||
|
||
//implements ToString via BazMiddle | ||
public class Baz : BazMiddle | ||
{ | ||
|
||
} | ||
|
||
public class Quux | ||
{ | ||
public string ToString(string format) | ||
{ | ||
return "I implement ToString() with an argument!"; | ||
} | ||
} | ||
|
||
public class QuuzBase | ||
{ | ||
protected string __repr__() | ||
{ | ||
return "I implement __repr__ but it isn't public!"; | ||
} | ||
} | ||
|
||
public class Quuz : QuuzBase | ||
{ | ||
|
||
} | ||
|
||
public class Corge | ||
{ | ||
public string __repr__(int i) | ||
{ | ||
return "__repr__ implemention with input parameter!"; | ||
} | ||
} | ||
|
||
public class Grault | ||
{ | ||
public int __repr__() | ||
{ | ||
return "__repr__ implemention with wrong return type!".Length; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
"""Test __repr__ output""" | ||
|
||
import System | ||
import pytest | ||
from Python.Test import ReprTest | ||
|
||
def test_basic(): | ||
"""Test Point class which implements both ToString and __repr__ without inheritance""" | ||
ob = ReprTest.Point(1,2) | ||
# point implements ToString() and __repr__() | ||
assert ob.__repr__() == "Point(1,2)" | ||
assert str(ob) == "Python.Test.ReprTest+Point: X=1, Y=2" | ||
|
||
def test_system_string(): | ||
"""Test system string""" | ||
ob = System.String("hello") | ||
assert str(ob) == "hello" | ||
assert "<System.String object at " in ob.__repr__() | ||
|
||
def test_str_only(): | ||
"""Test class implementing ToString() but not __repr__()""" | ||
ob = ReprTest.Bar() | ||
assert str(ob) == "I implement ToString() but not __repr__()!" | ||
assert "<Python.Test.Bar object at " in ob.__repr__() | ||
|
||
def test_hierarchy1(): | ||
"""Test inheritance heirarchy with base & middle class implementing ToString""" | ||
ob1 = ReprTest.BazBase() | ||
assert str(ob1) == "Base class implementing ToString()!" | ||
assert "<Python.Test.BazBase object at " in ob1.__repr__() | ||
|
||
ob2 = ReprTest.BazMiddle() | ||
assert str(ob2) == "Middle class implementing ToString()!" | ||
assert "<Python.Test.BazMiddle object at " in ob2.__repr__() | ||
|
||
ob3 = ReprTest.Baz() | ||
assert str(ob3) == "Middle class implementing ToString()!" | ||
assert "<Python.Test.Baz object at " in ob3.__repr__() | ||
|
||
def bad_tostring(): | ||
"""Test ToString that can't be used by str()""" | ||
ob = ReprTest.Quux() | ||
assert str(ob) == "Python.Test.ReprTest+Quux" | ||
assert "<Python.Test.Quux object at " in ob.__repr__() | ||
|
||
def bad_repr(): | ||
"""Test incorrect implementation of repr""" | ||
ob1 = ReprTest.QuuzBase() | ||
assert str(ob1) == "Python.Test.ReprTest+QuuzBase" | ||
assert "<Python.Test.QuuzBase object at " in ob.__repr__() | ||
|
||
ob2 = ReprTest.Quuz() | ||
assert str(ob2) == "Python.Test.ReprTest+Quuz" | ||
assert "<Python.Test.Quuz object at " in ob.__repr__() | ||
|
||
ob3 = ReprTest.Corge() | ||
with pytest.raises(Exception): | ||
str(ob3) | ||
with pytest.raises(Exception): | ||
ob3.__repr__() | ||
|
||
ob4 = ReprTest.Grault() | ||
with pytest.raises(Exception): | ||
str(ob4) | ||
with pytest.raises(Exception): | ||
ob4.__repr__() |
Uh oh!
There was an error while loading. Please reload this page.