Error Handling Assessment
Test your mastery of Python error handling: try-except blocks, custom exceptions, context managers, and defensive programming patterns.
Write a function safe_divide(a, b) that returns the result of a / b. If b is zero, return the string "Cannot divide by zero". If either argument is not a number, return the string "Invalid input".
The function below is supposed to catch ValueError and Exception separately, but the specific ValueError handler never runs. Fix the bug so that parse_int("abc") prints "Not a valid integer" and parse_int(None) prints "Unexpected error".
Create a custom exception class ValidationError that inherits from ValueError. It should accept a field and message parameter and store them as attributes. Its string representation (__str__) should return "{field}: {message}". Then write a function validate_age(age) that raises ValidationError("age", "Must be between 0 and 150") if age is not in that range, otherwise returns age.
What does the following code print? Pay careful attention to the order of execution with try, except, and finally.
The function below should print "Conversion successful: <number>" only when no error occurs, and "Invalid" when a ValueError is raised. Currently the success message prints even on error. Fix it using the else clause properly.
Write a function validate_username(username) that raises:
TypeError with message "Username must be a string" if username is not a stringValueError with message "Username cannot be empty" if it is an empty stringValueError with message "Username too long" if it is longer than 20 charactersOtherwise return the username stripped of leading/trailing whitespace.
What does the following code print? Think about how raise ... from ... affects the exception chain.
Refactor the ManagedResource class below so it can be used as a context manager with with. The __enter__ method should call self.open() and return self. The __exit__ method should call self.close() and return False (do not suppress exceptions). Keep the existing open, close, and read methods unchanged.
Refactor the fetch_data function to include retry logic. Write a function retry(func, max_attempts=3) that:
func() up to max_attempts timesfunc() succeeds, return its result immediatelyfunc() raises a ConnectionError, print "Attempt <n> failed" and try againConnectionErrorKeep fetch_data as-is (it is used by the test cases).
The function below silently swallows all errors with a bare except: pass. Fix it so that:
ZeroDivisionError prints "Error: division by zero"TypeError prints "Error: invalid type"The function should return the result on success, or None when a handled error occurs.