Personal Expense Tracker CLI

Project Overview & Use Case

Managing daily expenses manually can lead to lost receipts and forgotten spending.

The Use Case: This project is a Command-Line Interface (CLI) application that allows users to log their daily expenses, categorize them, and instantly view a summary of their spending habits.

The Output: It saves all data permanently into a .csv (Comma Separated Values) file, which can later be opened in Microsoft Excel or Google Sheets for further analysis.

System Workflow (How It Works)

Initialization: When the script runs, it checks if a file named expenses.csv exists. If it does not, the script creates it and adds the header row (Date, Category, Amount, Description).

Main Menu: The user is presented with a text-based menu offering three options:

  • Add a new expense.

  • View an expense summary.

  • Exit the program.

Data Entry: If the user adds an expense, the script automatically captures the current date, asks for the category, amount, and description, and appends this data to the CSV file.

Data Aggregation: If the user views the summary, the script reads the CSV file, groups the spending by category using a Python dictionary, and calculates the total amount spent per category.

Source Code

Save the following code in a file named expense_tracker.py.

expense_tracker.py

import csv
import os
from datetime import datetime

# Define the file name where data will be saved
FILE_NAME = "expenses.csv"

def initialize_file():
  """Creates the CSV file with headers if it doesn't already exist."""
  if not os.path.exists(FILE_NAME):
      with open(FILE_NAME, mode='w', newline='') as file:
          writer = csv.writer(file)
          writer.writerow(["Date", "Category", "Amount", "Description"])

def add_expense():
  """Prompts the user for expense details and saves them to the CSV."""
  print("
--- Add a New Expense ---")
  
  # Get current date automatically
  date_today = datetime.now().strftime("%Y-%m-%d")
  
  category = input("Enter Category (e.g., Food, Transport, Utilities): ").capitalize()
  
  # Error handling to ensure the amount is a valid number
  try:
      amount = float(input("Enter Amount: $"))
  except ValueError:
      print("❌ Invalid input. Please enter a numerical value for the amount.")
      return
      
  description = input("Enter a brief description: ")

  # Append the new record to the CSV file
  with open(FILE_NAME, mode='a', newline='') as file:
      writer = csv.writer(file)
      writer.writerow([date_today, category, amount, description])
  
  print(f"✅ Successfully added: $ {amount:.2f} for {category}.")

def view_summary():
  """Reads the CSV and displays total spending per category."""
  print("
--- Expense Summary ---")
  
  if not os.path.exists(FILE_NAME):
      print("⚠️ No expenses recorded yet.")
      return

  category_totals = {}
  total_spent = 0.0

  # Read the file and calculate totals
  with open(FILE_NAME, mode='r') as file:
      reader = csv.DictReader(file)
      for row in reader:
          category = row["Category"]
          amount = float(row["Amount"])
          
          # Add amount to the specific category
          if category in category_totals:
              category_totals[category] += amount
          else:
              category_totals[category] = amount
              
          total_spent += amount

  # Display the aggregated data
  if total_spent == 0:
      print("No expenses found.")
  else:
      for cat, total in category_totals.items():
          print(f"🔹 {cat}: $ {total:.2f}")
      print("-" * 23)
      print(f"💰 Total Spent: $ {total_spent:.2f}")

def main():
  """The main loop that runs the interactive menu."""
  initialize_file()
  
  while True:
      print("
" + "="*25)
      print("   EXPENSE TRACKER MENU")
      print("="*25)
      print("1. Add an Expense")
      print("2. View Summary")
      print("3. Exit")
      
      choice = input("Select an option (1-3): ")
      
      if choice == '1':
          add_expense()
      elif choice == '2':
          view_summary()
      elif choice == '3':
          print("Exiting Expense Tracker. Have a great day! 👋")
          break
      else:
          print("❌ Invalid choice. Please select 1, 2, or 3.")

if __name__ == "__main__":
  main()

Code Explanation (Component Breakdown)

csv Module: Python’s built-in tool for reading and writing CSV files. csv.writer is used to add data row by row, while csv.DictReader transforms each row of the file into a dictionary, allowing us to access columns by their header names (e.g., row[“Amount”]).

with open(…) as file: This is a context manager. It is best practice for file handling because it automatically closes the file when the block of code finishes, even if an error occurs.

mode=‘a’ vs mode=‘w’ vs mode=‘r’:

  • ‘w’ (Write): Creates a new file or overwrites an existing one. Used in initialization.
  • ‘a’ (Append): Adds new data to the bottom of the file without deleting existing data. Used when adding an expense.
  • ‘r’ (Read): Opens the file strictly to view the data. Used in the summary.

Try/Except Block: When asking the user for the money amount (float(input(…))), the user might accidentally type a letter instead of a number. The try/except ValueError catches this mistake and prevents the entire program from crashing.

Execution Guide (How to Run)

Save the file: Create a new folder on your desktop called ExpenseProject. Inside it, create a file named expense_tracker.py and paste the code above.

Open Terminal/Command Prompt: Navigate to that folder.

Run the script: Type the command python expense_tracker.py and press Enter.

Interact: Follow the on-screen menu to log a few test expenses (like groceries or rent), then choose option 2 to see your calculated totals.

Verify: Open the ExpenseProject folder. You will see a newly generated expenses.csv file that you can open with Excel.