Skip to content

Commit c54567c

Browse files
committed
[GR-10866] Attach Python exceptions as __cause__ to ImportErrors raised for C extension modules
PullRequest: graalpython/120
2 parents a0bf2ed + aa04bd3 commit c54567c

File tree

6 files changed

+51
-12
lines changed

6 files changed

+51
-12
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
*/
3939
package com.oracle.graal.python.builtins.modules;
4040

41+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CAUSE__;
4142
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FILE__;
4243
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ImportError;
4344
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
@@ -56,6 +57,7 @@
5657
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.AsPythonObjectNode;
5758
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.SetItemNode;
5859
import com.oracle.graal.python.builtins.objects.dict.PDict;
60+
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5961
import com.oracle.graal.python.builtins.objects.function.PArguments;
6062
import com.oracle.graal.python.builtins.objects.module.PythonModule;
6163
import com.oracle.graal.python.builtins.objects.object.PythonObject;
@@ -239,13 +241,22 @@ private PException reportImportError(RuntimeException e, String path) {
239241
StringBuilder sb = new StringBuilder();
240242
sb.append(e.getMessage());
241243
Throwable cause = e;
244+
Object pythonCause = PNone.NONE;
242245
while ((cause = cause.getCause()) != null) {
246+
if (e instanceof PException) {
247+
if (pythonCause != PNone.NONE) {
248+
((PythonObject) pythonCause).setAttribute(__CAUSE__, ((PException) e).getExceptionObject());
249+
}
250+
pythonCause = ((PException) e).getExceptionObject();
251+
}
243252
if (cause.getMessage() != null) {
244253
sb.append(", ");
245254
sb.append(cause.getMessage());
246255
}
247256
}
248-
return raise(ImportError, "cannot load %s: %s", path, sb.toString());
257+
PBaseException importExc = factory().createBaseException(ImportError, "cannot load %s: %s", new Object[]{path, sb.toString()});
258+
importExc.setAttribute(__CAUSE__, pythonCause);
259+
throw raise(importExc);
249260
}
250261

251262
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionBuiltins.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
package com.oracle.graal.python.builtins.objects.exception;
2727

28+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CAUSE__;
29+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CONTEXT__;
2830
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__TRACEBACK__;
2931
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
3032
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
@@ -39,6 +41,8 @@
3941
import com.oracle.graal.python.builtins.objects.list.PList;
4042
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
4143
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
44+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
45+
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
4246
import com.oracle.graal.python.nodes.expression.CastToListNode;
4347
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
4448
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
@@ -131,17 +135,29 @@ public Object args(PBaseException self, Object value,
131135
}
132136
}
133137

134-
@Builtin(name = "__cause__", fixedNumOfArguments = 1, isGetter = true)
138+
@Builtin(name = __CAUSE__, minNumOfArguments = 1, maxNumOfArguments = 2, isGetter = true, isSetter = true)
135139
@GenerateNodeFactory
136140
public abstract static class CauseNode extends PythonBuiltinNode {
141+
@Specialization(guards = "isNoValue(value)")
142+
public Object cause(PBaseException self, @SuppressWarnings("unused") PNone value,
143+
@Cached("create()") ReadAttributeFromObjectNode readCause) {
144+
Object cause = readCause.execute(self, __CAUSE__);
145+
if (cause == PNone.NO_VALUE) {
146+
return PNone.NONE;
147+
} else {
148+
return cause;
149+
}
150+
}
137151

138152
@Specialization
139-
public Object cause(@SuppressWarnings("unused") PBaseException self) {
153+
public Object cause(PBaseException self, PBaseException value,
154+
@Cached("create()") WriteAttributeToObjectNode writeCause) {
155+
writeCause.execute(self, __CAUSE__, value);
140156
return PNone.NONE;
141157
}
142158
}
143159

144-
@Builtin(name = "__context__", fixedNumOfArguments = 1, isGetter = true)
160+
@Builtin(name = __CONTEXT__, fixedNumOfArguments = 1, isGetter = true)
145161
@GenerateNodeFactory
146162
public abstract static class ContextNode extends PythonBuiltinNode {
147163

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PBaseNode.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import com.oracle.graal.python.PythonLanguage;
4242
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
43+
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
4344
import com.oracle.graal.python.builtins.objects.type.PythonClass;
4445
import com.oracle.graal.python.runtime.PythonContext;
4546
import com.oracle.graal.python.runtime.PythonCore;
@@ -74,6 +75,10 @@ public final NodeFactory getNodeFactory() {
7475
return getCore().getLanguage().getNodeFactory();
7576
}
7677

78+
public final PException raise(PBaseException exc) {
79+
throw getCore().raise(exc, this);
80+
}
81+
7782
public final PException raise(PythonErrorType type) {
7883
throw getCore().raise(type, this);
7984
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialAttributeNames.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public abstract class SpecialAttributeNames {
6262
public static final String __FILE__ = "__file__";
6363
public static final String __CACHED__ = "__cached__";
6464
public static final String __TRACEBACK__ = "__traceback__";
65+
public static final String __CAUSE__ = "__cause__";
66+
public static final String __CONTEXT__ = "__context__";
6567
public static final String __BASICSIZE__ = "__basicsize__";
6668
public static final String __NEW__ = "__new__";
6769
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/RaiseNode.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
3434
import com.oracle.graal.python.builtins.objects.type.PythonClass;
3535
import com.oracle.graal.python.nodes.PNode;
36+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
3637
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
3738
import com.oracle.graal.python.runtime.PythonContext;
3839
import com.oracle.graal.python.runtime.exception.PException;
@@ -49,8 +50,6 @@
4950
@NodeChildren({@NodeChild(value = "type", type = PNode.class), @NodeChild(value = "cause", type = PNode.class)})
5051
public abstract class RaiseNode extends StatementNode {
5152

52-
private static final String __CAUSE__ = "__cause__";
53-
5453
private final ConditionProfile simpleBaseCheckProfile = ConditionProfile.createBinaryProfile();
5554
private final BranchProfile baseCheckFailedProfile = BranchProfile.create();
5655

@@ -65,15 +64,15 @@ public Object reraise(PNone type, Object cause,
6564
throw currentException;
6665
}
6766

68-
@Specialization(guards = "isNoValue(cause)")
67+
@Specialization
6968
public Object raise(PBaseException exception, PNone cause) {
7069
throw getCore().raise(exception, this);
7170
}
7271

73-
@Specialization(guards = "!isNoValue(cause)")
72+
@Specialization(guards = "!isPNone(cause)")
7473
public Object raise(PBaseException exception, Object cause,
7574
@Cached("create()") WriteAttributeToObjectNode writeCause) {
76-
writeCause.execute(exception, __CAUSE__, cause);
75+
writeCause.execute(exception, SpecialAttributeNames.__CAUSE__, cause);
7776
throw getCore().raise(exception, this);
7877
}
7978

@@ -91,18 +90,18 @@ private void checkBaseClass(PythonClass pythonClass) {
9190
throw raise(PythonErrorType.TypeError, "exceptions must derive from BaseException");
9291
}
9392

94-
@Specialization(guards = "isNoValue(cause)")
93+
@Specialization
9594
public Object raise(PythonClass pythonClass, PNone cause) {
9695
checkBaseClass(pythonClass);
9796
throw getCore().raise(factory().createBaseException(pythonClass), this);
9897
}
9998

100-
@Specialization(guards = "!isNoValue(cause)")
99+
@Specialization(guards = "!isPNone(cause)")
101100
public Object raise(PythonClass pythonClass, Object cause,
102101
@Cached("create()") WriteAttributeToObjectNode writeCause) {
103102
checkBaseClass(pythonClass);
104103
PBaseException pythonException = factory().createBaseException(pythonClass);
105-
writeCause.execute(pythonException, __CAUSE__, cause);
104+
writeCause.execute(pythonException, SpecialAttributeNames.__CAUSE__, cause);
106105
throw getCore().raise(pythonException, this);
107106
}
108107

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PythonObjectFactory.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
import com.oracle.graal.python.parser.ExecutionCellSlots;
105105
import com.oracle.graal.python.runtime.PythonCore;
106106
import com.oracle.graal.python.runtime.PythonParseResult;
107+
import com.oracle.graal.python.runtime.exception.PythonErrorType;
107108
import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage;
108109
import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage;
109110
import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage;
@@ -533,6 +534,11 @@ public PBaseException createBaseException(PythonClass cls, String format, Object
533534
return trace(new PBaseException(cls, format, args));
534535
}
535536

537+
public PBaseException createBaseException(PythonErrorType typ, String format, Object[] args) {
538+
assert format != null;
539+
return trace(new PBaseException(getCore().getErrorClass(typ), format, args));
540+
}
541+
536542
public PBaseException createBaseException(PythonClass cls) {
537543
return trace(new PBaseException(cls, createEmptyTuple()));
538544
}

0 commit comments

Comments
 (0)