thecodex.expert · The Codex Family of Knowledge
Tier 1 · Beginner · Python Project

Budget Tracker

Track income and expenses, see your balance, and break down spending by category. Learn summarising data.

🧠 Teaches how to think spoonfed, every age Last verified:

1 The Problem

We want a budget tracker: record income and expenses (each with an amount and category), then show the total balance and a breakdown of spending per category. It teaches recording transactions and summarising them — totalling and grouping, the core of any reporting tool.

Where this shows up: finance apps, expense reports, sales dashboards, analytics, any feature that takes many records and rolls them up into totals and breakdowns. Summarising data is one of the most valuable skills in software.

2 How to Think About It

Think about recording and summarising, before any code:

The plan — in plain English
1. Each entry is an amount plus a category (income is positive, expense is negative). → 2. Keep them in a list. → 3. Balance = add up all the amounts. → 4. By category = group the amounts by their category and total each group. → 5. Save to a file.

Add

Balance

By category

Load entries

Show menu

Choice?

Record amount + category

Sum all amounts

Group and total

Save

3 The Build — explained part by part

Here is the complete budget tracker. Each part is explained below.

Pythonbudget.py
import json
import os
from collections import defaultdict

FILE = "budget.json"

def load():
    if os.path.exists(FILE):
        with open(FILE) as f:
            return json.load(f)
    return []

def save(entries):
    with open(FILE, "w") as f:
        json.dump(entries, f)

entries = load()

while True:
    print("\n1. Add  2. Balance  3. By category  4. Quit")
    choice = input("Choose: ")

    if choice == "1":
        amount = float(input("Amount (negative for expense): "))
        category = input("Category: ")
        entries.append({"amount": amount, "category": category})
        save(entries)
    elif choice == "2":
        balance = sum(e["amount"] for e in entries)
        print(f"Balance: {balance:.2f}")
    elif choice == "3":
        totals = defaultdict(float)
        for e in entries:
            totals[e["category"]] += e["amount"]
        for category, total in totals.items():
            print(f"{category}: {total:.2f}")
    elif choice == "4":
        break
What each part does — in plain words
{"amount": amount, "category": category} — each entry is a record with an amount (positive income, negative expense) and a category label.

sum(e["amount"] for e in entries) — the balance: add up every amount in one line. Income adds, expenses (being negative) subtract.

from collections import defaultdict — a dictionary that starts each new key at zero automatically, so we can add to a category without first checking it exists.

totals[e["category"]] += e["amount"] — the grouping: for each entry, add its amount to its category’s running total. After the loop, totals holds the sum per category.

{balance:.2f} — format as money with two decimals.
Common mistakes — and how to avoid them
✗ Checking if category in totals before adding — works, but defaultdict removes the need.
✓ Use defaultdict(float) so new categories start at 0 automatically.
✗ Storing expenses as positive and subtracting elsewhere — easy to get signs wrong.
✓ Store expenses as negative amounts; then summing “just works”.
✗ Forgetting :.2f — money shows with messy decimals.
✓ Format money with two decimal places.

4 Test & Prove Each Part

We test the two summaries — total balance and per-category grouping — with known entries.

The balance is the sum of all amounts
Expenses (negative) reduce the balance
Category totals group amounts correctly
Pythontest_budget.py
from collections import defaultdict


def balance(entries):
    return sum(e["amount"] for e in entries)


def by_category(entries):
    totals = defaultdict(float)
    for e in entries:
        totals[e["category"]] += e["amount"]
    return dict(totals)


def test_balance():
    """Balance sums all amounts."""
    entries = [{"amount": 100, "category": "pay"}, {"amount": -30, "category": "food"}]
    assert balance(entries) == 70


def test_expenses_reduce():
    """Negative amounts reduce the balance."""
    assert balance([{"amount": -50, "category": "rent"}]) == -50


def test_grouping():
    """Amounts group and total by category."""
    entries = [{"amount": -10, "category": "food"}, {"amount": -5, "category": "food"}]
    assert by_category(entries)["food"] == -15

Run with pytest -v. The balance and by_category functions hold the summarising logic, tested against entries where we know the totals. This is exactly how real reporting code is tested.

5 The Interface

INPUTamount + categorynumber (neg for expense) and label
What it expects
Amount: -25
Category: groceries
OUTPUTbalance + breakdowntotals, saved to file
What it returns
Balance: 475.00
groceries: -125.00
salary: 600.00

6 Run It & Automate It

Run it locally
python3 budget.py
Add income and expenses, then check your balance and category breakdown.

Jenkins runs the tests automatically — each line explained below.

What you should see when it works
Terminala real run
Choose: 2
Balance: 475.00

Choose: 3
salary: 600.00
groceries: -125.00
If it breaks — how to fix it
🚨 Balance looks wrong.
Check expenses are stored as negative numbers, not positive.
🚨 KeyError in the category breakdown.
Use defaultdict(float) instead of a plain dict so missing keys default to 0.
GroovyJenkinsfile
// Jenkinsfile — automated tests on every change.
pipeline {
    agent any
    stages {
        stage('Get the code') { steps { checkout scm } }       // download the code
        stage('Install') { steps { sh 'python3 -m venv venv && . venv/bin/activate && pip install pytest' } }  // test tool
        stage('Test') { steps { sh '. venv/bin/activate && pytest -v' } }   // run every test
    }
    post {
        success { echo 'All tests passed.' }
        failure { echo 'A test failed — look above.' }
    }
}
🎯 Try this next — make it yours
  1. Monthly view. Add a date and total by month. (Teaches: dates and grouping.)
  2. Budget limits. Warn when a category exceeds a set limit. (Teaches: comparisons on totals.)
  3. Biggest expense. Find the single largest spend. (Teaches: max with a key.)
What you learned
You learned to record transactions as structured entries and summarise them two ways: a grand total with sum() and a per-group breakdown with defaultdict. Totalling and grouping is the engine behind every dashboard and report. Related: collections, Comprehensions.