how to handle Exceptions in programs¶
requirements¶
test_catching_exceptions_w_messages¶
I add a failing test to
test_exceptions.pydef test_catching_exceptions_w_messages(self): src.exceptions.raise_exception()
the terminal shows AttributeError
AttributeError: module 'src.exceptions' has no attribute 'raise_exception'
green: make it pass¶
I add the name to
exceptions.pydef function_name(): return None raise_exception
the terminal shows NameError
NameError: name 'raise_exception' is not defined
I point it to None
raise_exception = None
the terminal shows TypeError
TypeError: 'NoneType' object is not callable
When I make it a function
def raise_exception(): return None
the test passes
I want the function to raise an Exception when it is called
def test_catching_exceptions_w_messages(self): with self.assertRaises(Exception): src.exceptions.raise_exception()
the terminal shows AssertionError
AssertionError: Exception not raised
I use the raise statement
def raise_exception(): raise Exception
and the test is green
I can use the unittest.TestCase.assertRaisesRegex method to be more specific in tests, it checks that the code in its context raises the Exception it is given, with the message it is given, it uses Regular Expressions for this
def test_catching_exceptions_w_messages(self): with self.assertRaisesRegex( Exception, 'BOOM!' ): src.exceptions.raise_exception()
the terminal shows AssertionError
AssertionError: "BOOM!" does not match ""
the Exception is right, the message is not. I add it
def raise_exception(): raise Exception('BOOM!')
the test passes. Time to add an how to test that an Exception is raised to the program
test_catching_failure¶
red: make it fail¶
I add a new failing test
def test_catching_failure(self):
self.assertEqual(
src.exceptions.an_exception_handler(
src.exceptions.raise_exception
),
'failed'
)
the terminal shows AttributeError
AttributeError: module 'src.exceptions' has no attribute 'an_exception_handler'
green: make it pass¶
When I add the name
def raise_exception(): raise Exception('BOOM') an_exception_handler
I get NameError
NameError: name 'an_exception_handler' is not defined
I point it to None
an_exception_handler = None
the terminal shows TypeError
TypeError: 'NoneType' object is not callable
then I make it a function
def an_exception_handler(): return None
the terminal shows TypeError
TypeError: an_exception_handler() takes 0 positional arguments but 1 was given
I make the function take input
def an_exception_handler(argument): return None
the terminal shows AssertionError
AssertionError: None != 'failed'
the result of calling
src.exceptions.an_exception_handleris None, the test expects'failed'I change the return statement to match the expectation
def an_exception_handler(argument): return 'failed'
the test passes.
test_catching_success¶
I want an_exception_handler to process its input and return failed when an Exception happens or success when it does not.
red: make it fail¶
I add a new test
def test_catching_success(self):
self.assertEqual(
src.exceptions.an_exception_handler(
src.exceptions.does_not_raise_exception
),
'succeeded'
)
the terminal shows AttributeError
AttributeError: module 'src.exceptions' has no attribute 'does_not_raise_exception'
green: make it pass¶
I add the name to
exceptions.pydef raise_exception(): raise Exception('BOOM') does_not_raise_exception def an_exception_handler(argument): return 'failed'
the terminal shows NameError
NameError: name 'does_not_raise_exception' is not defined
I point it to None
does_not_raise_exception = None
the terminal shows AssertionError
AssertionError: 'failed' != 'succeeded'
src.exceptions.an_exception_handlerstill returns'failed', the test expects'succeeded'I make
an_exception_handlerreturn its inputdef an_exception_handler(argument): return argument return 'failed'
the terminal shows AssertionError
FAILED tests/test_exceptions.py::TestExceptions::test_catching_failure - AssertionError: <function raise_exception at 0xabcd12e34567> != 'failed' FAILED tests/test_exceptions.py::TestExceptions::test_catching_success - AssertionError: None != 'succeeded'
I rename the input parameter to describe it better
def an_exception_handler(a_function): return a_function return 'failed'
then make
an_exception_handlerreturn the result of a call to its input as a functiondef an_exception_handler(a_function): return a_function() return 'failed'
the terminal shows TypeError
a_function = None def an_exception_handler(a_function): > return a_function() E TypeError: 'NoneType' object is not callable
because
does_not_raise_exceptionpoints to None, which is not callable. I make it a function to fix thisdef does_not_raise_exception(): return None
the terminal shows AssertionError
AssertionError: None != 'succeeded'
the result of calling
src.exceptions.raise_exceptionintest_catching_failureis an Exception with a messageFAILED tests/test_exceptions.py::TestExceptions::test_catching_failure - Exception: 'BOOM!'
how to use try…except…else¶
when I add a try statement
def an_exception_handler(a_function): try: a_function() except Exception: return 'failed'
test_catching_failurepasses and the terminal still shows AssertionErrorAssertionError: None != 'succeeded'
I add an else clause
def an_exception_handler(a_function): try: a_function() except Exception: return 'failed' else: return None
then change its return statement
def an_exception_handler(a_function): try: a_function() except Exception: return 'failed' else: return 'succeeded'
the test passes.
The try statement is used to catch/handle exceptions in Python. It allows the program to make a decision when it runs into an Exception. I think of it as
tryrunning thisexcept Exception- when running this raisesException, run the code in this blockelse- when running this does NOT raiseException, run the code in this block
In this case
trycallinga_function()except Exception- when callinga_function()raisesExceptionreturn'failed'else- when callinga_function()does NOT raiseExceptionreturn'succeeded'
I can be more specific with the Exception in the
exceptblock, for exampledef an_exception_handler(a_function): try: a_function() except ModuleNotFoundError: return 'failed' else: return 'succeeded'
shows this in the terminal
Exception: 'BOOM!'
because Exception is not ModuleNotFoundError, the try statement will only catch the Exception given in the
exceptblock and its children, all others will be raisedI change it back to what works
def an_exception_handler(a_function): try: a_function() except Exception: return 'failed' else: return 'succeeded'
the terminal shows green again
review¶
I ran tests to show how to cause Exceptions, and catch or handle them in tests and programs. Would you like to test measuring sleep duration?