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 ?
TL;DR
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.
Analysis
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.
Note on traceback module vs. Python interpreter
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
My guess is that you have unicode in file_path or list_lines variables dues to which it is not being printed on a console without unicode capabilities.
or any other exception in __str__ can cause such strange behavior, best way is to catch exception and see whats is happening, use debugger too
def __str__(self):
try:
s = 'File {0} contains nested comments at lines {1}'.format(self.file_path, ', '.join(self.list_lines))
except Exception,e:
print "-----",type(e),e
return s
Related
some_function() raises an exception while executing, so the program jumps to the except:
try:
some_function()
except:
print("exception happened!")
How do I see what caused the exception to occur?
The other answers all point out that you should not catch generic exceptions, but no one seems to want to tell you why, which is essential to understanding when you can break the "rule". Here is an explanation. Basically, it's so that you don't hide:
the fact that an error occurred
the specifics of the error that occurred (error hiding antipattern)
So as long as you take care to do none of those things, it's OK to catch the generic exception. For instance, you could provide information about the exception to the user another way, like:
Present exceptions as dialogs in a GUI
Transfer exceptions from a worker thread or process to the controlling thread or process in a multithreading or multiprocessing application
So how to catch the generic exception? There are several ways. If you just want the exception object, do it like this:
try:
someFunction()
except Exception as ex:
template = "An exception of type {0} occurred. Arguments:\n{1!r}"
message = template.format(type(ex).__name__, ex.args)
print message
Make sure message is brought to the attention of the user in a hard-to-miss way! Printing it, as shown above, may not be enough if the message is buried in lots of other messages. Failing to get the users attention is tantamount to swallowing all exceptions, and if there's one impression you should have come away with after reading the answers on this page, it's that this is not a good thing. Ending the except block with a raise statement will remedy the problem by transparently reraising the exception that was caught.
The difference between the above and using just except: without any argument is twofold:
A bare except: doesn't give you the exception object to inspect
The exceptions SystemExit, KeyboardInterrupt and GeneratorExit aren't caught by the above code, which is generally what you want. See the exception hierarchy.
If you also want the same stacktrace you get if you do not catch the exception, you can get that like this (still inside the except clause):
import traceback
print traceback.format_exc()
If you use the logging module, you can print the exception to the log (along with a message) like this:
import logging
log = logging.getLogger()
log.exception("Message for you, sir!")
If you want to dig deeper and examine the stack, look at variables etc., use the post_mortem function of the pdb module inside the except block:
import pdb
pdb.post_mortem()
I've found this last method to be invaluable when hunting down bugs.
Get the name of the class that exception object belongs:
e.__class__.__name__
and using print_exc() function will also print stack trace which is essential info for any error message.
Like this:
from traceback import print_exc
class CustomException(Exception): pass
try:
raise CustomException("hi")
except Exception as e:
print ('type is:', e.__class__.__name__)
print_exc()
# print("exception happened!")
You will get output like this:
type is: CustomException
Traceback (most recent call last):
File "exc.py", line 7, in <module>
raise CustomException("hi")
CustomException: hi
And after print and analysis, the code can decide not to handle exception and just execute raise:
from traceback import print_exc
class CustomException(Exception): pass
def calculate():
raise CustomException("hi")
try:
calculate()
except CustomException as e:
# here do some extra steps in case of CustomException
print('custom logic doing cleanup and more')
# then re raise same exception
raise
Output:
custom logic doing cleanup and more
And interpreter prints exception:
Traceback (most recent call last):
File "test.py", line 9, in <module>
calculate()
File "test.py", line 6, in calculate
raise CustomException("hi")
__main__.CustomException: hi
After raise original exception continues to propagate further up the call stack. (Beware of possible pitfall) If you raise new exception it caries new (shorter) stack trace.
from traceback import print_exc
class CustomException(Exception):
def __init__(self, ok):
self.ok = ok
def calculate():
raise CustomException(False)
try:
calculate()
except CustomException as e:
if not e.ok:
# Always use `raise` to rethrow exception
# following is usually mistake, but here we want to stress this point
raise CustomException(e.ok)
print("handling exception")
Output:
Traceback (most recent call last):
File "test.py", line 13, in <module>
raise CustomException(e.message)
__main__.CustomException: hi
Notice how traceback does not include calculate() function from line 9 which is the origin of original exception e.
You usually should not catch all possible exceptions with try: ... except as this is overly broad. Just catch those that are expected to happen for whatever reason. If you really must, for example if you want to find out more about some problem while debugging, you should do
try:
...
except Exception as ex:
print ex # do whatever you want for debugging.
raise # re-raise exception.
Most answers point to except (…) as (…): syntax (rightly so) but at the same time nobody wants to talk about an elephant in the room, where the elephant is sys.exc_info() function.
From the documentation of sys module (emphasis mine):
This function returns a tuple of three values that give information
about the exception that is currently being handled.
(…)
If no exception is being handled anywhere on the stack, a tuple
containing three None values is returned. Otherwise, the values
returned are (type, value, traceback). Their meaning is: type gets the
type of the exception being handled (a subclass of BaseException);
value gets the exception instance (an instance of the exception type);
traceback gets a traceback object (see the Reference Manual) which
encapsulates the call stack at the point where the exception
originally occurred.
I think the sys.exc_info() could be treated as the most direct answer to the original question of How do I know what type of exception occurred?
These answers are fine for debugging, but for programmatically testing the exception, isinstance(e, SomeException) can be handy, as it tests for subclasses of SomeException too, so you can create functionality that applies to hierarchies of exceptions.
Unless somefunction is a very bad coded legacy function, you shouldn't need what you're asking.
Use multiple except clause to handle in different ways different exceptions:
try:
someFunction()
except ValueError:
# do something
except ZeroDivision:
# do something else
The main point is that you shouldn't catch generic exception, but only the ones that you need to. I'm sure that you don't want to shadow unexpected errors or bugs.
In Python 2, the following are useful
except Exception, exc:
# This is how you get the type
excType = exc.__class__.__name__
# Here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)
# It's easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))
Use type class and as statement
try:#code
except Exception as e:
m=type(e)
#m is the class of the exception
strm=str(m)
#strm is the string of m
Hope this will help a little more
import sys
varExcepHandling, varExcepHandlingZer = 2, 0
try:
print(varExcepHandling/varExcepHandlingZer)
except Exception as ex:
print(sys.exc_info())
'sys.exc_info()' will return a tuple, if you only want the exception class name use 'sys.exc_info()[0]'
Note:- if you want to see all the exception classes just write dir(__builtin__)
Here's how I'm handling my exceptions. The idea is to do try solving the issue if that's easy, and later add a more desirable solution if possible. Don't solve the issue in the code that generates the exception, or that code loses track of the original algorithm, which should be written to-the-point. However, pass what data is needed to solve the issue, and return a lambda just in case you can't solve the problem outside of the code that generates it.
path = 'app.p'
def load():
if os.path.exists(path):
try:
with open(path, 'rb') as file:
data = file.read()
inst = pickle.load(data)
except Exception as e:
inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
else:
inst = App()
inst.loadWidgets()
# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
class_name = e.__class__.__name__
print(class_name + ': ' + str(e))
print('\t during: ' + during)
return easy
For now, since I don't want to think tangentially to my app's purpose, I haven't added any complicated solutions. But in the future, when I know more about possible solutions (since the app is designed more), I could add in a dictionary of solutions indexed by during.
In the example shown, one solution might be to look for app data stored somewhere else, say if the 'app.p' file got deleted by mistake.
For now, since writing the exception handler is not a smart idea (we don't know the best ways to solve it yet, because the app design will evolve), we simply return the easy fix which is to act like we're running the app for the first time (in this case).
To add to Lauritz's answer, I created a decorator/wrapper for exception handling and the wrapper logs which type of exception occurred.
class general_function_handler(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
return self.__class__(self.func.__get__(obj, type))
def __call__(self, *args, **kwargs):
try:
retval = self.func(*args, **kwargs)
except Exception, e :
logging.warning('Exception in %s' % self.func)
template = "An exception of type {0} occured. Arguments:\n{1!r}"
message = template.format(type(e).__name__, e.args)
logging.exception(message)
sys.exit(1) # exit on all exceptions for now
return retval
This can be called on a class method or a standalone function with the decorator:
#general_function_handler
See my blog about for the full example: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/
You can start as Lauritz recommended, with:
except Exception as ex:
and then just to print ex like so:
try:
#your try code here
except Exception as ex:
print ex
Your question is: "How can I see exactly what happened in the someFunction() that caused the exception to happen?"
It seems to me that you are not asking about how to handle unforeseen exceptions in production code (as many answers assumed), but how to find out what is causing a particular exception during development.
The easiest way is to use a debugger that can stop where the uncaught exception occurs, preferably not exiting, so that you can inspect the variables. For example, PyDev in the Eclipse open source IDE can do that. To enable that in Eclipse, open the Debug perspective, select Manage Python Exception Breakpoints in the Run menu, and check Suspend on uncaught exceptions.
Use the below for both Exception type and Exception text
import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'")+"-"+(str(sys.exc_info()[1])))
if you want only exception type: Use -->
import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'"))
Thanks Rajeshwar
The actual exception can be captured in the following way:
try:
i = 1/0
except Exception as e:
print e
You can learn more about exceptions from The Python Tutorial.
Just refrain from catching the exception and the traceback that Python prints will tell you what exception occurred.
When I handle some code exception code, I wander why python didn't include what exception will the function raise in its introspect system.For example,when I have to use a function refer to many other function that will raise different exceptions,I have to consider all that happen in my business logic.
Like this:
def a():
raise Exception('exception1')
def b():
a()
raise Exception('exception2')
def c():
b()
raise Exception('exception3')
def business():
try:
c()
except Exception as e:
pass
I have to keep digging in the function calls between them that I can know what maybe raise in this code block.And introspect system does not have information of exception.
And as I know, Java will explicitly annotated 'Throw' in function definition,and IDE and programmer can easily know what kinds of exception should I handle.
It will be better if I can know all the exception with object itself,for example:
all_exception = obj.__exceptions__()
So,my question is,why python not include exception introspect in function object.
Who can explain python's design?
Python is a dynamic language, and you can't know, up front, what exceptions a function could throw.
Take this example:
def throw(exception):
raise exception
What exception will that function raise? I can use throw(ValueError) or throw(TypeError('foobar')), and both would work and are valid Python:
>>> throw(ValueError)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in throw
ValueError
>>> throw(TypeError('foobar'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in throw
TypeError: foobar
Exceptions are just classes and instances. Current versions of Python require that the exception class must derive from BaseException, but in old Python versions you could even use strings for exceptions (raise "Your mother was a hamster").
And because they are looked up as globals and are not reserved names, you can assign different exceptions to names. The following is legal Python syntax too:
>>> def oops():
... raise ValueError('Oops')
...
>>> ValueError = TypeError
>>> oops()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in oops
TypeError: Oops
That's why Python functions can't expose what exceptions they raise.
Note that there is never a good reason to use plain Exception. Use one of the standard exceptions where they make sense (ValueError, TypeError, IndexError, KeyError, etc.) or create your own API-specific exceptions by subclassing from Exception or a more specific exception subclass.
Then document your API properly. State what exceptions a developer should expect, where needed. The standard exceptions don't need to be spelled out; it is reasonably obvious that a function that only works on strings will throw TypeError if you pass in a file object instead.
You can use a exception class hierarchy in your business application if you need to catch multiple types:
class BusinessException(Exception):
"""The base exception for all of Business APIs"""
class SpecificBusinessException(BusinessException):
"""Exception that indicates a specific problem occurred"""
class DifferenBusinessException(BusinessException):
"""Exception that indicates a different specific problem occurred"""
then raise the subclassed exceptions and catch BusinessException to handle all, or catch only specific subclasses to customise handling.
If you must figure out what exceptions code raise and accept the risks involved with a dynamic language being able to change the names, then you could use abstract syntax tree (AST) analysis to at least find some information on exceptions. For straight raise Name and raise Name(args..) statements, extracting those names or calls by walking the AST is at least relatively straightforward:
import builtins
import inspect
import ast
class ExceptionExtractor(ast.NodeVisitor):
def __init__(self):
self.exceptions = []
def visit_Raise(self, node):
if node.exc is None:
# plain re-raise
return
exc_name = node.exc
if isinstance(exc_name, ast.Call):
exc_name = exc_name.func
if not (isinstance(exc_name, ast.Name) and
isinstance(exc_name.ctx, ast.Load)):
# not a raise Name or raise Name(...)
return
self.exceptions.append(exc_name.id)
def global_exceptions_raised(func):
"""Extract the expressions used in raise statements
Only supports raise Name and raise Name(...) forms, and
only if the source can be accessed. No checks are made for the
scope of the name.
returns references to those exception names that can be loaded from
the function globals.
"""
source = inspect.getsource(func)
tree = ast.parse(source)
extractor = ExceptionExtractor()
extractor.visit(tree)
fglobals = {**func.__globals__, **vars(builtins)}
return [fglobals[name] for name in extractor.exceptions if name in fglobals]
I'm trying to implement a system to help the user when calling functions/methods.
I know the user can just help(function) to get some kind of a documentation provided by me but I wanted to reimplement the TypeError do it would also print that documentation if available.
For example:
Suppose I have:
def foo(bar):
''' Adds 1 to 'bar' and prints output '''
print 1+bar
And the user decide to call foo() (with no arguments)
It will raise a TypeError like this:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-624891b0d01a> in <module>()
----> 1 foo()
TypeError: foo() takes exactly 1 argument (0 given)
I would like it to also print the information from the help(foo) as well. i.e.:
foo(bar)
Adds 1 to 'bar' and prints output
Any ideas on how to do that? I realise I need
to detect the function that raised the TypeError
get the help text for that function
add it to the raised TypeError.
for 1) this seems to work:
import sys, traceback
# Get latest traceback information
tb = sys.exc_info()[-1]
stk = traceback.extract_tb(tb, 1)
# Extract called function and remove '()' - This actually limits functionality as the user might had inputed some extra arguments for example
fname = stk[0][-1]
fname = str(fname).split('()')[0]
for 2) and 3) and have no ideas on how to proceed... =/
Very much appreciated!
Edit for 3) I'm trying to override the default behaviour of TypeError, so far with no success.
I created a new MyError class just to test it and made:
import exceptions
exception.TypeError = MyError
but whenever the TypeError is raised, the original version comes up and not MyError
Edit 2 Ok, found out that I actually need to override the sys.excepthook method.
As a test, I created:
import sys
def handler(exc, value, tb):
print 'Oops'
sys.excepthook = handler
However, whenever a error occurs it still brings the original error and not the 'Oops' message. Also, sys.excepthook still returns the original message:
<bound method TerminalInteractiveShell.excepthook of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x10f4320d0>>
I also tried overriding the IPython.terminal.interactiveshell.TerminalInteractiveShell.excepthook with no success.
Any ideas on how to keep going?
For number two:
>>> def foo(bar):
... '''Adds "1" to bar and prints output'''
... return 1 + bar
...
>>> print foo.__doc__
Adds "1" to bar and prints output
For number three, you may want to use the raise keyword to raise an error. You could probably use this with your first solution, but I've never used the traceback module so I can't help you there, sorry.
Ok, I finally got it!
This answer is valid for both python and ipython!
(I only tested with python 2.7, minor changes might be needed for python 3)
import sys
import traceback
import inspect
def get_args(func):
"""Get function arguments, varargs, kwargs and defaults.
This function will be called whenever a exception is raised."""
args, varargs, kwargs, defs = inspect.getargspec(func)
if defs is not None:
# If there are defaults, include them in the main argument list
for i in range(-len(defs), 0):
args[i] += ' = {}'.format(defs[i])
if varargs is not None:
# If the function accept extra arguments, include them at the end of the list.
args.append('*' + varargs)
if kwargs is not None:
# If the function accept extra keyworded arguments, include them at the end of the list.
args.append('**' + kwargs)
return args # args contain information about all the function arguments.
def value_handler(exc, value, tb):
"""Changes the default message to include additional information.
This handler will be called whenever an exception happens."""
args = list(value) # Value typically contains the error message.
if exc == TypeError and '()' in str(value):
# I want to change only TypeError from function calls.
func_name = str(value).split('()')[0] # Obtain the function name from the error message.
func = globals()[func_name] # Get function object from globals
func_doc = func.__doc__ # Function docstring
func_args = get_args(func) # Get function arguments
if func_doc is not None: # Add docstring to the message
args[0] += '\nDoc: \t{}'.format(func_doc)
args[0] += '\nArgs: \t' + '\n\t'.join(func_args) # Finally, add all the arguments to the message.
# Apply changes to the original error
value.args = args
return value
def custom_exc(shell, exc, value, tb, tb_offset=None):
"""Add aditional information and call original excepthook
This version works with iPython"""
value = value_handler(exc, value, tb) # Changes the error message
shell.showtraceback((exc, value, tb), tb_offset=tb_offset) # Raise the error with the new message (keeping traceback and other information).
def custom_python_exc(exc, value, tb):
"""Add aditional information and call original excepthook
This version works with regular python"""
value = value_handler(exc, value, tb) # Changes the error message
sys.__excepthook__(exc, value, tb) # Raise the error with the new message (keeping traceback and other information).
try:
__IPYTHON__ # Check if we're running iPython
except NameError:
# Not iPython enviroment, override excepthook
sys.excepthook = custom_python_exc
else:
# iPython enviroment, need to set custom excepthook
get_ipython().set_custom_exc((Exception,), custom_exc)
With this, one should be able to add more information to any Error being raised.
I want to make a decorator which will catch exceptions and adequately logged their.
def logger(foo):
try:
print foo()
except Exception as e:
print e
#logger
def d():
return 2/2
if __name__ == '__main__':
d()
Thats right i think, but then I run it and I have an exception like this:
1
Traceback (most recent call last):
File "log.py", line 14, in <module>
d()
TypeError: 'NoneType' object is not callable
Why interpreter tells me that the function has None type, but call it and print answer?
Your decorator needs to return a function, but it's not returning anything, hence the 'TypeError: 'NoneType' object is not callable'. You can implement it this way:
def logger(foo):
def fn():
try:
print foo()
except Exception as e:
print e
return fn
Check out This question for a good example of how to write/use a decorator.
logger as you have defined, does not return a value. All such functions can be thought of as returning None. You have not defined your decorator correctly. It should look more like this:
def logger(foo):
def _logger(foo):
try:
print foo()
except Exception as e:
print e
return _logger
...but keep in mind that this loses a great deal of information, catches and swallows a great deal of exceptions, and also swallows any return values from the foo function so decorated. While you probably do something different in your production code than what you have shown here, the important thing is that the decorator function must itself return a function that can be called (_logger in my example).
Here's my exception class that is using raise:
class SCE(Exception):
"""
An error while performing SCE functions.
"""
def __init__(self, value=None):
"""
Message: A string message or an iterable of strings.
"""
if value is None:
self._values = []
elif isinstance(value, str):
self._values = [value]
else:
self._values = list(value)
def __raise__(self):
print('raising')
if not len(self._values):
return
def __str__(self):
return self.__repr__()
def __iter__(self):
return iter(self._values)
def __repr__(self):
return repr(self._values)
Currently if I raise this exception with no value I get traceback followed by:
__main__.SCE: []
Instead of what I expected which was:
raising
>>>
How do you overload raise?
As the other answer says, there is no __raise__ special method. There was a thread in 2004 on comp.lang.python where someone suggested adding such a method, but I don't think there was any followup to that. The only way I can think of to hook exception raising is either by patching the interpreter, or some kind of source or bytecode rewriting that inserts a function call next to the raise operation.
There is no such special method __raise__ (at least none that I have ever heard of or that I can find in the Python documentation).
Why do you want to do this? I can't think of any reason why you want custom code be be executed when the exception is raised (as opposed to either when the exception is constructed, which you can do with the __init__ method, or when the exception is caught, which you can do with an except block). What is your use case for this behavior, and why do you expect that Python supports it?
As others have stated, there is no such private method __raise__. Nothing prevents defining one. For example:
#!/usr/bin/env python3
class MyClass(object):
def __init__(self, raise_exceptions=False):
self.raise_exceptions = raise_exceptions
def __raise__(self, err=None):
print(err, flush=True)
if self.raise_exceptions:
raise err
def run(self):
try:
assert False, 'assertion False'
except Exception as err:
self.__raise__(err)
if __name__ == '__main__':
MyClass(raise_exceptions=False).run()
MyClass(raise_exceptions=True).run()
Here is the output:
$ python3 my_class.py
assertion False
assertion False
Traceback (most recent call last):
File "my_class.py", line 22, in <module>
MyClass(raise_exceptions=True).run()
File "my_class.py", line 17, in run
self.__raise__(err)
File "my_class.py", line 11, in __raise__
raise err
File "my_class.py", line 15, in run
assert False, 'assertion False'
AssertionError: assertion False
Process finished with exit code 1