Skip to content

Commit c6998da

Browse files
committed
[GR-35631] Make __str__ call toDisplayString for foreign objects
PullRequest: graalpython/2068
2 parents a2a9d6a + 7e1cf28 commit c6998da

File tree

3 files changed

+43
-30
lines changed

3 files changed

+43
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ language runtime. The main focus is on user-observable behavior of the engine.
88
* Added partial support for `PYTHONHASHSEED` environment variable (also available via `HashSeed` context option), currently only affecting hashing in `pyexpat` module.
99
* Implement `_csv` module.
1010
* Improved compatibility with PyPI packages `wheel` and `click`
11+
* String conversion (`__str__`) now calls `toString` for Java objects and `toDisplayString` interop message for foreign objects.
1112

1213
## Version 21.3.0
1314

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,6 @@ protected static long doIt(Object object,
10301030
abstract static class StrNode extends PythonUnaryBuiltinNode {
10311031
@Child private LookupAndCallUnaryNode callStrNode;
10321032
@Child private CastToListNode castToListNode;
1033-
@Child private ObjectNodes.DefaultObjectReprNode defaultReprNode;
10341033

10351034
@Specialization
10361035
Object str(VirtualFrame frame, Object object,
@@ -1042,7 +1041,7 @@ Object str(VirtualFrame frame, Object object,
10421041
@Cached BranchProfile isLong,
10431042
@Cached BranchProfile isDouble,
10441043
@Cached BranchProfile isArray,
1045-
@Cached BranchProfile isHostObject) {
1044+
@Cached BranchProfile defaultCase) {
10461045
try {
10471046
if (lib.isNull(object)) {
10481047
isNull.enter();
@@ -1100,31 +1099,12 @@ Object str(VirtualFrame frame, Object object,
11001099
PForeignArrayIterator iterable = factory().createForeignArrayIterator(object);
11011100
return getCallStrNode().executeObject(frame, getCastToListNode().execute(frame, iterable));
11021101
}
1103-
} else if (getContext().getEnv().isHostObject(object)) {
1104-
isHostObject.enter();
1105-
boolean isMetaObject = lib.isMetaObject(object);
1106-
Object metaObject = isMetaObject
1107-
? object
1108-
: lib.hasMetaObject(object) ? lib.getMetaObject(object) : null;
1109-
if (metaObject != null) {
1110-
Object displayName = lib.toDisplayString(metaObject);
1111-
String text = createDisplayName(isMetaObject, displayName);
1112-
return PythonUtils.format("<%s at 0x%x>", text, PythonAbstractObject.systemHashCode(object));
1113-
}
11141102
}
11151103
} catch (UnsupportedMessageException e) {
11161104
// Fall back to the generic impl
11171105
}
1118-
return defaultRepr(frame, object);
1119-
}
1120-
1121-
@TruffleBoundary
1122-
private static String createDisplayName(boolean isMetaObject, Object object) {
1123-
StringBuilder sb = new StringBuilder();
1124-
sb.append(isMetaObject ? "JavaClass[" : "JavaObject[");
1125-
sb.append(object.toString());
1126-
sb.append("]");
1127-
return sb.toString();
1106+
defaultCase.enter();
1107+
return defaultConversion(frame, lib, object);
11281108
}
11291109

11301110
private LookupAndCallUnaryNode getCallStrNode() {
@@ -1143,19 +1123,50 @@ private CastToListNode getCastToListNode() {
11431123
return castToListNode;
11441124
}
11451125

1146-
protected String defaultRepr(VirtualFrame frame, Object object) {
1147-
if (defaultReprNode == null) {
1148-
CompilerDirectives.transferToInterpreterAndInvalidate();
1149-
defaultReprNode = insert(ObjectNodes.DefaultObjectReprNode.create());
1126+
protected String defaultConversion(@SuppressWarnings("unused") VirtualFrame frame, InteropLibrary lib, Object object) {
1127+
try {
1128+
return lib.asString(lib.toDisplayString(object));
1129+
} catch (UnsupportedMessageException e) {
1130+
throw CompilerDirectives.shouldNotReachHere("toDisplayString result not convertible to String");
11501131
}
1151-
return defaultReprNode.execute(frame, object);
11521132
}
11531133
}
11541134

11551135
@Builtin(name = __REPR__, minNumOfPositionalArgs = 1)
11561136
@GenerateNodeFactory
11571137
abstract static class ReprNode extends StrNode {
1158-
protected final String method = __REPR__;
1138+
@Child private ObjectNodes.DefaultObjectReprNode defaultReprNode;
1139+
1140+
protected String defaultConversion(VirtualFrame frame, @SuppressWarnings("unused") InteropLibrary lib, Object object) {
1141+
try {
1142+
if (getContext().getEnv().isHostObject(object)) {
1143+
boolean isMetaObject = lib.isMetaObject(object);
1144+
Object metaObject = null;
1145+
if (isMetaObject) {
1146+
metaObject = object;
1147+
} else if (lib.hasMetaObject(object)) {
1148+
metaObject = lib.getMetaObject(object);
1149+
}
1150+
if (metaObject != null) {
1151+
Object displayName = lib.toDisplayString(metaObject);
1152+
String text = createDisplayName(isMetaObject, displayName);
1153+
return PythonUtils.format("<%s at 0x%x>", text, PythonAbstractObject.systemHashCode(object));
1154+
}
1155+
}
1156+
} catch (UnsupportedMessageException e) {
1157+
// fallthrough to default
1158+
}
1159+
if (defaultReprNode == null) {
1160+
CompilerDirectives.transferToInterpreterAndInvalidate();
1161+
defaultReprNode = insert(ObjectNodes.DefaultObjectReprNode.create());
1162+
}
1163+
return defaultReprNode.execute(frame, object);
1164+
}
1165+
1166+
@TruffleBoundary
1167+
private static String createDisplayName(boolean isMetaObject, Object object) {
1168+
return (isMetaObject ? "JavaClass[" : "JavaObject[") + object + "]";
1169+
}
11591170
}
11601171

11611172
@Builtin(name = __BASES__, minNumOfPositionalArgs = 1, isGetter = true, isSetter = false)

graalpython/lib-python/3/test/test_subprocess.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,8 @@ def test_run_with_shell_timeout_and_capture_output(self):
15921592
stacks = traceback.format_exc() # assertRaises doesn't give this.
15931593
else:
15941594
self.fail("TimeoutExpired not raised.")
1595-
self.assertLess(after_secs - before_secs, 1.5,
1595+
# GraalVM change: increase the timing tolerance
1596+
self.assertLess(after_secs - before_secs, 3.0,
15961597
msg="TimeoutExpired was delayed! Bad traceback:\n```\n"
15971598
f"{stacks}```")
15981599

0 commit comments

Comments
 (0)