python unittest error raised by submodule - python

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 ...

Related

Running `python -m unittest` changes the way exceptions with overriden `__name__` are printed in the traceback

I have a piece of code that dynamically creates Exceptions. Every exception class created in this way gets its __name__ overwritten:
def exception_injector(name, parent, module_dict):
class product_exception(parent):
pass
product_exception.__name__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
When I use it regularly it prints everything out just fine:
>>> namespace = {"__name__": "some.module"}
>>> exception_injector("TestError", Exception, namespace)
>>> raise namespace["TestError"]("What's going on?")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
some.module.TestError: What's going on?
But when I use the unittest module the original __name__ is printed:
>>> import unittest
>>> class DemoTestCase(unittest.TestCase):
... def test_raise(self):
... namespace = {"__name__": "some.module"}
... exception_injector("TestError", Exception, namespace)
... namespace["TestError"]("What's going on?")
...
>>> unittest.main(defaultTest="DemoTestCase", argv=["demo"], exit=False)
E
======================================================================
ERROR: test_raise (__main__.DemoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 3, in test_raise
some.module.exception_injector.<locals>.product_exception: What's going on?
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
<unittest.main.TestProgram object at 0x1017c3eb8>
From where on the exception object could the unittest module be getting this original information?
Unittests use the traceback module to format exceptions. You can reproduce your output by doing the same:
>>> import traceback
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.exception_injector.<locals>.product_exception: What's going on?
What is being printed is the object __module__ attribute value*, with object.__qualname__ attribute appended (with a dot separator), rather than __module__ plus __name__:
>>> namespace["TestError"].__qualname__
'exception_injector.<locals>.product_exception'
The qualified name includes the full scope where the class was created (function names here, but this could also include class names).
If your aim is to add exceptions to the global namespaces of a module, you can just set it to the same value as name:
>>> namespace["TestError"].__qualname__ = "TestError"
>>> try:
... raise namespace["TestError"]("What's going on?")
... except Exception as e:
... tb = traceback.TracebackException.from_exception(e)
... print(*tb.format())
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
some.module.TestError: What's going on?
or in the context of your code:
def exception_injector(name, parent, module_dict):
class product_exception(parent, details=args):
pass
product_exception.__name__ = name
product_exception.__qualname__ = name
product_exception.__module__ = module_dict["__name__"]
module_dict[name] = product_exception
* The traceback module omits the exception module if the module name is either __main__ or builtins.

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

Python exception class not defined, no attribute

I am currently using pytesseract which defines an exception class as follows:
class TesseractError(Exception):
def __init__(self, status, message):
self.status = status
self.message = message
self.args = (status, message)
in my main.py, I tried several ways to use this exception for exception handling but I've gotten no "TesseractError" attribute error and no "TesseractError" defined error.
1.
>>> from pytesseract import TesseractError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'TesseractError'
2.
>>> import pytesseract
>>> try: raise pytesseract.TesseractError(True,"True")
... except TesseractError: print("error")
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'pytesseract' has no attribute 'TesseractError'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'TesseractError' is not defined
3.
>>> import pytesseract
>>> try: raise TesseractError(True,"True")
... except TesseractError: print("error")
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'TesseractError' is not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'TesseractError' is not defined
However, when I try the following in terminal, it just works.
>>> class ERR(Exception): pass
>>> try: raise ERR()
... except ERR: print("error found")
error found
so it seems it's the importing step is wrong but I don't know what caused it.
Here's the __init__ file:
https://github.com/madmaze/pytesseract/blob/master/src/init.py
Notice that it does not import the TesseractError to be visible from the package itself. You could either change the init file or import from the package>module>
from pytesseract.pytesseract import TesseractError

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...

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

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'

Categories

Resources