Does Python traceback.print_exc() prints to stdout or stderr? - python

I've read some Python docs, but I can't find where the print_exc function prints. So I searched some stack overflow, it says "print_exc() prints formatted exception to stdout". Link
I've been so confused.. In my opinion, that function should print to stderr because it's ERROR!.. What is right?

It prints to stderr, as can be seen from the following test:
$ cat test.py
try:
raise IOError()
except:
import traceback
traceback.print_exc()
$ python test.py
Traceback (most recent call last):
File "test.py", line 2, in <module>
raise IOError()
IOError
$ python test.py > /dev/null
Traceback (most recent call last):
File "test.py", line 2, in <module>
raise IOError()
IOError
$ python test.py 2> /dev/null
$

BTW you can also control it:
import traceback
import sys
try:
raise Exception
except Exception as E:
traceback.print_exc(file=sys.stderr)

According to the python documentation states "If file is omitted or None, the output goes to sys.stderr; otherwise it should be an open file or file-like object to receive the output."
This means you can control how / where the output is printed.
with open(outFile) as fp
print_exc(fp)
The above example will print to the file 'outFile'

Related

python unittest error raised by submodule

MyModule.py
import uno
class MyModule():
def myModuleMethode(self. args):
try:
uno.callMethod(args)
except NoSuchElementException:
return "error string"
test_mymodule.py
import my_module
import unittest
# unittest setup
def test_MyModuleMyModuleMethod(self):
with self.assertRaises(NoSuchElementException) as cm:
MyModuleMethod(make, sure, the, method, call, fails, with, these, params)
self.assertEqual(str(cm.exception), "error string")
the interpreter spits out:
>>> MyModuleMethod(make, sure, the, method, call, fails, with, these, params)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.NoSuchElementException
and running the test file from konsole, it returns:
Me#MyPrecious:$ python -m unittest -v test_mymodule
testmumblemumble:ERROR
ERROR: mumbledemumbling_moremublemumbelin_test (mymodule_test.MyModuleTest)
Traceback (most recent call last): File "/home/path/to/where/lib/python3/site-packages/MyModyle/test/mymodule_test.py",
line 207, in test_MyModuleMyModuleMethod
with self.assertRaises(NoSuchElementException) as cm: NameError: name 'NoSuchElementException' is not defined
The issue and question is that the uno module spits out an internally defined exception, and I cannot seem to catch it ...

How can I print the traceback and exception of a zmq.REQ worker?

I'm using pexpect.spawn to write some script that can run in parallel.
But I found that the traceback and exception of a zmq.REQ worker won't be printed out in the terminal where I run the master.py (zmq.REP).
I know sys.stderr can be used to redirect the traceback and exception, but I have no idea how should I use this in the worker.py so that the exceptions happen in worker.py can be printed out.
Use logging.exception and log into a file.
Example:
import logging
logging.basicConfig(filename='example.log')
def fail():
return 10/0
try:
fail()
except Exception as err:
loggin.exception(err)
Output (example.log) :
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
File "<ipython-input-4-d63f4b56d991>", line 2, in <module>
fail()
File "<ipython-input-3-edce7c179301>", line 2, in fail
return 10/0
ZeroDivisionError: integer division or modulo by zero

Why does the Python linecache affect the traceback module but not regular tracebacks?

Consider the following Python program:
code = """
def test():
1/0
"""
filename = "<test>"
c = compile(code, filename, 'exec')
exec(c)
import linecache
linecache.cache[filename] = (len(code), None, code.splitlines(keepends=True), filename)
import traceback
print("Traceback from the traceback module:")
print()
try:
test()
except:
traceback.print_exc()
print()
print("Regular traceback:")
print()
test()
I am dynamically defining a function that raises an exception and adding it to the linecache. The output of the code is
Traceback from the traceback module:
Traceback (most recent call last):
File "test.py", line 20, in <module>
test()
File "<test>", line 3, in test
1/0
ZeroDivisionError: division by zero
Regular traceback:
Traceback (most recent call last):
File "test.py", line 28, in <module>
test()
File "<test>", line 3, in test
ZeroDivisionError: division by zero
If I then get a traceback from that function using the traceback module, the line of code from the function is shown (the 1/0 part of the first traceback). But if I just let the code raise an exception and get the regular traceback from the interpreter, it doesn't show the code.
Why doesn't the regular interpreter traceback use the linecache? Is there a way to make the code appear in regular tracebacks?
The default sys.excepthook uses a separate, C-level implementation of traceback printing, not the traceback module. (Perhaps this is so it still works even if the system is too borked to use traceback.py.) The C implementation doesn't try to use linecache. You can see the code it uses to retrieve source lines in _Py_DisplaySourceLine.
If you want tracebacks to use the traceback module's implementation, you could replace sys.excepthook with traceback.print_exception:
import sys
import traceback
sys.excepthook = traceback.print_exception

traceback.print_exc() shows incomplete stack trace

The traceback module is great for capturing and handling exceptions, but in the following example it seems to capture an incomplete stack from the most recent exception.
Consider two files, one say "mymod.py":
import sys, traceback
def func():
try:
otherfunc()
except:
raise
#traceback.print_exc()
def otherfunc():
raise Exception( 'fake' )
And another one say "myfile.py":
from mymod import *
func()
Running myfile.py gives:
Traceback (most recent call last):
File "myfile.py", line 2, in <module>
func()
File "/Users/rrdrake/temp/mymod.py", line 5, in func
otherfunc()
File "/Users/rrdrake/temp/mymod.py", line 11, in otherfunc
raise Exception( 'fake' )
Now change mymod.py to comment out the "raise" and uncomment the print_exc line. Then we get
Traceback (most recent call last):
File "/Users/rrdrake/temp/mymod.py", line 5, in func
otherfunc()
File "/Users/rrdrake/temp/mymod.py", line 11, in otherfunc
raise Exception( 'fake' )
Exception: fake
Notice that print_exc() does not include the myfile.py frame while re-raising does. How can I make print_exc() include the origin calling frame?
Note that if I add a traceback.print_stack() in the except block, it does include the myfile.py frame, so the information seems to be available.
In your first case, the exception from your raise call bubbles up at the top level of the script. Python calls sys.excepthook(), which displays the full traceback.
In your second case, the exception is caught and print_exc() is used to print the exception, and this stops at the calling function (otherfunc() in your case) so you don't get the full traceback.
You can change that by using your own traceback/exception print function,
something along those lines:
def print_full_stack(tb=None):
if tb is None:
tb = sys.exc_info()[2]
print 'Traceback (most recent call last):'
for item in reversed(inspect.getouterframes(tb.tb_frame)[1:]):
print ' File "{1}", line {2}, in {3}\n'.format(*item),
for line in item[4]:
print ' ' + line.lstrip(),
for item in inspect.getinnerframes(tb):
print ' File "{1}", line {2}, in {3}\n'.format(*item),
for line in item[4]:
print ' ' + line.lstrip(),
Just replace traceback.print_exc() with print_full_stack(). This function involves the inspect module to get code frames.
You can read this blog for much more information: http://blog.dscpl.com.au/2015/03/generating-full-stack-traces-for.html
Beware, the code in the above article has some indentation errors...

stdout Won't Flush After Exception

I have the following Python code:
import sys
import traceback
fifo_in = sys.argv[1]
while 1:
try:
exec open(fifo_in)
except:
traceback.print_exc()
sys.stdout.flush()
The first argument is a named pipe created by mkfifo. So the following prints '1':
mkfifo input
python script.py input
... in a separate terminal ...
echo "print 1" > input
Great, so far so good. But when I do something like echo "foobar" > input, the script only prints part of the traceback. It then pauses until I send it another command, and the output gets all mixed up:
echo "asdf" > input # pause here and check output
echo "print 1" > input
... in output terminal ...
Traceback (most recent call last):
File "test.py", line 8, in <module>
exec open(fifo_in)
File "in", line 1, in <module>
...PAUSES HERE...
print 1
NameError: name 'asdf' is not defined
What's going on? How can I get stdout to flush fully and why is it out of order? I've tried using traceback.format_exc instead, then printing it by hand, but I get the same result. Calling sys.stderr.flush does not fix anything either. I've also tried putting a sleep in the loop to see if that helps, but nothing.
UPDATE
One interesting piece of behavior I am seeing: If I ctrl+c it, normally the program keeps running - the try/except just catches the KeyboardInterrupt and it keeps looping. However, if I ctr+c it after sending it an error, the program exits and I get the following. It's almost like it pauses inside of print_exc:
^CTraceback (most recent call last):
File "test.py", line 10, in <module>
traceback.print_exc()
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
line = linecache.getline(filename, lineno, f.f_globals)
File "/usr/lib/python2.7/linecache.py", line 14, in getline
lines = getlines(filename, module_globals)
File "/usr/lib/python2.7/linecache.py", line 40, in getlines
return updatecache(filename, module_globals)
File "/usr/lib/python2.7/linecache.py", line 132, in updatecache
with open(fullname, 'rU') as fp:
KeyboardInterrupt
I think you want to look at the stdlib code module
This behavior is from using exec. Exec is for evaluating python code so "print 1" executes the python code print 1, where as "asdf" will raise a NameError as it does not exist in the context. exec open(fifo_in) is strange as it shouldn't work. The while will also eat up 100% cpu.
UPDATE: fix sleep duration
Here is a modified version of your code to try.
import sys
import time
import traceback
fifo_in = sys.argv[1]
try:
fp = open(fifo_in) # will block until pipe is opened for write
except IOError:
traceback.print_exc()
except OSError:
traceback.print_exc()
data = None
while True:
try:
data = fp.read()
try:
exec data
except:
traceback.print_exc()
finally:
time.sleep(0.1)
except KeyboardInterrupt:
break

Categories

Resources