Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
filmor merged 17 commits intopythonnet:masterfromkoubaa:repr
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
17 commits
Select commitHold shift + click to select a range
351d9ff
Provide hook to implement __repr__
koubaaJan 20, 2019
d71a391
Merge branch 'master' into repr
filmorMar 6, 2019
2a002d7
fix casing
koubaaMar 8, 2019
cf1f1dc
Merge branch 'master' into repr
filmorMar 19, 2019
1c0984f
Merge branch 'master' into repr
koubaaApr 5, 2019
a5b245b
Merge branch 'master' into repr
filmorApr 7, 2019
82aea1f
Merge branch 'master' into repr
filmorApr 8, 2019
502f0c3
Merge branch 'master' into repr
filmorJun 20, 2019
eb4004a
Merge branch 'master' into repr
filmorAug 2, 2019
c6ae6a4
Merge branch 'master' into repr
filmorSep 12, 2019
0916406
update based on review
koubaaSep 15, 2019
2fb6a43
fix whitespace
koubaaSep 15, 2019
9fc5b5f
fix whitespace
koubaaSep 15, 2019
00b55db
fix
koubaaSep 15, 2019
accc797
Don't use repr in __str__. Clean up unneeded tests
koubaaOct 16, 2019
ff5d96c
fix leak
koubaaOct 16, 2019
264c78b
Merge branch 'master' into repr
koubaaOct 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletionsAUTHORS.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,6 +41,7 @@
- Luke Stratman ([@lstratman](https://github.com/lstratman))
- Konstantin Posudevskiy ([@konstantin-posudevskiy](https://github.com/konstantin-posudevskiy))
- Matthias Dittrich ([@matthid](https://github.com/matthid))
- Mohamed Koubaa ([@koubaa](https://github.com/koubaa))
- Patrick Stewart ([@patstew](https://github.com/patstew))
- Raphael Nestler ([@rnestler](https://github.com/rnestler))
- Rickard Holmberg ([@rickardraysearch](https://github.com/rickardraysearch))
Expand Down
1 change: 1 addition & 0 deletionsCHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
- Added PyObject finalizer support, Python objects referred by C# can be auto collect now ([#692][p692]).
- Added detailed comments about aproaches and dangers to handle multi-app-domains ([#625][p625])
- Python 3.7 support, builds and testing added. Defaults changed from Python 3.6 to 3.7 ([#698][p698])
- Added support for C# types to provide `__repr__` ([#680][p680])

### Changed

Expand Down
38 changes: 38 additions & 0 deletionssrc/runtime/classbase.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Copy link
Contributor

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).

filmor reacted with thumbs up emoji
Copy link
Member

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?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Done
1160

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.
Expand Down
23 changes: 23 additions & 0 deletionssrc/runtime/exceptions.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,6 +36,29 @@ internal static Exception ToException(IntPtr ob)
return e;
}

/// <summary>
/// Exception __repr__ implementation
/// </summary>
public new static IntPtr tp_repr(IntPtr ob)
{
Exception e = ToException(ob);
if (e == null)
{
return Exceptions.RaiseTypeError("invalid object");
}
string name = e.GetType().Name;
string message;
if (e.Message != String.Empty)
{
message = String.Format("{0}('{1}')", name, e.Message);
}
else
{
message = String.Format("{0}()", name);
}
return Runtime.PyUnicode_FromString(message);
}

/// <summary>
/// Exception __str__ implementation
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletionsrc/testing/Python.Test.csproj
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,7 @@
<Compile Include="threadtest.cs" />
<Compile Include="doctest.cs" />
<Compile Include="subclasstest.cs" />
<Compile Include="ReprTest.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
Expand All@@ -111,4 +112,4 @@
<Copy SourceFiles="$(TargetAssembly)" DestinationFolder="$(SolutionDir)\src\tests\fixtures" />
<!--Copy SourceFiles="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" DestinationFolder="$(PythonBuildDir)" /-->
</Target>
</Project>
</Project>
108 changes: 108 additions & 0 deletionssrc/testing/ReprTest.cs
View file
Open in desktop
Original file line numberDiff line numberDiff 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;
}
}
}
}
7 changes: 2 additions & 5 deletionssrc/tests/test_exceptions.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -282,11 +282,8 @@ def test_python_compat_of_managed_exceptions():

assert e.args == (msg,)
assert isinstance(e.args, tuple)
if PY3:
strexp = "OverflowException('Simple message"
assert repr(e)[:len(strexp)] == strexp
elif PY2:
assert repr(e) == "OverflowException(u'Simple message',)"
strexp = "OverflowException('Simple message"
assert repr(e)[:len(strexp)] == strexp


def test_exception_is_instance_of_system_object():
Expand Down
68 changes: 68 additions & 0 deletionssrc/tests/test_repr.py
View file
Open in desktop
Original file line numberDiff line numberDiff 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__()
1 change: 1 addition & 0 deletionssrc/tests/tests.pyproj
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -59,6 +59,7 @@
<Compile Include="test_recursive_types.py" />
<Compile Include="test_subclass.py" />
<Compile Include="test_thread.py" />
<Compile Include="test_repr.py" />
<Compile Include="utils.py" />
<Compile Include="fixtures\argv-fixture.py" />
</ItemGroup>
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp