I tried to define my own exception class in python 2.7, deriving from BaseException
.
class NestedCommentException(BaseException):
"""
Exception for nested comments
"""
def __init__(self, file_path, list_lines):
self.file_path = file_path
self.list_lines = list_lines
def __repr__(self):
return self.__str__()
def __str__(self):
return 'File {0} contains nested comments at lines {1}'.format(self.file_path, ', '.join(self.list_lines))
But when throwing it, it cannot be printed: raise NestedCommentException(file_path, list_lines)
triggers
Traceback (most recent call last):
File "D:\DATA\FP12210\My Documents\Outils\SVN\05_impl\2_tools\svn_tag_setup.py", line 85, in <module>
tag_checks()
File "D:\DATA\FP12210\My Documents\Outils\SVN\05_impl\2_tools\svn_tag_setup.py", line 66, in tag_checks
check_nested_comments(ddl_path)
File "D:\DATA\FP12210\My Documents\Outils\SVN\05_impl\2_tools\svn_tag_setup.py", line 54, in check_nested_comments
raise NestedCommentException(file_path, list_lines)
NestedCommentException: <unprintable NestedCommentException object>
Can you please explain why this happens, even if I defined __str__
and __repr__
methods ?
Catching Specific Exceptions in Python A try clause can have any number of except clauses to handle different exceptions, however, only one will be executed in case an exception occurs. We can use a tuple of values to specify multiple exceptions in an except clause. Here is an example pseudo code.
To create a User-defined Exception, we have to create a class that implements the Exception class. We can raise(throw) these exceptions using the raise keyword. These exceptions can be caught in the try-except block, just like common exceptions. In some conditions, we have multiple errors to handle in the same class.
When you see this thing, it basically means that some kind of exception has been raised in __str__()
of your object. So unless the problem is trivial enough to see at the first sight (e.g. forgotten "%s"), either
wrap the __str__
body in a try/except clause as Anurag advices, or
instantiate your exception and call the __str__
(or any methods you may have
overridden) manually, outside the traceback module, so that you get the full
description of the exception.
Actually this <unprintable MyException object>
can come from various functions in traceback module, which, when trying to get a string (i.e. "printable") version of a value (exception), it
calls str()
on it, and if anything goes wrong,
tries to treat it as unicode and convert it to ASCII, and if still anything goes wrong
simply prints the above representation.
Responsible code (same in 2.6 and 2.7):
def _some_str(value): try: return str(value) except Exception: pass try: value = unicode(value) return value.encode("ascii", "backslashreplace") except Exception: pass return '<unprintable %s object>' % type(value).__name__
As you can see, any exceptions coming from the str()
call or the unicode.encode()
call are ceased in the process and only the "cryptic" representation is given.
Contrary to what traceback
documentation tells us:
It exactly mimics the behavior of the Python interpreter when it prints a stack trace.
the representation given by Python interpreter is slightly different here. As opposed to the "unprintable" message, the interpreter would simply display the name of the exception, ceasing any actual exceptions as well.
Here is a simple script that demonstrates all three approaches: leaving the exception to Python interpreter, using traceback module, or calling the function by hand.
#!/usr/bin/python
import sys, traceback
class Boom(Exception):
def __init__(self, foo, bar, baz):
self.foo, self.bar, self.baz = foo, bar, baz
def __str__(self):
return ("boom! foo: %s, bar: %s, baz: " # ouch! forgot an %s!
% (self.foo, self.bar, self.baz))
def goBoom(): raise Boom(foo='FOO', bar='BAR', baz='BAZ')
if __name__ == "__main__":
if sys.argv[1].startswith("i"):
goBoom()
# __main__.Boom
elif sys.argv[1].startswith("t"):
try: goBoom()
except: traceback.print_exc(file=sys.stdout)
# Boom: <unprintable Boom object>
elif sys.argv[1].startswith("m"):
e = Boom(foo='FOO', bar='BAR', baz='BAZ')
e.__str__()
# TypeError: not all arguments converted during string formatting
else: pass
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