Hone logo
Hone
Problems

Crafting Custom Exceptions for Enhanced Error Handling

In Python, built-in exceptions are useful, but sometimes you need to define your own specific error types to represent situations unique to your application. This challenge will guide you in creating and utilizing custom exceptions to make your code more readable, maintainable, and robust by clearly communicating the nature of errors.

Problem Description

Your task is to create a system for managing user accounts, including registration and login. To make error handling more precise, you need to define custom exceptions for common issues that might arise during these operations.

What needs to be achieved:

  1. Define three custom exception classes:
    • UserAlreadyExistsError: Raised when attempting to register a username that already exists.
    • InvalidCredentialsError: Raised when login attempts with incorrect username or password.
    • AccountNotFoundError: Raised when attempting to perform an operation on a non-existent account.
  2. Implement a simple UserManager class that handles user registration and login.
  3. Ensure that the UserManager raises the appropriate custom exceptions when specific error conditions are met.

Key requirements:

  • Custom exceptions should inherit from Python's Exception class or a more specific built-in exception (e.g., ValueError, LookupError) if appropriate for semantic clarity.
  • Each custom exception should have a descriptive error message.
  • The UserManager class should have at least two methods: register_user(username, password) and login_user(username, password).
  • The login_user method should also consider the AccountNotFoundError case if a username doesn't exist.

Expected behavior:

  • When register_user is called with a username that already exists, UserAlreadyExistsError should be raised.
  • When login_user is called with an incorrect username or password, InvalidCredentialsError should be raised.
  • When login_user is called with a username that has not been registered, AccountNotFoundError should be raised.

Important edge cases to consider:

  • Empty strings for username or password during registration or login. While not explicitly requiring custom exceptions for these, consider how your UserManager might handle them (e.g., by raising a standard ValueError or TypeError). For this challenge, focus on the specified custom exceptions.

Examples

Example 1: Successful Registration and Login

user_manager = UserManager()
user_manager.register_user("alice", "password123")
print("Alice registered successfully.")
if user_manager.login_user("alice", "password123"):
    print("Alice logged in successfully.")

Output:

Alice registered successfully.
Alice logged in successfully.

Explanation: The user "alice" is registered with a password. Subsequently, a successful login is performed with the correct credentials, and no exceptions are raised.

Example 2: User Already Exists Error

user_manager = UserManager()
user_manager.register_user("bob", "securepass")
try:
    user_manager.register_user("bob", "anotherpass")
except UserAlreadyExistsError as e:
    print(f"Error: {e}")

Output:

Error: Username 'bob' already exists.

Explanation: Attempting to register the username "bob" a second time triggers the UserAlreadyExistsError, and the custom error message is printed.

Example 3: Invalid Credentials and Account Not Found Errors

user_manager = UserManager()
user_manager.register_user("charlie", "charmain")
try:
    user_manager.login_user("charlie", "wrongpassword")
except InvalidCredentialsError as e:
    print(f"Error: {e}")

try:
    user_manager.login_user("david", "anypassword")
except AccountNotFoundError as e:
    print(f"Error: {e}")

Output:

Error: Invalid username or password for 'charlie'.
Error: Account for username 'david' not found.

Explanation: The first try-except block catches an InvalidCredentialsError when "charlie" attempts to log in with an incorrect password. The second try-except block catches an AccountNotFoundError because the username "david" has not been registered.

Constraints

  • The UserManager should store user data in memory (e.g., a dictionary). No persistent storage is required.
  • Usernames and passwords are case-sensitive.
  • The system should handle up to 100 unique users for testing purposes.

Notes

  • Consider what information each custom exception might carry. For instance, UserAlreadyExistsError could store the username that caused the conflict.
  • Inheriting from ValueError for UserAlreadyExistsError and AccountNotFoundError might be semantically appropriate, as these often relate to invalid values or missing items. However, inheriting directly from Exception is also perfectly acceptable and common.
  • Focus on correctly defining and raising the custom exceptions. The internal implementation of how the UserManager stores and validates credentials is secondary to the exception handling aspect of this challenge.
Loading editor...
python