...

/

Error Handling and Refinement

Error Handling and Refinement

Add edge case and exception handling to our budget app.

We kicked off this project by gathering requirements from a simulated client. Our AI co-pilot helped us quickly generate a functional core, and it worked flawlessly in our tests. The code accepted income and logged expenses just as we wanted. But in the real world, users aren't always perfect. What happens when they make a mistake?

Let's find out.

The widget below contains the code we just generated. Run it as instructed. When you see the prompt that says Enter your monthly income, type the words five hundred instead of entering the number 500.

income = 0.0
expenses = [] # Each item is a dict: {"category": str, "amount": float}

# Common categories to suggest to the user
allowed_categories = [
    "Food", "Rent", "Transport", "Entertainment",
    "Utilities", "Health", "Education", "Other"
]

def add_income(amount):
    """Set or update the monthly income (float > 0)."""
    global income
    income = float(amount)

def add_expense(category, amount):
    """Append an expense entry with category, amount (>0)."""
    new_expense = {
        "category": category,
        "amount": float(amount)
    }
    expenses.append(new_expense)

def delete_expense(idx):
    """Delete an expense by zero-based"""
    return expenses.pop(idx)

def total_spent(expenses_list=None):
    """Return the sum of all expense amounts from a list or the global store."""
    if expenses_list is None:
        expenses_list = expenses
    return sum(entry["amount"] for entry in expenses_list)

def compute_category_totals(expenses_list=None):
    """Return a dict mapping category -> total amount from expenses."""
    if expenses_list is None:
        expenses_list = expenses
    
    totals = {}
    for entry in expenses_list:
        category = entry["category"]
        amount = entry["amount"]
        totals[category] = totals.get(category, 0) + amount
    return totals

def print_report(income_value=None, expenses_list=None):
    """Print a formatted budget report with category totals and status line."""
    if income_value is None:
        income_value = income
    if expenses_list is None:
        expenses_list = expenses

    total = total_spent(expenses_list)
    remaining_balance = income_value - total
    category_totals = compute_category_totals(expenses_list)
    
    print("\n--- Budget Report ---")
    print(f"Income: ${income_value:.2f}")
    print(f"Total Spent: ${total:.2f}")
    
    print("\nCategory Spending:")
    for category, amount in category_totals.items():
        print(f"  - {category}: ${amount:.2f}")
    
    print("-" * 27)
    print(f"Remaining Balance: ${remaining_balance:.2f}")
    
def show_menu():
    """Display simple command menu for the CLI."""
    print("\n--- Budget Tracker Menu ---")
    print("1. Set Monthly Income")
    print("2. Add an Expense")
    print("3. Delete an Expense")
    print("4. Show Budget Report")
    print("5. Reset All Data")
    print("6. Exit")

# Helper function to list expenses
def list_expenses():
    """Display all expenses with their index."""
    if not expenses:
        print("No expenses recorded yet.")
        return
    print("\nCurrent Expenses:")
    for i, expense in enumerate(expenses):
        print(f"{i}: {expense['category']} - ${expense['amount']:.2f}")
        
def reset_data():
    """Clear income and expenses; return to a clean initial state."""
    global income, expenses
    income = 0.0
    expenses.clear()
    print("All budget data has been cleared.")

def run_cli():
    """Main loop: set income, add expenses, show report/export, reset, exit."""
    global income
    print("Welcome to Budget Tracker!")
    income_input = input("Enter your monthly income: ")
    add_income(income_input)

    while True:
        show_menu()
        choice = input("Choose an option: ").strip()

        if choice == "1":
            amount = input("Enter new monthly income: ")
            add_income(amount)
        elif choice == "2":
            # Display categories to the user
            print("\nAvailable Categories:")
            for i, cat in enumerate(allowed_categories):
                print(f"{i}: {cat}")
            
            # Prompt for category and amount
            category_idx_str = input("Enter the number for the category: ")
            category_idx = int(category_idx_str)

            if 0 <= category_idx < len(allowed_categories):
                category = allowed_categories[category_idx]
                amount = input(f"Enter expense amount for {category}: ")
                add_expense(category, amount)
                print("Expense added.")
            else:
                print("Invalid category number. Please try again.")

        elif choice == "3":
            list_expenses()  # Display list before prompting for deletion
            if not expenses:
                continue
            
            idx_str = input("Enter the index of the expense to delete: ")
            idx = int(idx_str)
            
            if 0 <= idx < len(expenses):
                deleted_expense = delete_expense(idx)
                print(f"Deleted expense: {deleted_expense['category']} - ${deleted_expense['amount']:.2f}")
            else:
                print("Invalid index. No expense deleted.")
        elif choice == "4":
            print_report()
        elif choice == "5":
            reset_data()
        elif choice == "6":
            print("Goodbye!")
            break
        else:
            print("Invalid choice. Please try again.")

if __name__ == "__main__":
    run_cli()
Test your project with wrong user input

The app crashed, and the terminal is filled with red text: ValueError: could not convert string to float: 'five hundred'.

What went wrong?

The AI-generated code expected a numeric value. It attempted to convert my text five hundred into a number using the float() function. Because the text was not numeric, the program raised a ValueError and stopped running.

The AI’s goal was to generate a solution based on the most common and ideal scenario. It is assumed that a user would always input a valid number because that’s what a budget tracker implies. This kind of code is great for a rapid prototype, but it’s brittle. It lacks the defensive layers that ...