Skip to content

Commit eabe991

Browse files
committed
Implement warnings.warn skip_file_prefixes argument
1 parent b055942 commit eabe991

File tree

6 files changed

+113
-62
lines changed

6 files changed

+113
-62
lines changed

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

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import com.oracle.graal.python.builtins.objects.function.PArguments;
8787
import com.oracle.graal.python.builtins.objects.list.PList;
8888
import com.oracle.graal.python.builtins.objects.module.PythonModule;
89+
import com.oracle.graal.python.builtins.objects.str.StringNodes;
8990
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9091
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
9192
import com.oracle.graal.python.lib.PyCallableCheckNode;
@@ -137,6 +138,7 @@
137138
import com.oracle.truffle.api.frame.Frame;
138139
import com.oracle.truffle.api.frame.VirtualFrame;
139140
import com.oracle.truffle.api.nodes.Node;
141+
import com.oracle.truffle.api.nodes.RootNode;
140142
import com.oracle.truffle.api.profiles.BranchProfile;
141143
import com.oracle.truffle.api.strings.TruffleString;
142144

@@ -402,13 +404,37 @@ private PDict getGlobalsDict(Object globals) {
402404
return getDictFromGlobalsNode.executeCached(globals);
403405
}
404406

405-
private PFrame getCallerFrame(VirtualFrame frame, int stackLevel) {
407+
private PFrame getCallerFrame(VirtualFrame frame, int stackLevel, TruffleString[] skipFilePrefixes) {
406408
if (readCallerNode == null) {
407409
CompilerDirectives.transferToInterpreterAndInvalidate();
408410
reportPolymorphicSpecialize();
409411
readCallerNode = insert(ReadCallerFrameNode.create());
410412
}
411-
return readCallerNode.executeWith(PArguments.getCurrentFrameInfo(frame), ReadCallerFrameNode.FrameSelector.SKIP_INTERNAL, stackLevel);
413+
PFrame.Reference ref = PArguments.getCurrentFrameInfo(frame);
414+
ReadCallerFrameNode.FrameSelector selector = ReadCallerFrameNode.SkipInternalFramesSelector.INSTANCE;
415+
if (skipFilePrefixes != null) {
416+
/*
417+
* CPython would always count the first frame into the stacklevel even if it is
418+
* supposed to be skipped. We do that too, but our code is one off because of the
419+
* builtin frame. Let's just assume the common case where the first python frame is
420+
* always skipped by the filter.
421+
*/
422+
stackLevel--;
423+
selector = rootNode -> ReadCallerFrameNode.SkipInternalFramesSelector.INSTANCE.skip(rootNode) || isFilenameToSkip(skipFilePrefixes, rootNode);
424+
}
425+
return readCallerNode.executeWith(ref, selector, stackLevel);
426+
}
427+
428+
@TruffleBoundary
429+
private static boolean isFilenameToSkip(TruffleString[] skipFilePrefixes, RootNode rootNode) {
430+
TruffleString fileName = PCode.extractFileName(rootNode);
431+
for (TruffleString prefix : skipFilePrefixes) {
432+
if (fileName.byteLength(TS_ENCODING) >= prefix.byteLength(TS_ENCODING) &&
433+
prefix.regionEqualByteIndexUncached(0, fileName, 0, prefix.byteLength(TS_ENCODING), TS_ENCODING)) {
434+
return true;
435+
}
436+
}
437+
return false;
412438
}
413439

414440
// _Warnings_GetState split up
@@ -852,10 +878,10 @@ private void warnExplicitPart2(PythonContext context, PythonModule warnings, Tru
852878
/**
853879
* Used from doWarn. On the fast path.
854880
*/
855-
private void setupContext(VirtualFrame frame, int stackLevel, TruffleString[] filename, int[] lineno, TruffleString[] module, Object[] registry) {
881+
private void setupContext(VirtualFrame frame, int stackLevel, TruffleString[] skipFilePrefixes, TruffleString[] filename, int[] lineno, TruffleString[] module, Object[] registry) {
856882
// the stack level for the intrinsified version is off-by-one compared to the Python
857883
// version
858-
PFrame f = frame == null ? null : getCallerFrame(frame, stackLevel - 1);
884+
PFrame f = frame == null ? null : getCallerFrame(frame, stackLevel - 1, skipFilePrefixes);
859885
PDict globals;
860886
if (f == null || f.getGlobals() == null) {
861887
globals = getSysDict();
@@ -910,12 +936,12 @@ private Object getCategory(VirtualFrame frame, Object message, Object category)
910936
*/
911937
private void doWarn(VirtualFrame frame, PythonModule warnings,
912938
Object message, Object category, int stackLevel, Object source,
913-
IndirectCallData indirectCallData) {
939+
IndirectCallData indirectCallData, TruffleString[] skipFilePrefixes) {
914940
TruffleString[] filename = new TruffleString[1];
915941
int[] lineno = new int[1];
916942
TruffleString[] module = new TruffleString[1];
917943
Object[] registry = new Object[1];
918-
setupContext(frame, stackLevel, filename, lineno, module, registry);
944+
setupContext(frame, stackLevel, skipFilePrefixes, filename, lineno, module, registry);
919945
warnExplicit(frame, warnings, category, message, filename[0], lineno[0], module[0], registry[0], null, source, indirectCallData);
920946
}
921947

@@ -956,7 +982,8 @@ private static TruffleString getSourceLine(Node node, PDict globals, int lineno)
956982
}
957983
}
958984

959-
@Builtin(name = J_WARN, minNumOfPositionalArgs = 2, parameterNames = {"$mod", "message", "category", "stacklevel", "source"}, declaresExplicitSelf = true, alwaysNeedsCallerFrame = true)
985+
@Builtin(name = J_WARN, minNumOfPositionalArgs = 2, parameterNames = {"$mod", "message", "category", "stacklevel", "source",
986+
"skip_file_prefixes"}, declaresExplicitSelf = true, alwaysNeedsCallerFrame = true)
960987
@ArgumentClinic(name = "category", defaultValue = "PNone.NONE")
961988
@ArgumentClinic(name = "stacklevel", conversion = ClinicConversion.Int, defaultValue = "1")
962989
@ArgumentClinic(name = "source", defaultValue = "PNone.NONE")
@@ -967,14 +994,34 @@ protected ArgumentClinicProvider getArgumentClinic() {
967994
return WarnBuiltinNodeClinicProviderGen.INSTANCE;
968995
}
969996

970-
public abstract Object execute(VirtualFrame frame, PythonModule mod, Object message, Object category, int stacklevel, Object source);
997+
public abstract Object execute(VirtualFrame frame, PythonModule mod, Object message, Object category, int stacklevel, Object source, Object skipFilePrefixes);
971998

972999
@Specialization
973-
Object doWarn(VirtualFrame frame, PythonModule mod, Object message, Object category, int stacklevel, Object source,
1000+
Object doWarn(VirtualFrame frame, PythonModule mod, Object message, Object category, int stacklevel, Object source, Object skipFilePrefixesObj,
1001+
@Bind Node inliningTarget,
9741002
@Cached("createFor(this)") IndirectCallData indirectCallData,
1003+
@Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode,
1004+
@Cached StringNodes.CastToTruffleStringCheckedNode castToStringChecked,
1005+
@Cached PRaiseNode raiseNode,
9751006
@Cached WarningsModuleNode moduleFunctionsNode) {
9761007
// warnings_warn_impl
977-
moduleFunctionsNode.doWarn(frame, mod, message, moduleFunctionsNode.getCategory(frame, message, category), stacklevel, source, indirectCallData);
1008+
TruffleString[] skipFilePrefixes = null;
1009+
if (skipFilePrefixesObj instanceof PTuple tuple) {
1010+
SequenceStorage storage = tuple.getSequenceStorage();
1011+
if (storage.length() > 0) {
1012+
skipFilePrefixes = new TruffleString[storage.length()];
1013+
for (int i = 0; i < storage.length(); i++) {
1014+
Object item = getItemScalarNode.execute(inliningTarget, storage, i);
1015+
skipFilePrefixes[i] = castToStringChecked.cast(inliningTarget, item, ErrorMessages.FOUND_NON_STR_S_IN_SKIP_FILE_PREFIXES, item);
1016+
}
1017+
if (stacklevel < 2) {
1018+
stacklevel = 2;
1019+
}
1020+
}
1021+
} else if (skipFilePrefixesObj != PNone.NO_VALUE) {
1022+
throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError);
1023+
}
1024+
moduleFunctionsNode.doWarn(frame, mod, message, moduleFunctionsNode.getCategory(frame, message, category), stacklevel, source, indirectCallData, skipFilePrefixes);
9781025
return PNone.NONE;
9791026
}
9801027

@@ -1105,7 +1152,7 @@ protected void execute(Frame frame, Object source, Object category, TruffleStrin
11051152
CompilerDirectives.transferToInterpreterAndInvalidate();
11061153
moduleFunctionsNode = insert(WarningsModuleNode.create());
11071154
}
1108-
moduleFunctionsNode.doWarn((VirtualFrame) frame, _warnings, message, category, stackLevel, source, indirectCallData);
1155+
moduleFunctionsNode.doWarn((VirtualFrame) frame, _warnings, message, category, stackLevel, source, indirectCallData, null);
11091156
}
11101157

11111158
/*

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
import com.oracle.graal.python.nodes.frame.GetFrameLocalsNode;
5555
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode;
5656
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
57-
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode.FrameSelector;
5857
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
5958
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
6059
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -337,7 +336,7 @@ Object getBackref(VirtualFrame frame, PFrame self,
337336
// a) self is still on the stack and the caller isn't filled in
338337
// b) this frame has returned, but not (yet) to a Python caller
339338
// c) this frame has no caller (it is/was a top frame)
340-
callerFrame = readCallerFrame.executeWith(cur.getRef(), FrameSelector.ALL_PYTHON_FRAMES, 0);
339+
callerFrame = readCallerFrame.executeWith(cur.getRef(), ReadCallerFrameNode.AllFramesSelector.INSTANCE, 0);
341340

342341
// We don't need to mark the caller frame as 'escaped' because if 'self' is
343342
// escaped, the caller frame will be escaped when leaving the current function.

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode;
9494
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
9595
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
96-
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode.FrameSelector;
9796
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
9897
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
9998
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
@@ -299,7 +298,7 @@ PNone init(VirtualFrame frame, SuperObject self, @SuppressWarnings("unused") PNo
299298
@Shared @Cached PRaiseNode raiseNode,
300299
@Cached ReadCallerFrameNode readCaller,
301300
@Shared @Cached CellBuiltins.GetRefNode getRefNode) {
302-
PFrame target = readCaller.executeWith(frame, FrameSelector.SKIP_PYTHON_BUILTIN, 0);
301+
PFrame target = readCaller.executeWith(frame, ReadCallerFrameNode.SkipPythonBuiltinFramesSelector.INSTANCE, 0);
303302
if (target == null) {
304303
throw raiseNode.raise(inliningTarget, RuntimeError, ErrorMessages.NO_CURRENT_FRAME, "super()");
305304
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,7 @@ public abstract class ErrorMessages {
12321232
public static final TruffleString ISINSTANCE_ARG_2_CANNOT_CONTAIN_A_PARAMETERIZED_GENERIC = tsLiteral("isinstance() argument 2 cannot contain a parameterized generic");
12331233
public static final TruffleString ISSUBCLASS_ARG_2_CANNOT_CONTAIN_A_PARAMETERIZED_GENERIC = tsLiteral("issubclass() argument 2 cannot contain a parameterized generic");
12341234
public static final TruffleString ISSUBCLASS_ARG_1_MUST_BE_A_CLASS = tsLiteral("issubclass() arg 1 must be a class");
1235+
public static final TruffleString FOUND_NON_STR_S_IN_SKIP_FILE_PREFIXES = tsLiteral("Found non-str '%s' in skip_file_prefixes.");
12351236

12361237
// ctypes
12371238
public static final TruffleString PASSING_STRUCTS_BY_VALUE_NOT_SUPPORTED = tsLiteral("Passing structs by value is not supported on NFI backend");

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadCallerFrameNode.java

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -62,47 +62,53 @@
6262
import com.oracle.truffle.api.profiles.ConditionProfile;
6363

6464
public final class ReadCallerFrameNode extends Node {
65-
public enum FrameSelector {
66-
ALL_PYTHON_FRAMES {
67-
@Override
68-
public boolean skip(RootNode rootNode) {
69-
return false;
70-
}
71-
},
72-
/**
73-
* Skips any internal code frames including internal Python level frames of functions
74-
* annotated with @builtin.
75-
*/
76-
SKIP_PYTHON_INTERNAL {
77-
@Override
78-
public boolean skip(RootNode rootNode) {
79-
return PRootNode.isPythonInternal(rootNode);
80-
}
81-
},
82-
/**
83-
* Skips any internal frames including Python frames from internal modules in lib-graalpy.
84-
*/
85-
SKIP_INTERNAL {
86-
@Override
87-
public boolean skip(RootNode rootNode) {
88-
return (rootNode != null && rootNode.isInternal()) || PRootNode.isPythonInternal(rootNode);
89-
}
90-
},
91-
/**
92-
* Skips only builtins frames, not internal Python level frames.
93-
*/
94-
SKIP_PYTHON_BUILTIN {
95-
@Override
96-
public boolean skip(RootNode rootNode) {
97-
return PRootNode.isPythonBuiltin(rootNode);
98-
}
99-
};
65+
public interface FrameSelector {
66+
boolean skip(RootNode rootNode);
67+
}
68+
69+
public static class AllFramesSelector implements FrameSelector {
70+
public static final AllFramesSelector INSTANCE = new AllFramesSelector();
71+
72+
@Override
73+
public boolean skip(RootNode rootNode) {
74+
return false;
75+
}
76+
}
77+
78+
/**
79+
* Skips any internal code frames including internal Python level frames of functions annotated
80+
* with @builtin.
81+
*/
82+
public static class SkipPythonInternalFramesSelector implements FrameSelector {
83+
public static final SkipPythonInternalFramesSelector INSTANCE = new SkipPythonInternalFramesSelector();
10084

101-
public abstract boolean skip(RootNode rootNode);
85+
@Override
86+
public boolean skip(RootNode rootNode) {
87+
return PRootNode.isPythonInternal(rootNode);
88+
}
89+
}
90+
91+
/**
92+
* Skips any internal frames including Python frames from internal modules in lib-graalpy.
93+
*/
94+
public static class SkipInternalFramesSelector implements FrameSelector {
95+
public static final SkipInternalFramesSelector INSTANCE = new SkipInternalFramesSelector();
96+
97+
@Override
98+
public boolean skip(RootNode rootNode) {
99+
return (rootNode != null && rootNode.isInternal()) || PRootNode.isPythonInternal(rootNode);
100+
}
101+
}
102+
103+
/**
104+
* Skips only builtins frames, not internal Python level frames.
105+
*/
106+
public static class SkipPythonBuiltinFramesSelector implements FrameSelector {
107+
public static final SkipPythonBuiltinFramesSelector INSTANCE = new SkipPythonBuiltinFramesSelector();
102108

103-
public final boolean skip(PFrame.Reference ref) {
104-
Node callNode = ref.getCallNode();
105-
return callNode == null || skip(callNode.getRootNode());
109+
@Override
110+
public boolean skip(RootNode rootNode) {
111+
return PRootNode.isPythonBuiltin(rootNode);
106112
}
107113
}
108114

@@ -118,23 +124,23 @@ public static ReadCallerFrameNode create() {
118124
}
119125

120126
public PFrame executeWith(VirtualFrame frame, int level) {
121-
return executeWith(PArguments.getCurrentFrameInfo(frame), FrameSelector.SKIP_PYTHON_INTERNAL, level);
127+
return executeWith(PArguments.getCurrentFrameInfo(frame), SkipPythonInternalFramesSelector.INSTANCE, level);
122128
}
123129

124130
public PFrame executeWith(VirtualFrame frame, FrameSelector selector, int level) {
125131
return executeWith(PArguments.getCurrentFrameInfo(frame), selector, level);
126132
}
127133

128134
public PFrame executeWith(Frame startFrame, int level) {
129-
return executeWith(PArguments.getCurrentFrameInfo(startFrame), FrameSelector.SKIP_PYTHON_INTERNAL, level);
135+
return executeWith(PArguments.getCurrentFrameInfo(startFrame), SkipPythonInternalFramesSelector.INSTANCE, level);
130136
}
131137

132138
public PFrame executeWith(PFrame.Reference startFrameInfo, int level) {
133-
return executeWith(startFrameInfo, FrameSelector.SKIP_PYTHON_INTERNAL, level);
139+
return executeWith(startFrameInfo, SkipPythonInternalFramesSelector.INSTANCE, level);
134140
}
135141

136142
public PFrame executeWith(PFrame.Reference startFrameInfo, FrameInstance.FrameAccess frameAccess, int level) {
137-
return executeWith(startFrameInfo, frameAccess, FrameSelector.SKIP_PYTHON_INTERNAL, level);
143+
return executeWith(startFrameInfo, frameAccess, SkipPythonInternalFramesSelector.INSTANCE, level);
138144
}
139145

140146
public PFrame executeWith(PFrame.Reference startFrameInfo, FrameSelector selector, int level) {
@@ -252,7 +258,7 @@ private PFrame.Reference walkLevels(PFrame.Reference startFrameInfo, FrameInstan
252258
* @param frameAccess - the desired {@link FrameInstance} access kind
253259
*/
254260
public static Frame getCurrentFrame(Node requestingNode, FrameInstance.FrameAccess frameAccess) {
255-
return getFrame(Objects.requireNonNull(requestingNode), null, frameAccess, FrameSelector.ALL_PYTHON_FRAMES, 0);
261+
return getFrame(Objects.requireNonNull(requestingNode), null, frameAccess, AllFramesSelector.INSTANCE, 0);
256262
}
257263

258264
/**

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ExecutionContext.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode;
5151
import com.oracle.graal.python.nodes.frame.MaterializeFrameNodeGen;
5252
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
53-
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode.FrameSelector;
5453
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode;
5554
import com.oracle.graal.python.runtime.ExecutionContextFactory.CallContextNodeGen;
5655
import com.oracle.graal.python.runtime.PythonContext.PythonThreadState;
@@ -60,8 +59,8 @@
6059
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
6160
import com.oracle.truffle.api.CompilerDirectives.ValueType;
6261
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
63-
import com.oracle.truffle.api.bytecode.ContinuationRootNode;
6462
import com.oracle.truffle.api.RootCallTarget;
63+
import com.oracle.truffle.api.bytecode.ContinuationRootNode;
6564
import com.oracle.truffle.api.dsl.Bind;
6665
import com.oracle.truffle.api.dsl.Cached;
6766
import com.oracle.truffle.api.dsl.GenerateCached;
@@ -328,7 +327,7 @@ private void exitEscaped(VirtualFrame frame, PRootNode node, Node location, Refe
328327
// n.b. We need to use 'ReadCallerFrameNode.getCallerFrame' instead of
329328
// 'Truffle.getRuntime().getCallerFrame()' because we still need to skip
330329
// non-Python frames, even if we do not skip frames of builtin functions.
331-
Frame callerFrame = ReadCallerFrameNode.getCallerFrame(info, FrameInstance.FrameAccess.READ_ONLY, FrameSelector.ALL_PYTHON_FRAMES, 0);
330+
Frame callerFrame = ReadCallerFrameNode.getCallerFrame(info, FrameInstance.FrameAccess.READ_ONLY, ReadCallerFrameNode.AllFramesSelector.INSTANCE, 0);
332331
if (PArguments.isPythonFrame(callerFrame)) {
333332
callerInfo = PArguments.getCurrentFrameInfo(callerFrame);
334333
} else {

0 commit comments

Comments
 (0)