In python versions before PEP 553 breakpoint()
utility, what is the recommended way to add (ideally a one-liner) code to have a breakpoint that can be ignored upon a condition (e.g. a global debug flag or args.debug flag).
In Perl, I am used to use $DB::single=1;1;
single-lines, which I know I can safely leave in the code and won't affect the normal running of perl code.pl
unless explicitly calling perl -d code.pl
. E.g.:
my $a = 1;
$DB::single=1;1; # breakpoint line
my $b = 2;
print "$a $b\n";
If I run this code as: perl code.pl
, it will run to completion.
If I run this code with: perl -d code.pl
, the pdb
will stop at the breakpoint line (not before the next line with a my $b = 2;
statement) because it contains a 1;
statement after the $DB::single=1;
statement;
Similarly, if I write:
my $debug = 1;
my $a = 1;
$DB::single=$debug;1; # first breakpoint line
my $b = 2;
$DB::single=$debug;1; # second breakpoint line
print "$a $b\n";
# [...] Lots more code sprinkled with more of these
$DB::single=$debug;1; # n'th breakpoint line
I can then execute perl -d code.pl
, which will stop in the first breakpoint line, then in the pdb
session, once I am happy that it does not need stopping anywhere else, then execute: $debug = 0
, then pdb
continue c
, which will make it not stop at the second or other similar breakpoint lines in the code.
How can I achieve the same, ideally in single-line statements, in python (2.x and 3.x before PEP 553)?
I am aware of PEP 553 and apart from the hassle of having to explicitly set PYTHONBREAKPOINT=0 python3.7 code.py
or comment out the breakpoint()
lines, it is a solution to the question here.
I thought of options like:
import pdb; pdb.set_trace()
dummy=None;
The statement underneath pdb.set_trace()
is so that I can achieve the same as the 1;
in the same line after $DB::single=1;
in Perl, which is to have the debugger stop where I placed the breakpoint, rather than the next statement. This is so that if there are large chunks of commented code or documentation in-between, the debugger does not jump to the next statement far away from the breakpoint.
Or with conditionals like:
if args.debug or debug:
import pdb; pdb.set_trace()
_debug=False; #args.debug=False
So that if I am done debugging for a script, I can set args.debug=False
or debug=False
and not have to touch all these breakpoints in the code.
Python breakpoint() - Stop Debugging Python sys. breakpointhook() function uses environment variable PYTHONBREAKPOINT to configure the debugger. If unset, the default PDB debugger is used. If it's set to “0” then the function returns immediately and no code debugging is performed.
It's easy to set a breakpoint in Python code to i.e. inspect the contents of variables at a given line. Add import pdb; pdb. set_trace() at the corresponding line in the Python code and execute it. The execution will stop at the breakpoint.
To set a conditional breakpointOn the Home tab, in the Breakpoints group, choose Set/Clear Condition. In the Debugger Breakpoint Condition window, enter a condition. On the Home tab, in the Breakpoints group, choose List. In the Debugger Breakpoint List window, enter a condition in the Condition column.
Starting Python Debugger To start debugging within the program just insert import pdb, pdb. set_trace() commands. Run your script normally, and execution will stop where we have introduced a breakpoint. So basically we are hard coding a breakpoint on a line below where we call set_trace().
Same as perl, python can be run with -d
to set a debug flag:
$ python --help
[...]
-d : debug output from parser; also PYTHONDEBUG=x
[...]
You can check its state during runtime via sys.flags
:
$ python -d
Python 2.7.15+ (default, Nov 27 2018, 23:36:35)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.flags
sys.flags(debug=1, py3k_warning=0, division_warning=0, ...)
# ^ there it is, right at the front
Which allows for the following one-liner to enable debugging:
import pdb, sys; pdb.set_trace() if sys.flags[0] else None
Regarding this part
[...] once I am happy that it does not need stopping anywhere else, then execute [something] which will make it not stop at the second or other similar breakpoint lines in the code.
it gets a little trickier though, since python doesn't allows mutation of the flags
structure, or even creating an instance of it:
>>> import sys
>>> sys.flags.debug = 0 # no mutating ...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
>>> type(sys.flags)() # ... and no instanciating
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: cannot create 'sys.flags' instances
But as far as I have tested, unless you run python with other flags, the following works to deactivate subsequent traces without altering your program's other behavior:
import sys; sys.flags = [0]*len(sys.flags) # even fits onto a single line
For a slightly more robust monkey patch that you should use in case the former one leads to strange bugs, you'll need to have something like this:
def untrace():
"""Call this function in the pdb session to skip debug-only set_trace() calls"""
import re
import sys
from collections import namedtuple # has the same interface as struct sequence
sys.flags = namedtuple(
'sys_flags',
[m.group() for m in re.finditer(r'\w{2,}', repr(sys.flags)[10:-1])]
)(0, *sys.flags[1:])
While this statement can be put on a single line, it's probably a little too much. You can either paste this function into the .py
file where you plan to use it, or have some kind of utils.py
from which you import it during debugging, after which a c(ontinue) should again run the rest of the program:
(Pdb) import utils; utils.untrace()
(Pdb) c
Here is a simple way using a .pdbrc
file in the current directory:
t.py
def my_trace():
global debug
if debug:
import pdb; pdb.set_trace()
debug = True
a= 1
my_trace()
b = 2
c = 3
my_trace()
d = 4
.pdbrc:
r
Example session:
$ python t.py
--Return--
> [...]/t.py(12)<module>()
-> b = 2
(Pdb) p a
1
(Pdb) p b
*** NameError: name 'b' is not defined
(Pdb) !debug=False
(Pdb) c
$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With