I am trying to step through a python script for some code I wrote over a year ago. The way I recall, when you write a pdb.set_trace() line, the program will halt its execution at that point and print the next line that will be executed. Entering 'n' or 's' will advance the execution by a line (and maybe step into a function, not too relevant to my problem) AND print the next line to be executed again.
Now, I have one program "example1.py" and it is not printing the next statement to be executed. I just get some output like the following
./example1.py
> /home/some/example1.py(44)create()
(Pdb) s
> /home/some/example1.py(45)create()
(Pdb) s
--Call--
> /home/some/example1.py(90)parse()
But when I try this same thing with a different python program, "example2.py", one that I wrote more recently I am getting the output I expect (the next statement to be executed.)
> /home/some/example2.py(86)random_update()
-> DATE_LIMIT=1
(Pdb) n
> /home/some/example2.py(87)random_update()
-> FILE_LIMIT=120
(Pdb) n
> /home/some/example2.py(89)random_update()
-> n_dates=0
I have no idea what could be a possible cause for this. Could import statements interfere with pdb's execution?
UPDATE:
So I set my trace breakpoint before changing to a directory that is outside my home directory. When I do this, I get the output that I expect. I noticed that this directory's group owner was root so I changed it to my user. This didn't resolve my problem, but now I know it has to do with the program execution location.
I figured it out. If I set my trace before a line that changes the current directory to a directory where the program is not located, I was getting the output I expected. Once I set the trace after this directory change, I was no longer getting statement execution output.
To resolve this, I executed the program with a full path
python /home/name/home/some/example1.py
Related
I have Python 3.8(32-bit) installed, and I am using Atom to write my attempts and then copy-pasting them into the Python terminal.
The following code is copied directly from the very beginning of an introductory Python course I am taking "for fun":
n = 5
while n > 0:
print(n)
n=n-1
print('Blastoff!')
The code works in every sandbox I can find, and the last line works on its own in my terminal. But when I copy it to my terminal, I get an invalid syntax error that points to the word print. I can fix this and get the desired output by changing my code to:
n = 5
while n > 0:
print(n)
n=n-1
else:
print('Blastoff!')
But I have three issues with this:
Why does my original code not work, as it is copied directly from the course?
I need to hit Enter twice after copying in that second block of code for it to run. Why is that?
Why does Atom insist on indenting the last print farther than my other indents?
Here is what I am seeing when entering my first code brick:
>>> n = 5
>>> while n > 0:
... print(n)
... n=n-1
... print('Blastoff!')
File "<stdin>", line 4
print('Blastoff!')
^
SyntaxError: invalid syntax
Since you're entering code into the Python interpreter, it'll interpret the code line-by-line. This is great for quick tests and checks, but for larger code, you'll want to run an entire file.
You can achieve this a couple different ways:
Running it from the command prompt/terminal. If your Python executable is in your PATH, you can open a command prompt and navigate to your file and run python myfile.py. See "How to add Python to Windows PATH".
If you've installed Python from python.org, you may have IDLE installed. You can run the IDLE application and open your file from the menu File > Open. From there, you can run the file from the menu Run > Run Module.
I'd suggest the second option since you are learning and it will help you focus on coding instead of fighting your code environment. However, feel free to revisit option #1 in the future. It is definitely helpful to know your way around the command line (if you work on a machine without IDLE installed, this would be the proper way to run Python files).
Also "How to Run Your Python Scripts" is a great resource for learning more about how running scripts in Python works.
I have a code separated into three modules; the modules are the following:
1) run_module.py
2) module1.py
3) module2.py
I have an if name == 'main': statement inside run_module.py and I am very comfortable using my CLI to do python -b pdb run_module.py and then set a breakpoint inside run_module.py using the (pdb) b linenumber format.
My question is this: How can I set breakpoints inside module1.py or module2.py from the CLI; ie. not intervening directly into the module1.py and module2.py scripts and typing import pdb; pdb.set_trace()?
Any insight would be extremely appreciated. Many thanks in advance.
pdb, like gdb, or trepan3k has a break command:
(Pdb) help break
b(reak) ([file:]lineno | function) [, condition]
With a line number argument, set a break there in the current
file. With a function name, set a break at first executable line
of that function. Without argument, list all breaks. If a second
argument is present, it is a string specifying an expression
which must evaluate to true before the breakpoint is honored.
The line number may be prefixed with a filename and a colon,
to specify a breakpoint in another file (probably one that
hasn't been loaded yet). The file is searched for on sys.path;
the .py suffix may be omitted.
But when you do this there are some things you should be aware of.
If you specify breakpoints by filename and line number, it is possible to get a error message. For example:
(Pdb) break foo.py
*** The specified object 'foo.py' is not a function or was not found along sys.path.
Let's try to understand what the message says. foo.py clearly isn't a function. It is a file. Is it in sys.path?
(Pdb) import sys
(Pdb) sys.path
['', '/usr/lib/python3.6', ...]
No. Ok. well how about if I give the file name as an absolute path?
(Pdb) break /tmp/bug.py:2
Breakpoint 1 at /tmp/bug.py:2
Ok. That works. But again there is a caveat: is it possible to stop at at that line in that file? Watch this:
(Pdb) break /etc/hosts:1
Breakpoint 2 at /etc/hosts:1
/etc/hosts is a file, but it is not a Python program. And while as we saw before pdb warns if the file is missing, it doesn't check whether the file is a Python file.
If instead you run this with trepan3k it prints out a nasty traceback (which I'll fix at some point), but at least it gives some inkling that something is wrong:
(Nasty traceback)...
ValueError: path /etc/hosts must point to a Python source that can be compiled, or Python bytecode (.pyc, .pyo)
[The traceback has been removed in the github source and will not appear in version 1.2.9. In version 1.2.8 of trepan2 this is gone too.]
Also pdb isn't that smart about knowing whether line 2 has code that can be stopped at; pdb will warn about empty or blank lines or lines comment lines, but anything more sophisticated than that, like some random text, and no dice.
Again trepan3k is a little better about this:
(trepan3k) break /tmp/bug.py:2
** File /tmp/bug.py is not stoppable at line 2.
The last caveat when working with breakpoints is that a breakpoint might not be hit because the code never gets there. But you have this also with sys.set_trace() so I imagine that kind of behavior is less of a surprise.
One other difference of note between the breakpoints of trepan3k and pdb. In pdb when you breakpoint on a function, you are really setting breakpoint on the first line recorded for that function. That is, you have already entered the function.
In trepan3k you are setting it on the function call which is independent of where it is located. Note the different syntax for functions, they have trailing parenthesis after the name, e.g. foo() vs foo.
A method name given in the context of the object is is a method of is also possible, and I use that a lot. Here is an example:
trepan3k /tmp/pathtest.py
(/tmp/pathtest.py:1): <module>
-> 1 from pathlib import Path
(trepan3k) n
(/tmp/pathtest.py:2 #12): <module>
-- 2 mypath = Path(__file__)
(trepan3k) n
(/tmp/pathtest.py:3 #20): <module>
-- 3 print(mypath.match("p.*"))
(trepan3k) break mypath.match()
Breakpoint 1 set at line 972 of file /home/test/.pyenv/versions/3.8.10/lib/python3.8/pathlib.py
(trepan3k) c
(/home/test/.pyenv/versions/3.8.10/lib/python3.8/pathlib.py:972): match
xx 972 def match(self, path_pattern):
(trepan3k) path_pattern
'p.*'
(trepan3k) info pc
PC offset is -1.
I'm working on a Python project, and I've been using the VS Code Python debugger frequently, using breakpoints or just using the step over/into tool to understand how my code executes.
After making some changes to a single Python file, the debugger started behaving strangely. While the script itself is executing as expected (based on logs and expected side effects), when I step through the script with the debugger it skips over lines that clearly are being executed, and stops on lines that clearly are not being executed.
For example, after setting an early breakpoint and using only "Step Over" to navigate through the execution of my script, the debugger highlighted the following lines, individually in sequence:
An if statement (normal [expected to resolve as true based on variable values])
Each line of the if block (normal)
The first line of the corresponding else block (not normal)--without stopping on the else statement itself (also not normal)
The second line of a try block, without stopping on the try statement itself, or on the first line of the try block (not normal)--and without stopping on any of the other lines in the above else block
... (many more lines)
The second line of an if block, for which the if statement resolved to false, without stopping on the if statement itself or on the first line of the if statement (not normal)
The second line of a finally block, without stopping at the else statement or else block corresponding to the above statement(not normal)--or on the finally line itself, or on the first line of the finally block (not normal)
Again, I can clearly tell this is not how the code is executing. Referring to steps 5 and 6 above: the code generates an email as coded in the else case, and does not generate an email as coded in the if case.
If I revert the file to its previous state, the debugger behaves normally. Using git diff, I can tell there are no differences in blocking, parentheses, whitespace, etc. between the previous version and this one.
Am I missing something? I don't believe I ever had this issue before.
I don't understand how changing the code would change the behavior of the debugger
This issue renders the debugger essentially useless for my intention of understanding the behavior of my code.
I'll try to explain, let's suppose you've the code:
1 if True:
2 if False:
3 a = 1
4 else:
5 b = 2
6 try:
7 c = 3
Then you run Python with debugger, it stops on 1st line.
Next you remove 2nd line in IDE and got actual code:
1 if True:
2 a = 1
3 else:
4 b = 2
5 try:
6 c = 3
Many frameworks uses watchdogs in development mode to autoreload project when source files changed (also some debuggers could do that on-the-fly for specific changed module). But if your edit doesn't trigger reloading of Python you've got situation where script executes lines in order:
1 (if True)
2 (if False)
4 (else)
6 (try)
and IDE will stops on these lines but with wrong statements:
1 (if True)
2 (a = 1)
4 (b = 2)
6 (c = 3)
I was seeing the exact same problem (lines appearing to be skipped during debug, etc.), probably caused by ptvsd not working with the actual up-to-date source file. I've managed to work around this by adding the following to my workspace settings, which disables an experiment:
"python.experiments.optOutFrom": [
"PtvsdWheels37 - experiment"
],
Without the above workaround, the problem occurs sporadically for me -- I haven't been able to pin down exactly when it occurs. I've created the issue https://github.com/microsoft/vscode-python/issues/11716 on this.
Is it possible to run code line by line with Python.
Including running any module code, when used, line by line as well.
I would like to go out and run some code line by line and watch as each of the lines goes through the processing phase and see just what code is getting executed when certain actions occur. I'm curious how certain values are getting passed off to the interpreter.
Just use python -m pdb mycode.py, which will run your code in the python debugger (pdb module).
In the debugger you can execute arbitrary code, watch variables, and jump to different places in the code. Specifically, n will execute the next line and h will show you the debugger help.
To add a breakpoint you can use pdb inline:
import pdb; pdb.set_trace()
From this line bleow you can go step by step and you can enter inside every called function (with s) or jump function execution (with n).
Also, a good tip is to use ipdb instead of pdb because it knows autocomplete (it's an ipython prompt)
I'd like to save the commands for a breakpoint in a .pdbrc, something like:
b 81
commands 1
pp foo.attr1
pp foo.attr2
end
b 108
commands 2
pp bar.attr1
pp bar.attr2
end
This would automate setting the environment for the debugging session. However, this does not work with python -m pdb script.py, because at the line commands 1, the pdb prompt starts and asks me for the commands for the first breakpoint, ignoring what I wrote in .pdbrc; further, it raises a NameError after I type end at the pdb prompt, because of foo.attr1, foo.attr2 and even end. The same happens for the rest of the breakpoints, so I end up with them set but not their commands.
What would be the correct way to do this? Is it even possible?
You probably don't want this set every time you use pdb anywhere. My recommendation would be to set up an alias, such as:
alias setup_myproj b 81;; commands 1;; pp foo.attr1;; pp foo.attr2;; end
Then you can run setup_myproj when appropriate.
My first thought was that the command must be defined on one line:
commands 1;; pp foo.attr1;; pp foo.attr2;; end;;
However, it appears that this will only work at the prompt, and you will incorrectly get:
Usage : commands [bnum]
...
end
if you place the line above in a .pdbrc
Looking at pdb.py it appears that the author does not properly handle defining commands in a pdbrc.
I personally would just temporarily place the print lines in the code I was debugging while using pdbrc to save the breakpoints of interest to get around this.
More than ten years later, but, unfortunately, it looks like pdb still does not properly handle the end command when reading commands from a .pdbrc file. There's now a related issue for cpython.
In the meantime, for simple control flows, it may be possible to work around the issue, simply by not using the commands command. For example, you could do:
# set the breakpoints
b 81
b 108
# continue to the first breakpoint
continue
# execute commands at first breakpoint
pp foo.attr1
pp foo.attr2
# continue to the second breakpoint
continue
# execute commands at second breakpoint
pp bar.attr1
pp bar.attr2
...
Obviously this only works in simple cases where you know which breakpoint will be reached next.