why `pdb` states something unrelated and misleading? - python

My Python script reports where it goes wrong ("line 122" in myscript.py), when I run it in a shell:
$ toc2others.py -i toc -p pg
Traceback (most recent call last):
File "~/myscript.py", line 122, in <module>
p = re.match(keywords[index+1][0], inlines[n+1], re.IGNORECASE)
IndexError: list index out of range
It is because keywords[index+1] goes out of the index range of keywords.
When I run it under pdb, however, it doesn't report where it goes wrong, but says something unrelated (error is reported to take place at import re).
$ pdb ~/myscript.py -i toc -p pg
> /myscript.py(3)<module>()
-> import re
(Pdb) c
Traceback (most recent call last):
File "/usr/lib/python2.7/pdb.py", line 1314, in main
pdb._runscript(mainpyfile)
File "/usr/lib/python2.7/pdb.py", line 1233, in _runscript
self.run(statement)
File "/usr/lib/python2.7/bdb.py", line 387, in run
exec cmd in globals, locals
File "<string>", line 1, in <module>
File "~/myscript.py", line 3, in <module>
import re
IndexError: list index out of range
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
I wonder why pdb states something unrelated and misleading?
Can pdb state where it actually goes wrong?
Thanks.

It's a bug, actually.
See issues:
http://bugs.python.org/issue16482
http://bugs.python.org/issue17277
This only happens if exception is thrown on module-level of executed file, i.e. not inside any function. So if you just put your code in a main() function, this will fix it. Or you can use ipython, which is much more fun for debugging:
ipython ~/myscript.py --pdb -- -i toc -p pg
This will run the script and only stop if there's an error, and it also does not suffer from the above bug.

Related

CS50 - debug50 isn't working after update

runoff/ $ debug50 ./runoff a b c
Launching VS Code debugger...
Traceback (most recent call last):
File "/usr/local/bin/debug50", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.10/site-packages/debug50/__main__.py", line 72, in main
asyncio.get_event_loop().run_until_complete(launch(args.PROGRAM, extra_args))
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/usr/local/lib/python3.10/site-packages/debug50/__main__.py", line 90, in launch
source = list(filter(lambda source_file: program in source_file, get_source_files(program)))[0]
IndexError: list index out of range
After I updated the web IDE for CS50, I keep getting this error whenever I try to launch debug50. I don't know what to do. It was working just fine.
Obs: I'm setting the breakpoints, I didn't miss this part.
I ran into this same issue. I'm wondering if an update to debug50 has been made. Here's how I got it to work.
Try omitting the ./ from your command line script, so long as you are in the directory containing your program.
e.g.
debug50 runoff a b c

Using pdb, how can I run a program and pause where reaching an error?

Using python interpreter and/or pdb, can we run a program and pause whenever reaching an error, so that I can examine all the frames of the call stack of the program at the time of crashing?
When I run a program directly inside python interpreter, when reaching an error, it tells where the line of code it happens, but it seems return to the topmost frame, and I can't examine the frame where the error actually happens. E.g.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 194, in <module>
addlevel(root_toc, 0)
File "test.py", line 191, in addlevel
addlevel(child, root_level+1)
File "test.py", line 188, in addlevel
root.value.append(root_level)
AttributeError: 'str' object has no attribute 'append'
>>> root_level
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'root_level' is not defined
The error happens at the lowest frame, and I can't examine the value of root_level at that frame. Is it because it returns to the topmost frame after the error happens? How can examine the lowest frame?
THanks.
Run pdb as a module, passing the script you want to debug. It will break on abnormal exits. (This is mentioned early in the docs.)
python -m pdb my_script.py
If you're in the interpreter, you can use pdb.pm() to debug the last traceback.
Or, use the IPython interpreter. Typing debug after an uncaught exception will enter a pdb session for the last traceback, similar to pm().

How can I make a shortcut to a module that runs unittest.main() and then allows the Python interpreter to remain open?

I am developing a package that uses unittest for its tests. The tests are all in a submodule called tests. At the bottom of the submodule is this:
if __name__ == '__main__':
unittest.main()
But if you run the module, Windows closes the command window before one can read the output. OK, this is not a new problem. There are ways around this, for example making a shortcut that looks something like:
cmd /k "python -m mypackage.tests"
This works, now you get to see the output. But then you are dumped back at the C:\Windows\System32 command prompt. It would be nicer to be able to still be in the Python interpreter, so that I can play around in Python if something occurs to me to check after I saw the tests. So you try something like this:
cmd /k "python -i -m mypackage.tests"
But, whoa, what's this? after the test output, you see
Traceback (most recent call last):
File "C:\Python33\lib\runpy.py", line 160, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "C:\Python33\lib\runpy.py", line 73, in _run_code
exec(code, run_globals)
File "D:\Docs\programs\python\mypackage\tests.py", line 274, in <module>
unittest.main()
File "C:\Python33\lib\unittest\main.py", line 125, in __init__
self.runTests()
File "C:\Python33\lib\unittest\main.py", line 267, in runTests
sys.exit(not self.result.wasSuccessful())
SystemExit: True
>>>
You are still in the Python interpreter, but now for some reason there are several lines of dumb noise in between the test results and the new prompt. No-one wants to see that. It is presumably because unittest.main() tries to exit the interpreter but the interpreter doesn't let it happen because you used the -i option. Which is good in a way, but the traceback isn't wanted.
You look at the documentation for unittest to see if there is a way to make Python stick around after running the tests. There are no command line switches for unittest that have this effect, but there is a keyword argument exit that could be used to prevent unittest from trying to close Python. So we could change the end of tests.py to this:
if __name__ == '__main__':
unittest.main(exit = False)
The problem with this is that sometimes you might want the default behaviour of closing the interpreter, like say if you had your version control software run the tests module automatically. So it would be best to have some way of conditionally disabling the exit. Well, it seems like by implementing a rudimentary check for command line options this could be done. So we try changing it to
if __name__ == '__main__':
import sys
unittest.main(exit = 'noexit' not in ''.join(sys.argv[1:]))
and the shortcut to
cmd /k "python -i -m mypackage.tests --noexit"
But now when you run it the tests don't even run, instead you see a big wall of complaints about how there's no option called "noexit":
Usage: tests.py [options]
tests.py: error: no such option: --noexit
Traceback (most recent call last):
File "C:\Python33\lib\optparse.py", line 1391, in parse_args
stop = self._process_args(largs, rargs, values)
File "C:\Python33\lib\optparse.py", line 1431, in _process_args
self._process_long_opt(rargs, values)
File "C:\Python33\lib\optparse.py", line 1484, in _process_long_opt
opt = self._match_long_opt(opt)
File "C:\Python33\lib\optparse.py", line 1469, in _match_long_opt
return _match_abbrev(opt, self._long_opt)
File "C:\Python33\lib\optparse.py", line 1674, in _match_abbrev
raise BadOptionError(s)
optparse.BadOptionError: no such option: --noexit
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python33\lib\runpy.py", line 160, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "C:\Python33\lib\runpy.py", line 73, in _run_code
exec(code, run_globals)
File "D:\Docs\programs\python\mypackage\tests.py", line 275, in <module>
unittest.main(exit = 'noexit' not in ''.join(sys.argv[1:]))
File "C:\Python33\lib\unittest\main.py", line 124, in __init__
self.parseArgs(argv)
File "C:\Python33\lib\unittest\main.py", line 148, in parseArgs
options, args = parser.parse_args(argv[1:])
File "C:\Python33\lib\optparse.py", line 1393, in parse_args
self.error(str(err))
File "C:\Python33\lib\optparse.py", line 1573, in error
self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg))
File "C:\Python33\lib\optparse.py", line 1563, in exit
sys.exit(status)
SystemExit: 2
Well I think I should be the one who decides what command line options there are, but maybe I haven't gone through the correct formalities to declare what command line options I'll accept. But actually, no, that isn't the case, because if I comment out the line that calls unittest.main():
if __name__ == '__main__':
import sys
#unittest.main(exit = 'noexit' not in ''.join(sys.argv[1:]))
then there is no complaining at all, just a >>> prompt! From which I can only deduce that unittest.main() is for some reason inspecting the command line arguments to my script, and throwing a hissy fit when they don't meet its standards - this despite the fact that they aren't directed at it in the first place. This wouldn't be so much of a problem if there were a command line switch that made it hang around instead of exiting (like the exit keyword argument does), but there isn't.
What's the answer? Every option seems unsatisfactory in one way or another.

Why this code doesn't work in parallel python

I tried to use pp(Parallel Python) like this:
import glob
import subprocess
import pp
def run(cmd):
print cmd
subprocess.call(cmd, shell=True)
job_server = pp.Server()
job_server.set_ncpus(8)
jobs = []
for a_file in glob.glob("./*"):
cmd = "ls"
jobs.append(job_server.submit(run, (cmd,)))
for j in jobs:
j()
But encountered such an error that subprocess.call is not a global name.
An error has occured during the function execution
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/pp-1.6.1-py2.7.egg/ppworker.py", line 90, in run
__result = __f(*__args)
File "<string>", line 3, in run
NameError: global name 'subprocess' is not defined
I've imported subprocess, why can't it be used here?
According to abarnert's suggestion, I changed my code to this:
import glob
import pp
def run(cmd):
print cmd
subprocess.call(cmd, shell=True)
job_server = pp.Server()
job_server.set_ncpus(8)
jobs = []
for a_file in glob.glob("./*"):
cmd = "ls"
jobs.append(job_server.submit(run, (cmd,),modules=("subprocess",)))
for j in jobs:
j()
But it still doesn't work, it complains like this:
Traceback (most recent call last):
File "/usr/lib/python2.6/threading.py", line 532, in __bootstrap_inner
self.run()
File "/usr/lib/python2.6/threading.py", line 484, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/local/lib/python2.6/dist-packages/pp-1.6.1-py2.6.egg/pp.py", line 721, in _run_local
job.finalize(sresult)
UnboundLocalError: local variable 'sresult' referenced before assignment
The documentation explains this pretty well, and each example shows you how to deal with it.
Among the params of the submit method is "modules - tuple with module names to import". Any modules you want to be available in the submitted job has to be listed here.
So, you can do this:
jobs.append(job_server.submit(run, (cmd,), (), ('subprocess',)))
Or this:
jobs.append(job_server.submit(run, (cmd,), modules=('subprocess',)))
Sorry, untested, but did you try:
from subprocess import call
Inside the 'run' function?
And then use "call" instead of "subprocess.call" ? That would make 'call' local to the function but accessible.

Python: Suppressing errors from going to commandline?

When I try to execute a python program from command line, it gives the following error. These errors do not cause any problem to my ouput. I dont want it to be displayed in the commandline
Traceback (most recent call last):
File "test.py", line 88, in <module>
p.feed(ht)
File "/usr/lib/python2.5/HTMLParser.py", line 108, in feed
self.goahead(0)
File "/usr/lib/python2.5/HTMLParser.py", line 148, in goahead
k = self.parse_starttag(i)
File "/usr/lib/python2.5/HTMLParser.py", line 226, in parse_starttag
endpos = self.check_for_whole_start_tag(i)
File "/usr/lib/python2.5/HTMLParser.py", line 301, in check_for_whole_start_tag
self.error("malformed start tag")
File "/usr/lib/python2.5/HTMLParser.py", line 115, in error
raise HTMLParseError(message, self.getpos())
HTMLParser.HTMLParseError: malformed start tag, at line 319, column 25
How could I suppress the errors?
Doesn't catching HTMLParseError work for you? If test.py is the name of your python file, it's propagated up to there, so it should.
Here's an example how to suppress such an error. You might want to tweak it a bit to match your code.
try:
# Put parsing code here
except HTMLParseError:
pass
You can also just suppress the error message by redirecting stderr to null, like Ignacio suggested. To do it in code, you can just write the following:
import sys
class DevNull:
def write(self, msg):
pass
sys.stderr = DevNull()
However, this is probably not be what you want, because from your error it looks like the script execution is stopped, and you probably want it to be continued.
Redirect stderr to /dev/null.
python somescript.py 2> /dev/null
In python 3, #Boaz Yaniv's answer can be simplified as
sys.stderr = object
since every class in python3 is inherited from Object, so technically this would work, at least I've tried it by myself in python 3.6.5 environment.
Here is a more readable, succinct solution for handling errors that are safe to ignore, without having to resort to the typical try/except/pass code block.
from contextlib import suppress
with suppress(IgnorableErrorA, IgnorableErrorB):
do_something()

Categories

Resources