Skip to content

Commit 573a7ba

Browse files
committed
SysModuleBuiltins add breakpointhook
1 parent ea49499 commit 573a7ba

File tree

4 files changed

+101
-35
lines changed

4 files changed

+101
-35
lines changed

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

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError;
44+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ImportError;
4345
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError;
46+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeWarning;
4447
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4548
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeEncodeError;
4649
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
@@ -61,13 +64,16 @@
6164
import static com.oracle.graal.python.builtins.objects.traceback.TracebackNodes.objectRepr;
6265
import static com.oracle.graal.python.builtins.objects.traceback.TracebackNodes.objectStr;
6366
import static com.oracle.graal.python.builtins.objects.traceback.TracebackNodes.tryCastToString;
67+
import static com.oracle.graal.python.nodes.BuiltinNames.BREAKPOINTHOOK;
6468
import static com.oracle.graal.python.nodes.BuiltinNames.BUILTINS;
6569
import static com.oracle.graal.python.nodes.BuiltinNames.DISPLAYHOOK;
6670
import static com.oracle.graal.python.nodes.BuiltinNames.EXCEPTHOOK;
71+
import static com.oracle.graal.python.nodes.BuiltinNames.PYTHONBREAKPOINT;
6772
import static com.oracle.graal.python.nodes.BuiltinNames.STDERR;
6873
import static com.oracle.graal.python.nodes.BuiltinNames.STDIN;
6974
import static com.oracle.graal.python.nodes.BuiltinNames.STDOUT;
7075
import static com.oracle.graal.python.nodes.BuiltinNames.UNRAISABLEHOOK;
76+
import static com.oracle.graal.python.nodes.BuiltinNames.__BREAKPOINTHOOK__;
7177
import static com.oracle.graal.python.nodes.BuiltinNames.__DISPLAYHOOK__;
7278
import static com.oracle.graal.python.nodes.BuiltinNames.__EXCEPTHOOK__;
7379
import static com.oracle.graal.python.nodes.BuiltinNames.__STDERR__;
@@ -76,6 +82,8 @@
7682
import static com.oracle.graal.python.nodes.BuiltinNames.__UNRAISABLEHOOK__;
7783
import static com.oracle.graal.python.nodes.ErrorMessages.ARG_TYPE_MUST_BE;
7884
import static com.oracle.graal.python.nodes.ErrorMessages.LOST_S;
85+
import static com.oracle.graal.python.nodes.ErrorMessages.WARN_CANNOT_RUN_PDB_YET;
86+
import static com.oracle.graal.python.nodes.ErrorMessages.WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S;
7987
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__;
8088
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__MODULE__;
8189
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SIZEOF__;
@@ -115,6 +123,7 @@
115123
import com.oracle.graal.python.builtins.objects.frame.PFrame;
116124
import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference;
117125
import com.oracle.graal.python.builtins.objects.function.PArguments;
126+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
118127
import com.oracle.graal.python.builtins.objects.ints.PInt;
119128
import com.oracle.graal.python.builtins.objects.list.PList;
120129
import com.oracle.graal.python.builtins.objects.module.PythonModule;
@@ -148,9 +157,11 @@
148157
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
149158
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
150159
import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode;
160+
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
151161
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
152162
import com.oracle.graal.python.nodes.object.GetClassNode;
153163
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
164+
import com.oracle.graal.python.nodes.statement.ImportNode;
154165
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
155166
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode;
156167
import com.oracle.graal.python.runtime.PosixSupportLibrary;
@@ -543,6 +554,7 @@ public void postInitialize0(Python3Core core) {
543554
sys.setAttribute(__EXCEPTHOOK__, sys.getAttribute(EXCEPTHOOK));
544555
sys.setAttribute(__UNRAISABLEHOOK__, sys.getAttribute(UNRAISABLEHOOK));
545556
sys.setAttribute(__DISPLAYHOOK__, sys.getAttribute(DISPLAYHOOK));
557+
sys.setAttribute(__BREAKPOINTHOOK__, sys.getAttribute(BREAKPOINTHOOK));
546558
}
547559

548560
@Override
@@ -1089,12 +1101,12 @@ void printExceptionRecursive(MaterializedFrame frame, PythonModule sys, Object o
10891101
final PBaseException context = exc.getContext();
10901102

10911103
if (cause != null) {
1092-
if (!contains(seen, cause)) {
1104+
if (notSeen(seen, cause)) {
10931105
printExceptionRecursive(frame, sys, out, cause, seen);
10941106
fileWriteString(frame, out, CAUSE_MESSAGE);
10951107
}
10961108
} else if (context != null && !exc.getSuppressContext()) {
1097-
if (!contains(seen, context)) {
1109+
if (notSeen(seen, context)) {
10981110
printExceptionRecursive(frame, sys, out, context, seen);
10991111
fileWriteString(frame, out, CONTEXT_MESSAGE);
11001112
}
@@ -1181,8 +1193,8 @@ static void add(Set<Object> set, Object value) {
11811193
}
11821194

11831195
@TruffleBoundary
1184-
static boolean contains(Set<Object> set, Object value) {
1185-
return set.contains(value);
1196+
static boolean notSeen(Set<Object> set, Object value) {
1197+
return !set.contains(value);
11861198
}
11871199

11881200
@TruffleBoundary
@@ -1191,7 +1203,7 @@ static Set<Object> createSet() {
11911203
}
11921204

11931205
@Specialization
1194-
Object doWithTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unused") Object excType, Object value, PTraceback traceBack) {
1206+
Object doHookWithTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unused") Object excType, Object value, PTraceback traceBack) {
11951207
if (PGuards.isPBaseException(value)) {
11961208
final PBaseException exc = (PBaseException) value;
11971209
final PTraceback currTb = getExceptionTraceback(exc);
@@ -1209,7 +1221,7 @@ Object doWithTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unused"
12091221
}
12101222

12111223
@Specialization(guards = "!isPTraceback(traceBack)")
1212-
Object doWithoutTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unused") Object excType, Object value, @SuppressWarnings("unused") Object traceBack) {
1224+
Object doHookWithoutTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unused") Object excType, Object value, @SuppressWarnings("unused") Object traceBack) {
12131225
final MaterializedFrame materializedFrame = frame.materialize();
12141226
Object stdErr = objectLookupAttr(materializedFrame, sys, STDERR);
12151227
printExceptionRecursive(materializedFrame, sys, stdErr, value, createSet());
@@ -1224,12 +1236,12 @@ Object doWithoutTb(VirtualFrame frame, PythonModule sys, @SuppressWarnings("unus
12241236
"\n" +
12251237
"Print an object to sys.stdout and also save it in builtins._")
12261238
@GenerateNodeFactory
1227-
abstract static class DisplayHook extends PythonBuiltinNode {
1239+
abstract static class DisplayHookNode extends PythonBuiltinNode {
12281240
private static final String ATTR_ENCODING = "encoding";
12291241
private static final String ATTR_BUFFER = "buffer";
12301242

12311243
@Specialization
1232-
Object doit(VirtualFrame frame, PythonModule sys, Object obj,
1244+
Object doHook(VirtualFrame frame, PythonModule sys, Object obj,
12331245
@Cached PyObjectSetAttr setAttr,
12341246
@Cached IsBuiltinClassProfile unicodeEncodeErrorProfile,
12351247
@Cached PyObjectLookupAttr lookupAttr,
@@ -1296,4 +1308,82 @@ Object doit(VirtualFrame frame, PythonModule sys, Object obj,
12961308
}
12971309
}
12981310

1311+
@Builtin(name = BREAKPOINTHOOK, takesVarKeywordArgs = true, takesVarArgs = true, doc = "breakpointhook(*args, **kws)\n" +
1312+
"\n" +
1313+
"This hook function is called by built-in breakpoint().\n")
1314+
@GenerateNodeFactory
1315+
abstract static class BreakpointHookNode extends PythonVarargsBuiltinNode {
1316+
static final String VAL_PDB_SETTRACE = "pdb.set_trace";
1317+
1318+
@Child private ImportNode.ImportExpression importNode;
1319+
1320+
private ImportNode.ImportExpression ensureImportNode(String name) {
1321+
if (importNode == null) {
1322+
CompilerDirectives.transferToInterpreterAndInvalidate();
1323+
importNode = insert(ImportNode.createAsExpression(name));
1324+
}
1325+
return importNode;
1326+
}
1327+
1328+
@TruffleBoundary
1329+
private static Object getEnv(String name) {
1330+
return System.getenv(name);
1331+
}
1332+
1333+
@Specialization
1334+
Object doHook(VirtualFrame frame, Object[] args, PKeyword[] keywords,
1335+
@Cached CallNode callNode,
1336+
@Cached PyObjectGetAttr getAttr,
1337+
@Cached IsBuiltinClassProfile importErrorProfile,
1338+
@Cached IsBuiltinClassProfile attrErrorProfile,
1339+
@Cached CastToJavaStringNode castToJavaStringNode,
1340+
@Cached WarningsModuleBuiltins.WarnNode warnNode) {
1341+
Object v = getEnv(PYTHONBREAKPOINT);
1342+
final String hookName;
1343+
if (v == null) {
1344+
warnNode.warnFormat(frame, RuntimeWarning, WARN_CANNOT_RUN_PDB_YET);
1345+
hookName = VAL_PDB_SETTRACE;
1346+
} else {
1347+
hookName = castToString(v, castToJavaStringNode);
1348+
}
1349+
1350+
if (hookName.length() == 1 && hookName.charAt(0) == '0') {
1351+
// The breakpoint is explicitly no-op'd.
1352+
return PNone.NONE;
1353+
}
1354+
1355+
final int lastDot = PythonUtils.lastIndexOf(hookName, '.');
1356+
final String modName;
1357+
final String attrName;
1358+
if (lastDot == -1) {
1359+
// The breakpoint is a built-in, e.g. PYTHONBREAKPOINT=int
1360+
modName = BUILTINS;
1361+
attrName = hookName;
1362+
} else {
1363+
// Split on the last dot
1364+
modName = PythonUtils.substring(hookName, 0, lastDot);
1365+
attrName = PythonUtils.substring(hookName, lastDot + 1);
1366+
}
1367+
1368+
final Object module;
1369+
try {
1370+
module = ensureImportNode(modName).execute(frame);
1371+
} catch (PException pe) {
1372+
pe.expect(ImportError, importErrorProfile);
1373+
warnNode.warnFormat(frame, RuntimeWarning, WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S, hookName);
1374+
return PNone.NONE;
1375+
}
1376+
1377+
final Object hook;
1378+
try {
1379+
hook = getAttr.execute(frame, module, attrName);
1380+
} catch (PException pe) {
1381+
pe.expect(AttributeError, attrErrorProfile);
1382+
warnNode.warnFormat(frame, RuntimeWarning, WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S, hookName);
1383+
return PNone.NONE;
1384+
}
1385+
1386+
return callNode.execute(hook, args, keywords);
1387+
}
1388+
}
12991389
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public abstract class BuiltinNames {
7474
public static final String STDIN = "stdin";
7575
public static final String __STDOUT__ = "__stdout__";
7676
public static final String STDOUT = "stdout";
77+
public static final String PYTHONBREAKPOINT = "PYTHONBREAKPOINT";
7778

7879
// builtin functions
7980
public static final String ABS = "abs";

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,4 +995,6 @@ public abstract class ErrorMessages {
995995
public static final String WARN_INT_CONVERSION_DEPRECATED = "an integer is required (got type %p). " +
996996
"Implicit conversion to integers using __int__ is deprecated, " +
997997
"and may be removed in a future version of Python.";
998+
public static final String WARN_CANNOT_RUN_PDB_YET = "Graal Python cannot run pdb, yet, consider using `--inspect` on the commandline";
999+
public static final String WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S = "Ignoring unimportable $PYTHONBREAKPOINT: \"%s\"";
9981000
}

graalpython/lib-graalpython/sys.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,33 +58,6 @@ def exit(arg=None):
5858
code = arg[0]
5959
raise SystemExit(code)
6060

61-
62-
@__graalpython__.builtin
63-
def breakpointhook(*args, **kws):
64-
import importlib, os, warnings
65-
hookname = os.getenv('PYTHONBREAKPOINT')
66-
if hookname is None or len(hookname) == 0:
67-
warnings.warn('Graal Python cannot run pdb, yet, consider using `--inspect` on the commandline', RuntimeWarning)
68-
hookname = 'pdb.set_trace'
69-
elif hookname == '0':
70-
return None
71-
modname, dot, funcname = hookname.rpartition('.')
72-
if dot == '':
73-
modname = 'builtins'
74-
try:
75-
module = importlib.import_module(modname)
76-
hook = getattr(module, funcname)
77-
except:
78-
warnings.warn(
79-
'Ignoring unimportable $PYTHONBREAKPOINT: "{}"'.format(
80-
hookname),
81-
RuntimeWarning)
82-
else:
83-
return hook(*args, **kws)
84-
85-
86-
__breakpointhook__ = breakpointhook
87-
8861
@__graalpython__.builtin
8962
def getrecursionlimit():
9063
return __graalpython__.sys_state.recursionlimit

0 commit comments

Comments
 (0)