8686import com .oracle .graal .python .builtins .objects .function .PArguments ;
8787import com .oracle .graal .python .builtins .objects .list .PList ;
8888import com .oracle .graal .python .builtins .objects .module .PythonModule ;
89+ import com .oracle .graal .python .builtins .objects .str .StringNodes ;
8990import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
9091import com .oracle .graal .python .builtins .objects .type .TypeNodes ;
9192import com .oracle .graal .python .lib .PyCallableCheckNode ;
137138import com .oracle .truffle .api .frame .Frame ;
138139import com .oracle .truffle .api .frame .VirtualFrame ;
139140import com .oracle .truffle .api .nodes .Node ;
141+ import com .oracle .truffle .api .nodes .RootNode ;
140142import com .oracle .truffle .api .profiles .BranchProfile ;
141143import 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 /*
0 commit comments