@@ -1107,17 +1107,32 @@ def stop_here(self, frame):
11071107 ]
11081108 )
11091109 )
1110+ if self .skip and self .is_skipped_module (frame .f_globals .get ("__name__" , "" )):
1111+ print (
1112+ self .theme .format (
1113+ [
1114+ (
1115+ Token .ExcName ,
1116+ " [... skipped 1 ignored module(s)]" ,
1117+ ),
1118+ (Token , "\n " ),
1119+ ]
1120+ )
1121+ )
1122+
1123+ return False
1124+
11101125 return super ().stop_here (frame )
11111126
11121127 def do_up (self , arg ):
11131128 """u(p) [count]
11141129 Move the current frame count (default one) levels up in the
11151130 stack trace (to an older frame).
11161131
1117- Will skip hidden frames.
1132+ Will skip hidden frames and ignored modules .
11181133 """
11191134 # modified version of upstream that skips
1120- # frames with __tracebackhide__
1135+ # frames with __tracebackhide__ and ignored modules
11211136 if self .curindex == 0 :
11221137 self .error ("Oldest frame" )
11231138 return
@@ -1126,35 +1141,49 @@ def do_up(self, arg):
11261141 except ValueError :
11271142 self .error ("Invalid frame count (%s)" % arg )
11281143 return
1129- skipped = 0
1144+
1145+ hidden_skipped = 0
1146+ module_skipped = 0
1147+
11301148 if count < 0 :
11311149 _newframe = 0
11321150 else :
11331151 counter = 0
11341152 hidden_frames = self .hidden_frames (self .stack )
1153+
11351154 for i in range (self .curindex - 1 , - 1 , - 1 ):
1136- if hidden_frames [i ] and self .skip_hidden :
1137- skipped += 1
1155+ should_skip_hidden = hidden_frames [i ] and self .skip_hidden
1156+ should_skip_module = self .skip and self .is_skipped_module (
1157+ self .stack [i ][0 ].f_globals .get ("__name__" , "" )
1158+ )
1159+
1160+ if should_skip_hidden or should_skip_module :
1161+ if should_skip_hidden :
1162+ hidden_skipped += 1
1163+ if should_skip_module :
1164+ module_skipped += 1
11381165 continue
11391166 counter += 1
11401167 if counter >= count :
11411168 break
11421169 else :
11431170 # if no break occurred.
11441171 self .error (
1145- "all frames above hidden, use `skip_hidden False` to get get into those ."
1172+ "all frames above skipped ( hidden frames and ignored modules). Use `skip_hidden False` for hidden frames or unignore_module for ignored modules ."
11461173 )
11471174 return
11481175
11491176 _newframe = i
11501177 self ._select_frame (_newframe )
1151- if skipped :
1178+
1179+ total_skipped = hidden_skipped + module_skipped
1180+ if total_skipped :
11521181 print (
11531182 self .theme .format (
11541183 [
11551184 (
11561185 Token .ExcName ,
1157- f" [... skipped { skipped } hidden frame(s)]" ,
1186+ f" [... skipped { total_skipped } frame(s): { hidden_skipped } hidden frames + { module_skipped } ignored modules ]" ,
11581187 ),
11591188 (Token , "\n " ),
11601189 ]
@@ -1166,7 +1195,7 @@ def do_down(self, arg):
11661195 Move the current frame count (default one) levels down in the
11671196 stack trace (to a newer frame).
11681197
1169- Will skip hidden frames.
1198+ Will skip hidden frames and ignored modules .
11701199 """
11711200 if self .curindex + 1 == len (self .stack ):
11721201 self .error ("Newest frame" )
@@ -1180,28 +1209,39 @@ def do_down(self, arg):
11801209 _newframe = len (self .stack ) - 1
11811210 else :
11821211 counter = 0
1183- skipped = 0
1212+ hidden_skipped = 0
1213+ module_skipped = 0
11841214 hidden_frames = self .hidden_frames (self .stack )
1215+
11851216 for i in range (self .curindex + 1 , len (self .stack )):
1186- if hidden_frames [i ] and self .skip_hidden :
1187- skipped += 1
1217+ should_skip_hidden = hidden_frames [i ] and self .skip_hidden
1218+ should_skip_module = self .skip and self .is_skipped_module (
1219+ self .stack [i ][0 ].f_globals .get ("__name__" , "" )
1220+ )
1221+
1222+ if should_skip_hidden or should_skip_module :
1223+ if should_skip_hidden :
1224+ hidden_skipped += 1
1225+ if should_skip_module :
1226+ module_skipped += 1
11881227 continue
11891228 counter += 1
11901229 if counter >= count :
11911230 break
11921231 else :
11931232 self .error (
1194- "all frames below hidden, use `skip_hidden False` to get get into those ."
1233+ "all frames below skipped ( hidden frames and ignored modules). Use `skip_hidden False` for hidden frames or unignore_module for ignored modules ."
11951234 )
11961235 return
11971236
1198- if skipped :
1237+ total_skipped = hidden_skipped + module_skipped
1238+ if total_skipped :
11991239 print (
12001240 self .theme .format (
12011241 [
12021242 (
12031243 Token .ExcName ,
1204- f" [... skipped { skipped } hidden frame(s)]" ,
1244+ f" [... skipped { total_skipped } frame(s): { hidden_skipped } hidden frames + { module_skipped } ignored modules ]" ,
12051245 ),
12061246 (Token , "\n " ),
12071247 ]
@@ -1214,6 +1254,67 @@ def do_down(self, arg):
12141254 do_d = do_down
12151255 do_u = do_up
12161256
1257+ def _show_ignored_modules (self ):
1258+ """Display currently ignored modules."""
1259+ if self .skip :
1260+ print (f"Currently ignored modules: { sorted (self .skip )} " )
1261+ else :
1262+ print ("No modules are currently ignored." )
1263+
1264+ def do_ignore_module (self , arg ):
1265+ """ignore_module <module_name>
1266+
1267+ Add a module to the list of modules to skip when navigating frames.
1268+ When a module is ignored, the debugger will automatically skip over
1269+ frames from that module.
1270+
1271+ Supports wildcard patterns using fnmatch syntax:
1272+
1273+ Usage:
1274+ ignore_module threading # Skip threading module frames
1275+ ignore_module asyncio.\\ * # Skip all asyncio submodules
1276+ ignore_module \\ *.tests # Skip all test modules
1277+ ignore_module # List currently ignored modules
1278+ """
1279+
1280+ if self .skip is None :
1281+ self .skip = set ()
1282+
1283+ module_name = arg .strip ()
1284+
1285+ if not module_name :
1286+ self ._show_ignored_modules ()
1287+ return
1288+
1289+ self .skip .add (module_name )
1290+
1291+ def do_unignore_module (self , arg ):
1292+ """unignore_module <module_name>
1293+
1294+ Remove a module from the list of modules to skip when navigating frames.
1295+ This will allow the debugger to step into frames from the specified module.
1296+
1297+ Usage:
1298+ unignore_module threading # Stop ignoring threading module frames
1299+ unignore_module asyncio.\\ * # Remove asyncio.* pattern
1300+ unignore_module # List currently ignored modules
1301+ """
1302+
1303+ if self .skip is None :
1304+ self .skip = set ()
1305+
1306+ module_name = arg .strip ()
1307+
1308+ if not module_name :
1309+ self ._show_ignored_modules ()
1310+ return
1311+
1312+ try :
1313+ self .skip .remove (module_name )
1314+ except KeyError :
1315+ print (f"Module { module_name } is not currently ignored" )
1316+ self ._show_ignored_modules ()
1317+
12171318 def do_context (self , context : str ):
12181319 """context number_of_lines
12191320 Set the number of lines of source code to show when displaying
0 commit comments