mdmintz / pdbp Goto Github PK
View Code? Open in Web Editor NEWpdbp (Pdb+): A drop-in replacement for pdb and pdbpp. To replace "pdb", add "import pdbp" to an "__init__.py" file.
License: Other
pdbp (Pdb+): A drop-in replacement for pdb and pdbpp. To replace "pdb", add "import pdbp" to an "__init__.py" file.
License: Other
Code block not printed after a jump LINENO
in sticky
mode.
Expecting to see a code block so that it's clear where the program is.
A basic code analysis shows that the package is a fork, and as such a direct derivative of pdbpp, which uses three-clause BSD license.
The BSD license terms, as non-onerous as they are, require replicating the copyright notice, even if new changes are licensed using a different software license.
Please reinstate the original copyright notice and code attribution, and credit Antonio Cuni's work directly, at the very least, thanks. Correcting the misleading commit messages that suggest that the package is entirely an original work would be useful, too.
Have a more intuitive list
/ l
command in debugger mode.
Like the original version, which lists 11 lines around the current line, and then continues from that point on, if the end-of-file (EOF) point is reached, the list
function should loop back to the active cursor position, and resume from there.
Drop support for Python 2.7
Whenever an exception is raised, the usual exception+stack trace is printed but then pdbp runs its clear screen leaving you with nothing but what comes after – an arrow pointing to the offending line of code without even the exception type to say what's wrong with it.
For example:
echo 'assert 0' > test.py
python -m pdbp test.py
If I c
through to the exception I just get the following which is pretty but less useful to me than boring old pdb
.
[4] > /tmp/test.py(1)
1 -> assert 0
(Pdb+)
It would be a lot more practical for the sequence to be, clear screen -> dump exception/stacktrace -> print current code location.
That all said, I'm personally happier to let the terminal do the scrolling. If I disable the clear screen (edit pdbp.py
and set CLEARSCREEN
to an empty string), the resultant UX is perfect for me.
Thanks a lot for pdbp
! I've already started using it lots, gradually replacing pdbpp
.
Running pdbpp
within pytest seems more complicated than previous alternatives, particularly in a project where we don't want to change the python code, or when recommending it to others who just want a simple command.
Currently I'm doing:
pytest --pdb --pdbcls=pdbp:Pdb --capture=tee-sys
--capture=tee-sys
is discussed in #57, but I would note that neither pdb
nor pdbpp
require this — are we confident it's not possible to avoid it?--pdbcls=pdbp:Pdb
is a pytest frailty from pytest-dev/pytest#5498. But would it be worth documenting it?I appreciate the sentiments behind not blindly overriding pdb, relative to pdbpp's practice. But would there be any interest in pip install pdbp[pdb]
, which would override pdb
like pdbpp
does? While your approach is purer, the pdbpp
override was overall a better experience on that dimension.
Currently, lines containing those special characters will cause the pdbp
debugger output to display double-spaced lines, (instead of the usual one line per line format). This is because those special characters have double the width of a regular characters, which pushes text over to the next line (caused by a bad calculation where line width is being incorrectly based on line length). The line width should only be equal to the line length when all characters of that line take up exactly one space each. Otherwise, the actual widths of each character need to be calculated in order to determine the correct line width.
Hi!
First, thank you for the Pdb++ upgrade – fixing those bugs is much appreciated, and I like the Sticky mode by default.
I've noticed that currently, the pdb config file is hardcoded to "~/.pdbrc.py" here, with the home path specified in the tabcompleter repository.
To avoid creating a new file in the home directory, it would be awesome if Pdb+ could support the XDG Base Directory specification. While a complete XDG implementation seems challenging due to the hardcoded home path in tabcompleter, tweaking the code in Pdb+ appears less critical and could be a solid initial step.
The modification involves updating the config_filename
definition, for example, like this:
config_filename = ( ".config/pdbp/pdbrc.py" if os.path.exists(os.path.join(os.path.expanduser("~"), ".config/pdbp/pdbrc.py")) else ".pdbrc.py" )
Theoretically, checking the "XDG_CONFIG_HOME" environment variable might be better, but this could complicate matters by requiring modifications in tabcompleter
and dealing with potential backward compatibility issues. On the other hand, the suggested change in Pdb+ is minimal and transparent for users.
What are your thoughts on this modification? Does it seem sensible?
Thanks!
currently crashes
When running a debug session (be it pdb, pdbpp or pdbp) and saving code in the editor, the autoreload of a development server (Flask Django) ruins the prompt of the terminal session, because the development server process is restarted.
This is not an pdbp issue, however maybe there is a way to mitigate this in some way an recover nicely from an autosave?
Error in inspect.getsourcelines: could not get source code
This bug was carried over from pdbpp
and happens in sticky
mode. It can be fixed by temporarily switching over to non-sticky mode in this stack iteration, which would display a single line of the code, rather than attempting to display all nearby lines of code.
The reason this bug can happen is due to Python frozen modules. Due to the nature of frozen modules, the full code cannot be accessed in the same way as non-frozen modules.
With a proper fix implemented, this would be the expected output (as an example) when using pdbp
(Pdb+) to view stack levels: (Note the switch from sticky mode to non-sticky mode.)
(Pdb+) u
[27] > <frozen importlib._bootstrap>(241)_call_with_frames_removed()
(Pdb+) u
[26] > <frozen importlib._bootstrap_external>(940)exec_module()
(Pdb+) u
[25] > <frozen importlib._bootstrap>(690)_load_unlocked()
(Pdb+) u
[24] > <frozen importlib._bootstrap>(1149)_find_and_load_unlocked()
(Pdb+) u
[23] > <frozen importlib._bootstrap>(1178)_find_and_load()
I discovered this issue while using pdbp
to debug an unrelated deprecation warning:
(sbase11c) MM-MacBook-Air:SeleniumBase michael$ mkdocs build
INFO - DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/warnings.py", line 514,
in _deprecated
warn(msg, DeprecationWarning, stacklevel=3)
File "/Users/michael/.virtualenvs/sbase11c/lib/python3.11/site-packages/htmlmin/main.py", line
28, in
import cgi
The cause of that deprecation warning was found to be: mkdocs-minify-plugin
. (A completely separate issue from this ticket.)
Make the new pygments
release the new minimum pygments
version.
Great news: The new pygments
release that just came out, 2.15.1
- (https://github.com/pygments/pygments/releases/tag/2.15.1) fixed some Python issues that caused problems for the debugger. That's going to become the new minimum version of pygments
in the pdbp
dependencies (for Python>=3.7
). The remaining supported Python versions (3.6
) will use pygments>=2.14.0
.
This upgrade will certainly help with making sure that code blocks are displayed properly by the pdbp
debugger.
Excellent work!
But there is something is not as expected about !
statement described here https://docs.python.org/3/library/pdb.html
when I want to assign values to variables in debugging, it does't work.
however, the pdb is ok.
Here is my env:
Linux
Python==3.10.6
pdbp== 1.4.6
Certain commands should automatically switch between "sticky" and non-"sticky" modes.
Eg. where
/ w
/ bt
should automatically switch to non-"sticky" mode.
Eg. longlist
/ ll
should automatically switch back to "sticky" mode.
Or use sticky
to toggle between the two modes.
An example of the where
/ w
command, which displays the current stack:
Hi!
So far I used pdb++ which is not maintained anymore and I'm quite happy that I found your project here. Many thanks!
I have a question wrt. to version 1.5.0
I'm wondering why the PYTHONBREAKPOINT
env var has no effect.
When I set it like documented and run
PYTHONBREAKPOINT=pdbp.set_trace python -m pdb -m my_library_module
the standard PDB w/o syntax highlighting comes up. When I run it like
PYTHONBREAKPOINT=pdbp.set_trace python -m pdbp -m my_library_module
PDB+ launches.
Is there anything I miss. My hope was that setting the env var results into sth. which is similar to the dropin-replacement behaviour of pdb++.
All best,
Jamil
Hi,
I've been testing pdbp as a replacement for pdbpp whose pytest integration is broken in 3.11, but… it seems like so it pdbp's? At least a breakpoint()
gives me an
OSError: pytest: reading from stdin while output is captured! Consider using
-s
.
$ env PYTHONBREAKPOINT=pdbp.set_trace pytest tests/ui/test_ui_e2e.py
================================================================ test session starts ================================================================
platform darwin -- Python 3.11.5, pytest-7.4.2, pluggy-1.3.0
rootdir: /Users/hynek/Work/spot-svc
configfile: pyproject.toml
plugins: anyio-4.0.0, icdiff-0.8
collected 5 items
[31] > /Users/hynek/Work/spot-svc/tests/api/test_api_e2e.py(42)
..
34 def test_docs(aclient):
35 """
36 The docs are served if the client is authentificated.
37 """
38 resp = aclient.get("/")
39
40 breakpoint()
41
42 -> assert 200 == resp.status_code
(Pdb+)
----------------------------------------------------------------- Captured log call -----------------------------------------------------------------
INFO httpx:_client.py:1013 HTTP Request: GET http://localhost/api/ "HTTP/1.1 200 OK"
------------------------------------------------------------- Captured stdout teardown --------------------------------------------------------------
closing 'sqlalchemy.engine.base.Connection'
closed 'sqlalchemy.engine.base.Connection'
--------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------
DEBUG svcs:_core.py:347 closing 'sqlalchemy.engine.base.Connection'
[33] > /Users/hynek/Work/spot-svc/tests/api/test_api_e2e.py(42)
..
34 def test_docs(aclient):
35 """
36 The docs are served if the client is authentificated.
37 """
38 resp = aclient.get("/")
39
40 breakpoint()
41
42 -> assert 200 == resp.status_code
(Pdb+)
----------------------------------------------------------------- Captured log call -----------------------------------------------------------------
INFO httpx:_client.py:1013 HTTP Request: GET http://localhost/api/ "HTTP/1.1 200 OK"
------------------------------------------------------------- Captured stdout teardown --------------------------------------------------------------
closing 'sqlalchemy.engine.base.Connection'
closed 'sqlalchemy.engine.base.Connection'
--------------------------------------------------------------- Captured log teardown ---------------------------------------------------------------
DEBUG svcs:_core.py:347 closing 'sqlalchemy.engine.base.Connection'
DEBUG svcs:_core.py:349 closed 'sqlalchemy.engine.base.Connection'
============================================================== short test summary info ==============================================================
FAILED tests/api/test_api_e2e.py::test_docs - OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
=========================================================== 1 failed, 47 passed in 10.28s ===========================================================
I've tried importing pdbp in my contest.py instead of setting PYTHONBREAKPOINT
to the same result.
Has something changed again or am I missing something?
$ pip list | grep pdbp
pdbp 1.5.0
Currently, j
is still being used as a shortcut for the old pdb
code, instead of the new pdbp
code. (The code block right now is only displayed after a new pdbp
jump
.)
Is there a way to hide commands from command line history?
The background is that nvim-gdb is a frontend in neovim to Gdb and Pdb and it works with Pdbp too. It injects a break command invisibly between each interaction to update its state on breakpoints.
If there's a way to hide this from command history, nvim-gdb could make use of this. The annoyance is that this "break" shows up as the first item with up-arrow.
In a regression from 1.1.0
, https://github.com/mdmintz/pdbp/releases/tag/v1.1.0, a print()
line was removed that wasn't needed for sticky
mode (the default mode), but that line was needed for non-sticky mode so that you can see where you are in the debugger stack.
A note on sticky
mode: Type sticky
into the Pdb+ prompt to alternate between sticky mode (the default mode) and non-sticky mode. In sticky
mode, you should see several lines of code in the method you're in. In non-sticky mode, you should only see the current line of the active stack.
When running this code
import pdb
import pdbp
if hasattr(pdb, "DefaultConfig"):
pdb.DefaultConfig.current_line_color = None
pdbp.set_trace()
print("Correct line colour")
foo = {'a': 1}
try:
print(foo['b'])
except Exception:
print(foo['a'])
print("Wrong line colour")
The line colour is reset to the default value at the print(foo['a'])
line. The variable pdb.DefaultConfig.current_line_color
is however not reset.
trun
to toggle). In regular truncation mode, long lines are expected to get truncated to the width of the window.truncation
mode in sticky
modeIn non-truncation
sticky
mode, instead of all lines taking on the length of of the longest line (for consistent spacing caused by adding empty spaces to shorter lines), each line should just be the length of itself. This will keep the code more concise, and prevent a really long line from messing up the entire spacing for the code display.
The code for disabling pytest
capturing is out-of-date.
That code section was made for an earlier version of pytest
, and should be updated.
This issue probably wasn't noticed, as the old code was already in a try/except
block.
builtins
Eg. KeyError
is really builtins.KeyError
, but since it is part of builtins
, the builtins
part isn't necessary.
But in the case of NoSuchElementException
, show the full selenium.common.exceptions.NoSuchElementException
.
This can help reduce confusion, especially when different libraries have the same exception name:
Eg.
selenium.common.exceptions.NoSuchElementException
seleniumbase.common.exceptions.NoSuchElementException
An example of expected output in a full exception message:
seleniumbase.common.exceptions.NoSuchElementException:
Element {div#ARMY_OF_ROBOTS} was not present after 1 second!
Expected output from pdbp
Debug Mode:
[1] > /Users/michael/github/SeleniumBase/examples/test_fail.py(16)
..
12 @pytest.mark.expected_failure
13 def test_find_army_of_robots_on_xkcd_desert_island(self):
14 self.open("https://xkcd.com/731/")
15 print("\n(This test should fail)")
16 -> self.assert_element("div#ARMY_OF_ROBOTS", timeout=1)
seleniumbase.common.exceptions.NoSuchElementException:
Element {div#ARMY_OF_ROBOTS} was not present after 1 second!
(Pdb+)
I have determined the cause to be the bold highlighting around (Pdb+)
. That was done using ANSI escape sequences, but the original pdb
library is counting those bold ANSI escape sequences towards text length. The quick solution is to remove the bold highlighting.
Maybe it may make sense to add something in the README regarding the possiblity of registering pdbp using PYTHONBREAKPOINT="pdbp.set_trace"
as an alternative to importing pdbp in the source code?
Traversing through tracebacks or just moving along with the debugger via n
or s
can lead to the screen flickering after each console refresh. This can probably be reduced.
Add a truncate
debugger command to toggle between line-truncation modes.
When truncate
mode is enabled, long lines are truncated.
When truncate
mode is disabled, long lines are wrapped around to the next line. (The longest line determines the spacing.)
Colors should change based on status.
Eg.
Regular debug mode: Highlight the active line with blue.
Post Mortem debug mode: Highlight the active line with red.
The color of the return values could also change based on status.
Eg.
If in a stack trace, use red.
If returning True
, use green.
If returning False
/None
, use yellow.
If returning a number, use purple.
If returning anything else, use gray.
When in a pdb debugger session, a new session (e.g. calling an arbitrary function foo
) can be started with (Pdb+) debug foo()
.
However, this results in an error:
*** RecursionError: maximum recursion depth exceeded while calling a Python object
Currently, only sticky
mode (the default mode) has syntax-highlighting.
See seleniumbase/SeleniumBase#1623 for all the details.
As per our mini discussion in the tractor
matrix room:
https://matrix.to/#/!scerhxskQIIRMpggqm:matrix.org/$slaV-GyCnC5Bbt3-IDn41aDJGsMJ4xfZoiZznBY3GrQ?via=matrix.org&via=gitter.im&via=ancap.tech
It'd be handy to have a visual indicator of the current frame particularly when stepping through frames using u
/d
/f <frame#>
.
Currently there is a >
char prefix (which came from pdbpp
afaiu) but it'd nice to have something with a little more "pop" for the human eye too 😉
To give a visual eg. stepping through a bt in one of our multi-actor debugger scripts:
As you can see, it's kinda hard to notice the chevron by first glance.
The debugger edit
command opened more than just the active Python file.
In the description, it says that the edit
command is supposed to open the active file and put the cursor at the currently-active line, but instead, it opened the active file to the first line, and opened a new file that was named with the line number expected for the active file. It could be that some text editors supported the format of opening a file directly to a specific line, but since not all of them do, the edit
command should just open the active file, and then then user can manually go to the line number desired.
inspect <VAR>
has poor error-handling.
The debugger crashes if no is provided, or if giving a that isn't defined.
Default behavior is to print the full path to a source file, but this adds unnecessary information in most cases. I know that this is default behavior that is expected from pdb / pdbpp, but I'd love to be able to set a configuration to have pdbp find the root of the project and, if found, only report the path under root directory of a project.
From the picture on the main page I want to see:
> SeleniumBase/examples/test_mfa_login.py(9)
Maybe this would even be a reasonable default? Increasing signal to noise ratio when debugging always seems helpful to me.
After the changes are made in #35, it should be safe to make non-truncate
sticky
mode the default mode. The current default setting is truncate
with sticky
.
This will prevent missing important details when long lines are truncated. This will also make screen-resizing more feasible, as the display will automatically correct itself during a resize.
Balancing symmetry of "Documented" and "Undocumented" help commands.
Looking for rectangular-symmetry so that each row and column has the same number of help items.
For the next release, this is the expected output when typing help
into the debugger. Looks better.
(This will be the help
output when running with python -m pdbp <script.py>
. The one that appears from pytest
debug mode will be a bit different when using pdbp
, as pytest
changes available options for debug mode.)
All commands listed together:
The next pdbp
release should be coming soon.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.