Skip to content

Commit a4aeeda

Browse files
authored
Support str subclass from repr (#1461)
1 parent 0590e99 commit a4aeeda

3 files changed

Lines changed: 21 additions & 5 deletions

File tree

Src/IronPython/Modules/Builtin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ private static void PrintHelper(CodeContext/*!*/ context, string/*!*/ sep, strin
12951295
}
12961296

12971297
public static object repr(CodeContext/*!*/ context, object? o)
1298-
=> PythonOps.Repr(context, o);
1298+
=> PythonOps.GetReprObject(context, o);
12991299

13001300
public static PythonType reversed => DynamicHelpers.GetPythonTypeFromType(typeof(ReversedEnumerator));
13011301

Src/IronPython/Runtime/Operations/PythonOps.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,13 @@ public static string Ascii(CodeContext/*!*/ context, object? o) {
225225
return StringOps.AsciiEncode(Repr(context, o));
226226
}
227227

228-
public static string Repr(CodeContext/*!*/ context, object? o) {
228+
internal static object GetReprObject(CodeContext/*!*/ context, object? o) {
229229
if (o == null) return "None";
230230

231+
// Fast tracks
231232
if (o is string s) return StringOps.__repr__(s);
232-
if (o is int) return Int32Ops.__repr__((int)o);
233-
if (o is long) return ((long)o).ToString();
233+
if (o is int i32) return Int32Ops.__repr__(i32);
234+
if (o is BigInteger bi) return BigIntegerOps.__repr__(bi);
234235

235236
// could be a container object, we need to detect recursion, but only
236237
// for our own built-in types that we're aware of. The user can setup
@@ -267,6 +268,9 @@ public static string Repr(CodeContext/*!*/ context, object? o) {
267268
throw PythonOps.TypeError("__repr__ returned non-string (got '{0}' from type '{1}')", PythonOps.GetPythonTypeName(repr), PythonOps.GetPythonTypeName(o));
268269
}
269270

271+
public static string Repr(CodeContext/*!*/ context, object? o)
272+
=> GetReprObject(context, o).ToString() ?? "<unknown>";
273+
270274
public static string Format(CodeContext/*!*/ context, object? argValue, string formatSpec) {
271275
object? res;
272276
// call __format__ with the format spec (__format__ is defined on object, so this always succeeds)

Tests/test_str.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import sys
88
import warnings
99

10-
from iptest import IronPythonTestCase, is_cli, big, run_test, skipUnlessIronPython
10+
from iptest import IronPythonTestCase, is_cli, big, mystr, run_test, skipUnlessIronPython
1111

1212
class Indexable:
1313
def __init__(self, value):
@@ -298,6 +298,18 @@ def __contains__(self, value): return False
298298
self.assertEqual(len(o), 2300)
299299
self.assertEqual('a' in o, False)
300300

301+
def test_repr_mystr(self):
302+
class A:
303+
def __repr__(self) -> str:
304+
return mystr("__repr__ called")
305+
def __str__(self) -> str:
306+
return mystr("__str__ called")
307+
308+
self.assertIs(type(repr(A())), mystr)
309+
self.assertIs(type(str(A())), mystr)
310+
self.assertEquals(repr(A()), "__repr__ called")
311+
self.assertEquals(str(A()), "__str__ called")
312+
301313
@skipUnlessIronPython()
302314
def test_str_char_hash(self):
303315
import System

0 commit comments

Comments
 (0)