Full-screen console debugger for Python

Overview

PuDB: a console-based visual debugger for Python

Gitlab Build Status Github Build Status Python Package Index Release Page

Its goal is to provide all the niceties of modern GUI-based debuggers in a more lightweight and keyboard-friendly package. PuDB allows you to debug code right where you write and test it--in a terminal. If you've worked with the excellent (but nowadays ancient) DOS-based Turbo Pascal or C tools, PuDB's UI might look familiar.

Here's a screenshot:

https://tiker.net/pub/pudb-screenshot.png

You may watch a screencast, too.

Features

  • Syntax-highlighted source, the stack, breakpoints and variables are all visible at once and continuously updated. This helps you be more aware of what's going on in your program. Variable displays can be expanded, collapsed and have various customization options.
  • Simple, keyboard-based navigation using single keystrokes makes debugging quick and easy. PuDB understands cursor-keys and Vi shortcuts for navigation. Other keys are inspired by the corresponding pdb commands.
  • Use search to find relevant source code, or use "m" to invoke the module browser that shows loaded modules, lets you load new ones and reload existing ones.
  • Breakpoints can be set just by pointing at a source line and hitting "b" and then edited visually in the breakpoints window. Or hit "t" to run to the line under the cursor.
  • Drop to a Python shell in the current environment by pressing "!". Or open a command prompt alongside the source-code via "Ctrl-X".
  • PuDB places special emphasis on exception handling. A post-mortem mode makes it easy to retrace a crashing program's last steps.
  • Ability to control the debugger from a separate terminal.
  • IPython integration (see wiki)
  • Should work with Python 3.6 and newer. (Versions 2019.2 and older continue to support Python 2.7.)

Links

PuDB documentation

PuDB also has a mailing list that you may use to submit patches and requests for help. You can also send a pull request to the GitHub repository

Development Version

You may obtain the development version using the Git version control tool.:

git clone https://github.com/inducer/pudb.git

You may also browse the code online.

Comments
  • Ctrl-x not function to leave console

    Ctrl-x not function to leave console

    When attempting to make local calls in the console, pressing ctrl-x merely prints ^x rather than leaving the console. At this point, the only way out is to kill pudb. An interesting behavior is that this only happens after issuing a command in the console; ctrl-x works fine until then.

    Details: pudb version: 2015.4.1 installed with pip running in osx 10.11.2 in iTerm2, Terminal, and Neovim's terminal mode

    opened by ghost 58
  • A way to un-breakpoint a set_trace() line

    A way to un-breakpoint a set_trace() line

    This sounds kind of odd, let me explain. I usually enter the debugger with an explicit call to set_trace(). Often, once I've hit that line a few times, I no longer need to stop there, but I don't want to restart the process.

    Just as I can manually turn a regular line into a breakpoint with the 'b' command, I would love a way to turn a set_trace() line back into a regular, non-breaking line. The set_trace function would still be called of course, but could examine the calling line to see if it had been marked as non-breaking, and continue.

    enhancement 
    opened by nedbat 33
  • Add set_continue() function to __init__.py

    Add set_continue() function to __init__.py

    This lets you start the debugger and immediately continue, i.e., it only stops on a previously defined breakpoint.

    Fixes #234.

    Let me know if you would prefer a better name, or just a flag to set_trace().

    opened by asmeurer 22
  • Two New Features

    Two New Features

    Hey there. Here are two features I've wanted for a little while (sorry, probably should have put them in separate branches but they're small and you should be able to cherry pick if you don't want both).

    One of them adds support for bpython-urwid (I think maybe I'll experiment later with getting this to run inside pudb's mainloop, since that can open up some possibilities).

    The other adds support for specifying an arbitrary expression to use as the stringifier for each variable.

    opened by Julian 22
  • Problems when setting breakpoints

    Problems when setting breakpoints

    When I try to set a breakpoin, I get the errormessage: The breakpoint you just set may be invalid, for the following reason: File failed to compile.

    I can set breakpoint with Set Anyway. After some debugging, the breakpoint(s) disappear.

    Version of pudb is 2017.1, python 2.7.12+ and Ubuntu 16.10.

    Eivind

    opened by enmy211 21
  • running set_trace() multiple times displays stdlib bdb.py

    running set_trace() multiple times displays stdlib bdb.py

    Reproduction steps:

    1. Save below script as foobar.py
    2. python foobar.py foo bar
    3. You'll break at function foo
    4. Defined a breakpoint at foobar.py:11 (the first line of main(): for arg in argv:)
    5. c
    6. You'll be brought to line 11
    7. c
    8. You'll be brought to /usr/lib/python2.6/bdb.py at _ste_stopinfo(), and also see that you now have two breakpoints at foobar.py:11
    9. Pressing s fourteen times eventually brings you to the correct breakpoint in bar()

    The expected behavior is to not display bdb.py, and not create duplicate breakpoints.

    Obviously there are other ways to accomplish the desired debugging session, but in a large, complex code base, it is sometimes extremely convenient to have multiple set_trace lines, which may or may not cause set_trace to be called twice.

    If you can tell me how to induce this error automatically, I can write a unit test for it, at minimum, and likely produce a patch for the bug as well.

    # Script: foobar.py
    def foo():
        import pudb; pudb.set_trace()
        print 'foo'
    
    def bar():
        import pudb; pudb.set_trace()
        print 'bar'
    
    def main(argv):
        for arg in argv:
            if arg == 'foo':
                foo()
            elif arg == 'bar':
                bar()
    
    import sys
    main(sys.argv)
    
    Bug 
    opened by bukzor 20
  • don't provoke undefined signal handling

    don't provoke undefined signal handling

    mod_wsgi installs a non-default signal handler for SIGINT.

    The current behavior of pudb utterly clobbers this signal handler and causes undefined behavior (in practice, the process becomes impossible to kill with SIGINT).

    Until pudb has better support for non-default signal handlers in the process-under-test, I've added this small amount of code to detect the situation, throw a warning, and continue without interrupt support.

    The new warning looks like this under apache.

    [Mon Jun 10 18:44:30 2013] [error] /home/buck/trees/theirs/pudb/pudb/__init__.py:166: UserWarning: A non-default handler for signal 2 is already installed (not installed from python). Skipping pudb interrupt support.
    [Mon Jun 10 18:44:30 2013] [error]   % (interrupt_signal, old_handler))
    

    Then the process continues to work as well as previous versions of pudb.

    In terms of priority, this is driving everyone that has upgraded pudb completely nuts, and the only recourse is to downgrade.

    opened by bukzor 18
  • Add mouse support and a few changes/fix

    Add mouse support and a few changes/fix

    I know I should have asked when I started adding mouse support. So, I will highlight the changes I have made:

    mouse support

    • add
      • class double_press_input_filter for double click,
      • def listen_mouse_event like def listen, and
      • def mouse_event like def keypress for mouse support.
    • change some event handlers because the argument difference of key event and mouse event, e.g. def move_down(w, size, key) to move_down(w, size, *args). Almost all of those handlers I changed don't use key at all.
    • add some mouse event handler, which are not documented in HELP yet.

    changes

    • change change_rhs_box sizing method, which cause both above and below the selected sidebox resize, which is strange to me. I changed it so it would only affect the box below.
    • add non_post_mortem_only decorator, just try to reduce few lines.

    fix

    • exception when key press on empty variables list.

    It's fine if no one else wants the mouse support; however if it's accepted, but some naming or style/method don't fit into pudb, please let me know I will add additional changes to meet the need.

    The two changes I made, especially first one, might need more input because not everyone likes the sizing method I like as I don't like the current.

    enhancement 
    opened by livibetter 16
  • Fix the midnight theme

    Fix the midnight theme

    This reverts the changes to the midnight theme that were made in #469 and also cleans it up a little bit.

    CC @mvanderkamp I don't know if any of the changes in c7a8fbb0 were actually important.

    opened by asmeurer 15
  • Latest PuDB (2017.1.3) dies with ListBoxError in some cases

    Latest PuDB (2017.1.3) dies with ListBoxError in some cases

    Stacktrace (edited slightly for anonymity):

      File "/usr/lib/python2.7/bdb.py", line 49, in trace_dispatch
        return self.dispatch_line(frame)
      File ".../site-packages/pudb/debugger.py", line 160, in dispatch_line
        self.user_line(frame)
      File ".../site-packages/pudb/debugger.py", line 381, in user_line
        self.interaction(frame)
      File ".../site-packages/pudb/debugger.py", line 349, in interaction
        show_exc_dialog=show_exc_dialog)
      File ".../site-packages/pudb/debugger.py", line 2084, in call_with_ui
        return f(*args, **kwargs)
      File ".../site-packages/pudb/debugger.py", line 2322, in interaction
        self.event_loop()
      File ".../site-packages/pudb/debugger.py", line 2280, in event_loop
        canvas = toplevel.render(self.size, focus=True)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 1751, in render
        canv = get_delegate(self).render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/container.py", line 1083, in render
        focus and self.focus_part == 'body')
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/decoration.py", line 225, in render
        canv = self._original_widget.render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/container.py", line 2085, in render
        focus = focus and self.focus_position == i)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 1751, in render
        canv = get_delegate(self).render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/container.py", line 1526, in render
        canv = w.render((maxcol, rows), focus=focus and item_focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/decoration.py", line 225, in render
        canv = self._original_widget.render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/container.py", line 1526, in render
        canv = w.render((maxcol, rows), focus=focus and item_focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/decoration.py", line 225, in render
        canv = self._original_widget.render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 1751, in render
        canv = get_delegate(self).render(size, focus=focus)
      File ".../site-packages/urwid/widget.py", line 141, in cached_render
        canv = fn(self, size, focus=focus)
      File ".../site-packages/urwid/listbox.py", line 489, in render
        raise ListBoxError, "Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (widget,w_pos,w_rows, canvas.rows())
    ListBoxError: Widget <VariableWidget selectable flow widget> at position 3 within listbox calculated 1 rows but rendered 0!
    

    This happens under Ubuntu 17.04 using Gnome Terminal (pudb is being run inside of a docker container also running Ubuntu 17.04 if it matters). The error goes away when using PuDB 2017.1.2. It also seems to be dependent on the terminal size. For example it happens both with my "maximized" terminal size (158x46) as well as at 132x43, but it does not happen when the terminal is resized to 80x24. My pudb.cfg:

    [pudb]
    breakpoints_weight = 1
    current_stack_frame = top
    custom_shell = 
    custom_stringifier = 
    custom_theme = 
    display = auto
    line_numbers = True
    prompt_on_quit = True
    seen_welcome = e032
    shell = internal
    sidebar_width = 0.5
    stack_weight = 1
    stringifier = type
    theme = classic
    variables_weight = 1
    wrap_variables = True
    

    This is also potentially related to #269

    opened by cdman 14
  • Fix make_canvas for lines with multiple attrs

    Fix make_canvas for lines with multiple attrs

    As I was saying in #174, I was seeing some dangling characters issue. The issue was more severe than that, because I was always using line[i:count] instead of line[i:i+count]. To ensure this two chars fix works I added unit tests. They can be run by using 'py.test' from the root pudb directory.

    opened by pquentin 14
  • Allow function definition locals() to be modified in the shell

    Allow function definition locals() to be modified in the shell

    This still requires more testing, especially for the different shells.

    For the IPython shell, this requires not making a copy of locals(), but this also causes the IPython shell to pollute the locals() namespace with all its internal variables (like _0 and so on), so a better fix is needed.

    Fixes #26.

    opened by asmeurer 4
  • pudb, when run on a Python 3.x invoked with -bb, tracebacks

    pudb, when run on a Python 3.x invoked with -bb, tracebacks

    Describe the bug python3 -bb is for finding comparisons between str and bytes. I am using it to assist with porting some old code from CPython 2.7 to CPython 3.10. pudb appears to be doing at least one such comparison that interferes with its operation when used with python3 -bb. That may or may not be intentional.

    The traceback looks like:

    lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
    x                                                          Pudb Internal Exception Encountered                                                         x
    x                                                                                                                                                      x
    xPudb has encountered and safely caught an internal exception.                                                                          < OK          >x
    x                                                                                                                                       < Save        >x
    xThe full traceback and some other information can be found below. Please report this information, along with details on what you were    traceback    x
    xdoing at the time the exception occurred, at: https://github.com/inducer/pudb/issues                                                                  x
    x                                                                                                                                                      x
    xpython version: 3.10.2 (main, Mar  2 2022, 03:29:23) [GCC 10.2.1 20210110]                                                                            x
    xpudb version: 2022.1.2                                                                                                                                x
    xurwid version: 2.1.2                                                                                                                                  x
    xTraceback (most recent call last):                                                                                                                    x
    x  File "/usr/local/lib/python3.10/site-packages/pudb/debugger.py", line 460, in user_line                                                             x
    x    self.interaction(frame)                                                                                                                           x
    x  File "/usr/local/lib/python3.10/site-packages/pudb/debugger.py", line 426, in interaction                                                           x
    x    self.ui.call_with_ui(self.ui.interaction, exc_tuple,                                                                                              x
    x  File "/usr/local/lib/python3.10/site-packages/pudb/debugger.py", line 2428, in call_with_ui                                                         x
    x    self.hide()                                                                                                                                       x
    x  File "/usr/local/lib/python3.10/site-packages/pudb/debugger.py", line 2421, in hide                                                                 x
    x    self.screen.stop()                                                                                                                                x
    x  File "/usr/local/lib/python3.10/site-packages/urwid/display_common.py", line 821, in stop                                                           x
    x    self._stop()                                                                                                                                      x
    x  File "/usr/local/lib/python3.10/site-packages/urwid/raw_display.py", line 275, in _stop                                                             x
    x    self.tty_signal_keys(*(self._old_signal_keys + (fd,)))                                                                                            x
    x  File "/usr/local/lib/python3.10/site-packages/urwid/display_common.py", line 761, in tty_signal_keys                                                x
    x    if intr == 'undefined': intr = 0                                                                                                                  x
    xBytesWarning: Comparison between bytes and string                                                                                                     x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    x                                                                                                                                                      x
    mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
    

    To Reproduce Steps to reproduce the behavior:

    1. Debug code with python3 -bb and a pudb.set_trace()
    2. Unfortunately, I cannot share the code that is triggering this, but there's a good chance pudb does it frequently

    Expected behavior A debugging session that doesn't give a Pudb Internal Exception.

    Screenshots

    Additional context

    Versions

    What version of pudb? What version of Python? pudb v2022.1.2, CPython 3.10.8.

    Thanks for the great tool!

    Bug 
    opened by dstromberg 1
  • Nord Theme

    Nord Theme

    Is your feature request related to a problem? Please describe.

    I'd like to have a pudb theme similar to this one:

    https://github.com/arcticicestudio/nord-vim https://www.nordtheme.com/ports/tmux https://www.nordtheme.com/

    Describe the solution you'd like

    I'd like to have a nord theme.

    enhancement 
    opened by jgarte 1
  • Customizable breakpoint file location

    Customizable breakpoint file location

    First, love to use pudb daily, thanks :heart:

    Issue

    Currently, breakpoint is saved globally, usually in ~/.config/pudb/saved-breakpoints-3.X.

    But in most use cases, breakpoints are natual to be set by project.

    • Breakpoint set for project A means nothing for project B, and vice versa

    So while debugging for several projects, the breakpoint file is getting bigger and bigger. This is not scalable nor ideal.

    Suggest

    It might be wonderful if there's way to set breakpoint by session. There are plenty of options I can imagine.

    pudb cli option to get breakpoint file from user

    pudb --breakpoint ./my_breakpoint.txt ...
    

    I see #539 suggested to do this for configuration. This suggestion is breakpoint version of #539. I think configuration is mostly global, while breakpoint is natively per project. So getting local breakpoint file from user seems natual.

    Convention for project-wise breakpoint file location to override global setting

    Like .pudb_saved_breakpoint in project root overrides global breakpoint file, if exists.

    pudb cli option to take breakpoint at runtime (#500)

    #500 might be one option (but I prefer getting file as argument)

    enhancement 
    opened by cgbahk 2
  • On exception pudb now jumps into the exception instead of showing it

    On exception pudb now jumps into the exception instead of showing it

    Describe the bug

    When you set a breakpoint with pudb.set_trace() and pudb stops, you can press n to execute the next statement. In the past if you the statement raised and exception, pudb would tell you that an exception was raised and pressing e let you inspect the exception. Since the release v2022.01.02 pudb does not show the exception but instead jumps onto the function where the exception was raised.

    To Reproduce Steps to reproduce the behavior:

    1. create a function that has raises an exception
    2. write a function that calls the failing function and set a break point before the call with pudb.set_trace()
    3. Press n to execute the failing function

    Expected behavior

    pudb should tell you that the function raised an exception, by pressing e you should be able to inspect the the exception

    Additional context

    While some some might consider thus a nice feature, it also has the huge drawback, that it takes out of the context you were debugging and you might not be able to jump back, specially on asyncio tasks where you end up on the aio-loop rather than on your initial breakpoint.

    I already asked this question on the discussions board and it was suggested that I do a git-bisect. I did that and 98ccafc49c1d3b31a74987eebb6cb11ba2c89998 was found as the commit that introduced the bug.

    Versions

    • v2022.01.02 on Python 3.10.4
    Bug 
    opened by shaoran 4
Releases(v2022.1.3)
Full featured multi arch/os debugger built on top of PyQt5 and frida

Full featured multi arch/os debugger built on top of PyQt5 and frida

iGio90 1.1k Nov 29, 2022
pdb++, a drop-in replacement for pdb (the Python debugger)

pdb++, a drop-in replacement for pdb What is it? This module is an extension of the pdb module of the standard library. It is meant to be fully compat

null 1k Nov 30, 2022
Debugger capable of attaching to and injecting code into python processes.

DISCLAIMER: This is not an official google project, this is just something I wrote while at Google. Pyringe What this is Pyringe is a python debugger

Google 1.6k Nov 30, 2022
pdb++, a drop-in replacement for pdb (the Python debugger)

pdb++, a drop-in replacement for pdb What is it? This module is an extension of the pdb module of the standard library. It is meant to be fully compat

null 1k Nov 30, 2022
Graphical Python debugger which lets you easily view the values of all evaluated expressions

birdseye birdseye is a Python debugger which records the values of expressions in a function call and lets you easily view them after the function exi

Alex Hall 1.5k Nov 30, 2022
Voltron is an extensible debugger UI toolkit written in Python.

Voltron is an extensible debugger UI toolkit written in Python. It aims to improve the user experience of various debuggers (LLDB, GDB, VDB an

snare 5.8k Nov 29, 2022
NoPdb: Non-interactive Python Debugger

NoPdb: Non-interactive Python Debugger Installation: pip install nopdb Docs: https://nopdb.readthedocs.io/ NoPdb is a programmatic (non-interactive) d

Ondřej Cífka 67 Oct 15, 2022
Tracing instruction in lldb debugger.Just a python-script for lldb.

lldb-trace Tracing instruction in lldb debugger. just a python-script for lldb. How to use it? Break at an address where you want to begin tracing. Im

null 154 Dec 2, 2022
Visual Interaction with Code - A portable visual debugger for python

VIC Visual Interaction with Code A simple tool for debugging and interacting with running python code. This tool is designed to make it easy to inspec

Nathan Blank 1 Nov 16, 2021
An improbable web debugger through WebSockets

wdb - Web Debugger Description wdb is a full featured web debugger based on a client-server architecture. The wdb server which is responsible of manag

Kozea 1.6k Nov 26, 2022
PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB), focused on games.

PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB), focused on games. However, it can be used for any reverse-engi

Korcan Karaokçu 1.5k Nov 27, 2022
Little helper to run Steam apps under Proton with a GDB debugger

protongdb A small little helper for running games with Proton and debugging with GDB Requirements At least Python 3.5 protontricks pip package and its

Joshie 21 Nov 27, 2022
Arghonaut is an interactive interpreter, visualizer, and debugger for Argh! and Aargh!

Arghonaut Arghonaut is an interactive interpreter, visualizer, and debugger for Argh! and Aargh!, which are Befunge-like esoteric programming language

Aaron Friesen 2 Dec 10, 2021
A simple rubber duck debugger

Rubber Duck Debugger I found myself many times asking a question on StackOverflow or to one of my colleagues just for finding the solution simply by d

null 1 Nov 10, 2021
Hdbg - Historical Debugger

hdbg - Historical Debugger This is in no way a finished product. Do not use this

Fivreld 2 Jan 2, 2022
Trashdbg - TrashDBG the world's worse debugger

The world's worse debugger Over the course of multiple OALABS Twitch streams we

OALabs 21 Jun 17, 2022
The official code of LM-Debugger, an interactive tool for inspection and intervention in transformer-based language models.

LM-Debugger is an open-source interactive tool for inspection and intervention in transformer-based language models. This repository includes the code

Mor Geva 105 Nov 18, 2022
Middleware that Prints the number of DB queries to the runserver console.

Django Querycount Inspired by this post by David Szotten, this project gives you a middleware that prints DB query counts in Django's runserver consol

Brad Montgomery 329 Nov 7, 2022
Trace any Python program, anywhere!

lptrace lptrace is strace for Python programs. It lets you see in real-time what functions a Python program is running. It's particularly useful to de

Karim Hamidou 687 Nov 20, 2022