Practical 13: Exception Handling Exercises

Objective

In this lab, you will look at exception handling exercises.

Submission Date:

Prerequisites

  • Basic knowledge of Python syntax
  • Understanding of lists and functions in Python
  • Familiarity with time complexity concepts (optional, but helpful)

Lab Steps

Step 1: Simple Python Exception Handling Errors

In this example, dividing number by 0 raises a ZeroDivisionError. The try block contains the code that might cause an exception and the except block handles the exception, printing an error message instead of stopping the program.

# Simple Exception Handling Example
n = 10
try:
    res = n / 0  # This will raise a ZeroDivisionError
except ZeroDivisionError:
    print("Can't be divided by zero!")

Value Error

float('z')

Index Error

x = []
print(x[2])

Invalid operations TypeError, NameError, AttributeError

a = 1
print('a = ' + a, length(a), a._x)

Step 2: Catching Specific Exceptions

Exception Handling with try, except, else and finally blocks.

def dividefunction(x, y):
    try:
        z = x/y
    except TypeError:
        print("Type Error: Cannot divide number by string")
    except ZeroDivisionError:
        print("Zero Division Error: Cannot divide by zero")
    except:
        print("Unknown Error")
    else:
        print(z)
    finally:
        print("End of the program")

dividefunction(10, 0)
dividefunction(10, "hello")

Step 3: Raising Exceptions

We raise an exception in Python using the raise keyword followed by an instance of the exception class that we want to trigger. We can choose from built-in exceptions or define our own custom exceptions by inheriting from Python’s built-in Exception class.

def set(age):
    if age < 0:
        raise ValueError("Age cannot be negative.")
    print(f"Age set to {age}")

try:
    set(-5)
except ValueError as e:
    print(e)

Step 4: User defined exceptions

Create your own Exception classes to handle application specific exceptions caused by business rule violations. All user-defined exception classes inherit from Exception class.

class InvalidAgeError(Exception):	# Step 1: Subclass the Exception class
    '''Raises InvalidAgeError when age is invalid '''
    def __init__(self, age, msg="Age must be between 0 and 120", error_code=1001):
        self.age = age			# Custom attributes
        self.msg = msg
        self.error_code = error_code
        super().__init__(self.msg)		# Call the base class constructor
    def __str__(self):			# Step 2: Customize the string representation of the exception
        return f"[Error Code {self.error_code}] {self.age} -> {self.msg}"
def set_age(age):
    if age < 0 or age > 120:
        raise InvalidAgeError(age)		# Step 3: Raising the custom exception
    else:
        print(f"Age set to: {age}")
try:					# Step 4: Handling the custom exception with further info
    set_age(150)  			# This will raise the custom exception
except InvalidAgeError as e:
    print(e)

Step 5: Unit test example

Steps to write test case:

  • Import unittest
  • Create a class that inherits from the TestCase class
  • Add methods inside the class by adding self as the first argument
  • Use the self.assertEqual() method on the TestCase class
  • Execute the test case using unittest.main()
import unittest
def triangle(height):
    pattern = ''
    for i in range(1, height + 1):
        for j in range(i):
            pattern += "* "
        pattern += '\n'
    return pattern

class testTriangle(unittest.TestCase):
    def test_triangle_positive_height(self):
        self.assertEqual(triangle(5), "* \n* * \n* * * \n* * * * \n* * * * * \n", 'Height must be a positive integer')
    
    def test_triangle_zero_height(self):
        self.assertEqual(triangle(0),'', 'Height must be a positive integer')
    
    def test_triangle_negative_height(self):
        self.assertEqual(triangle(-5),'', 'Height must be a positive integer')

unittest.main()

1. Either run the code with

python3 <script_name.py>

2. Or comment out the unittest.main() line

# unittest.main()

And run the following section of the code with

python3 -m unittest <script_name.py>

Step 6: Unit test example on testing raising of exception

The code can be modified to handle checking of exception raising upon receiving invalid parameters.

import unittest
def triangle(height):
    pattern = ''
    if type(height) not in [int, float]:
        raise TypeError("The height must be a real number")
    if height < 0:
        raise ValueError("The height cannot be a negative number")
    for i in range(1, height + 1):
        for j in range(i):
            pattern += "* "
        pattern += '\n'
    return pattern

class testTriangle(unittest.TestCase):
    def test_triangle_positive_height(self):
        self.assertEqual(triangle(5), "* \n* * \n* * * \n* * * * \n* * * * * \n", 'Height must be a positive integer')
    
    def test_values(self):
        self.assertRaises(ValueError, triangle, -2)

    def test_types(self):
        self.assertRaises(TypeError, triangle, 3+5j)
        self.assertRaises(TypeError, triangle, True)
        self.assertRaises(TypeError, triangle, "radius")
unittest.main()

Exercises for Students

  1. Implement exception handling and unit tests

Conclusion

In this lab, you've implemented some exception handling and unit testing.

Key takeaways: