-
-
Couldn't load subscription status.
- Fork 33.3k
gh-139721: Add ignore_module/unignore_module commands to pdb #139724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,7 +72,7 @@ def parse_opcode_signature(env, sig, signode): | |
|
|
||
| # Support for documenting pdb commands | ||
|
|
||
| pdbcmd_sig_re = re.compile(r'([a-z()!]+)\s*(.*)') | ||
| pdbcmd_sig_re = re.compile(r'([a-z()!_]+)\s*(.*)') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commands usually have dashes instead of underscores. At least most UNIX commands would be with dashes so I think it's better to have dashes in general. (also gdb uses dashes and not underscores for commands with multiple words) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to follow the convention of using snake case, the other option I was thinking is not using separator as pdb does with the commands There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For CLI-like options, I would prefer using dashes. Those are not really variables (even though they are stored in variables in the end). I'll leave the decision to Tian but we could also consider not having dashes/underscores at all if we find better words (showmodule, hidemodule would be fine I think although we're not really hiding them per se, just hiding them in the traceback). |
||
|
|
||
| # later... | ||
| # pdbargs_tokens_re = re.compile(r'''[a-zA-Z]+ | # identifiers | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -521,6 +521,13 @@ def curframe_locals(self, value): | |
|
|
||
| # Override Bdb methods | ||
|
|
||
| def stop_here(self, frame): | ||
| """Override bdb's stop_here to add message when skipping ignored modules.""" | ||
| if self.skip and self.is_skipped_module(frame.f_globals.get('__name__', '')): | ||
| self.message('[... skipped 1 ignored module(s)]') | ||
| return False | ||
| return super().stop_here(frame) | ||
|
|
||
| def user_call(self, frame, argument_list): | ||
| """This method is called when there is the remote possibility | ||
| that we ever need to stop in this function.""" | ||
|
|
@@ -1774,6 +1781,8 @@ def do_up(self, arg): | |
|
|
||
| Move the current frame count (default one) levels up in the | ||
| stack trace (to an older frame). | ||
|
|
||
| Will skip frames from ignored modules. | ||
| """ | ||
| if self.curindex == 0: | ||
| self.error('Oldest frame') | ||
|
|
@@ -1786,7 +1795,30 @@ def do_up(self, arg): | |
| if count < 0: | ||
| newframe = 0 | ||
| else: | ||
| newframe = max(0, self.curindex - count) | ||
| # Skip over ignored modules | ||
| counter = 0 | ||
| module_skipped = 0 | ||
| for i in range(self.curindex - 1, -1, -1): | ||
| frame = self.stack[i][0] | ||
| should_skip_module = (self.skip and | ||
| self.is_skipped_module(frame.f_globals.get('__name__', ''))) | ||
|
|
||
| if should_skip_module: | ||
| module_skipped += 1 | ||
| continue | ||
| counter += 1 | ||
| if counter >= count: | ||
| break | ||
| else: | ||
| # No valid frames found | ||
| self.error('All frames above are from ignored modules. ' | ||
| 'Use "unignore_module" to allow stepping into them.') | ||
| return | ||
|
|
||
| newframe = i | ||
| if module_skipped: | ||
| self.message(f'[... skipped {module_skipped} frame(s) ' | ||
| 'from ignored modules]') | ||
| self._select_frame(newframe) | ||
| do_u = do_up | ||
|
|
||
|
|
@@ -1795,6 +1827,8 @@ def do_down(self, arg): | |
|
|
||
| Move the current frame count (default one) levels down in the | ||
| stack trace (to a newer frame). | ||
|
|
||
| Will skip frames from ignored modules. | ||
| """ | ||
| if self.curindex + 1 == len(self.stack): | ||
| self.error('Newest frame') | ||
|
|
@@ -1807,7 +1841,30 @@ def do_down(self, arg): | |
| if count < 0: | ||
| newframe = len(self.stack) - 1 | ||
| else: | ||
| newframe = min(len(self.stack) - 1, self.curindex + count) | ||
| # Skip over ignored modules | ||
| counter = 0 | ||
| module_skipped = 0 | ||
| for i in range(self.curindex + 1, len(self.stack)): | ||
| frame = self.stack[i][0] | ||
| should_skip_module = (self.skip and | ||
| self.is_skipped_module(frame.f_globals.get('__name__', ''))) | ||
|
|
||
| if should_skip_module: | ||
| module_skipped += 1 | ||
| continue | ||
| counter += 1 | ||
| if counter >= count: | ||
| break | ||
| else: | ||
| # No valid frames found | ||
| self.error('All frames below are from ignored modules. ' | ||
| 'Use "unignore_module" to allow stepping into them.') | ||
| return | ||
|
|
||
| newframe = i | ||
| if module_skipped: | ||
| self.message(f'[... skipped {module_skipped} frame(s) ' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest indicating which module was ignored if there is only 1 module being ignored. |
||
| 'from ignored modules]') | ||
| self._select_frame(newframe) | ||
| do_d = do_down | ||
|
|
||
|
|
@@ -2327,6 +2384,69 @@ def do_interact(self, arg): | |
| console.interact(banner="*pdb interact start*", | ||
| exitmsg="*exit from pdb interact command*") | ||
|
|
||
| def _show_ignored_modules(self): | ||
| """Display currently ignored modules.""" | ||
| if self.skip: | ||
| self.message(f'Currently ignored modules: {sorted(self.skip)}') | ||
| else: | ||
| self.message('No modules are currently ignored.') | ||
|
|
||
| def do_ignore_module(self, arg): | ||
| """ignore_module [module_name] | ||
|
|
||
| Add a module to the list of modules to skip when stepping, | ||
| continuing, or navigating frames. When a module is ignored, | ||
| the debugger will automatically skip over frames from that | ||
| module during step, next, continue, up, and down commands. | ||
|
|
||
| Supports wildcard patterns using glob-style matching: | ||
|
|
||
| Usage: | ||
| ignore_module threading # Skip threading module frames | ||
| ignore_module asyncio.* # Skip all asyncio submodules | ||
| ignore_module *.tests # Skip all test modules | ||
| ignore_module # List currently ignored modules | ||
| """ | ||
| if self.skip is None: | ||
| self.skip = set() | ||
|
|
||
| module_name = arg.strip() | ||
|
|
||
| if not module_name: | ||
| self._show_ignored_modules() | ||
| return | ||
|
|
||
| self.skip.add(module_name) | ||
| self.message(f'Ignoring module: {module_name}') | ||
|
|
||
| def do_unignore_module(self, arg): | ||
| """unignore_module [module_name] | ||
|
|
||
| Remove a module from the list of modules to skip when stepping | ||
| or navigating frames. This will allow the debugger to step into | ||
| frames from the specified module. | ||
|
|
||
| Usage: | ||
| unignore_module threading # Stop ignoring threading module frames | ||
| unignore_module asyncio.* # Remove asyncio.* pattern | ||
| unignore_module # List currently ignored modules | ||
| """ | ||
| if self.skip is None: | ||
| self.skip = set() | ||
|
|
||
| module_name = arg.strip() | ||
|
|
||
| if not module_name: | ||
| self._show_ignored_modules() | ||
| return | ||
|
|
||
| try: | ||
| self.skip.remove(module_name) | ||
| self.message(f'No longer ignoring module: {module_name}') | ||
| except KeyError: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should only be emitted after |
||
| self.error(f'Module {module_name} is not currently ignored') | ||
| self._show_ignored_modules() | ||
|
|
||
| def do_alias(self, arg): | ||
| """alias [name [command]] | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.