ExoSnip Code Snippets

Python Snippets

← Back to Home

About Python

Python is great for scripting, backend work, automation, and data processing. This track covers practical fundamentals and a mini CLI project.

Create Virtual Environment and Install Tools

Isolate dependencies for each project and keep setup reproducible.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install pytest

Project Structure for Python CLI Learning

Separate application modules, data, and tests from the start.

habit-tracker/
  app/
    __init__.py
    models.py
    storage.py
    cli.py
  data/
    habits.json
  tests/
    test_storage.py
  requirements.txt

Model Data with dataclass (app/models.py)

dataclass gives readable domain objects without boilerplate.

from dataclasses import dataclass

@dataclass
class Habit:
    id: str
    name: str
    streak: int = 0
    completed_today: bool = False

JSON Storage Helpers (app/storage.py)

Keep file operations in one module for easier testing.

import json
from pathlib import Path

DATA_FILE = Path("data/habits.json")

def read_habits() -> list[dict]:
    if not DATA_FILE.exists():
        return []
    return json.loads(DATA_FILE.read_text())

def save_habits(habits: list[dict]) -> None:
    DATA_FILE.write_text(json.dumps(habits, indent=2))

CLI with argparse (app/cli.py)

Use subcommands to grow from one script into a maintainable CLI.

import argparse

def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(prog="habit")
    sub = parser.add_subparsers(dest="command", required=True)

    add_cmd = sub.add_parser("add")
    add_cmd.add_argument("name")

    sub.add_parser("list")
    return parser

CLI Command Dispatch (app/cli.py)

Parse arguments once, then delegate to focused command functions.

from app.commands import add_habit, list_habits

def main() -> None:
    parser = build_parser()
    args = parser.parse_args()

    if args.command == "add":
        add_habit(args.name)
    elif args.command == "list":
        list_habits()

if __name__ == "__main__":
    main()

Mini Project: Add Habit Command

Command handlers should validate input and persist changes.

from uuid import uuid4
from app.storage import read_habits, save_habits

def add_habit(name: str) -> None:
    habits = read_habits()
    habits.append({
        "id": str(uuid4()),
        "name": name,
        "streak": 0,
        "completed_today": False,
    })
    save_habits(habits)

Mini Project: Mark Habit Complete

Update one record safely and keep command behavior deterministic.

from app.storage import read_habits, save_habits

def complete_habit(habit_id: str) -> bool:
    habits = read_habits()
    for habit in habits:
        if habit["id"] == habit_id:
            habit["completed_today"] = True
            habit["streak"] += 1
            save_habits(habits)
            return True
    return False

Automated Test Example (tests/test_storage.py)

Test critical persistence behavior before adding more commands.

from app.storage import save_habits, read_habits

def test_round_trip(tmp_path, monkeypatch):
    from app import storage
    monkeypatch.setattr(storage, "DATA_FILE", tmp_path / "habits.json")

    expected = [{"id": "1", "name": "Read", "streak": 2, "completed_today": False}]
    save_habits(expected)
    assert read_habits() == expected

Run the Habit Tracker

Run these commands while practicing the mini project flow.

python -m app.cli add "Workout"
python -m app.cli list
pytest -q

Next Learning Upgrades

Use this path to evolve your Python snippets into real tooling.

1. Add rich terminal output with rich or typer.
2. Add SQLite persistence with SQLModel.
3. Add cron-based reminders for missed habits.
4. Add packaging with pyproject.toml.
5. Add GitHub Actions test automation.