← Back to Python series
🛠
Practice Projects · ★★★
File I/O · Encryption · Search · Markdown · OOP · State machine · JSON maps · Parser · argparse · subcommands · Config · Entry point · pandas · argparse · Jinja2 · HTML report

Project 11 — Diary App · Project 12 — Text Adventure Game · Project 13 — Argparse CLI Tool · Project 14 — CSV Report CLI

Write encrypted daily journal entries, search past entries by keyword or date, and export to Markdown. Build a text adventure game with rooms, items, NPCs, and a simple command parser. Load the world map from a JSON file. Build a professional command-line tool with argparse subcommands, a config file, logging, and a pip-installable entry point. Analyse a CSV file from the command line: filter rows, compute statistics, and generate HTML and Markdown reports using Pandas and Jinja2 templates.

file I/OencryptiondiarysearchmarkdownOOPgameparserstate machineJSONargparseCLIsubcommandsconfigentry_pointCSVpandasJinja2HTML report
Duration
⏱ 2.5 hours + 3 hours + 2.5 hours + 3 hours
Level
📊 Intermediate-Advanced Applied
Prerequisite
🎯 Intermediate Week 6
OUTCOME
An encrypted diary app with keyword search and Markdown export / A playable text adventure game loaded from a JSON world file / A pip-installable CLI tool with subcommands and config file support / A CLI that transforms CSV files into formatted HTML/Markdown reports

What you'll learn

  • 1Store entries as individual .txt files with date filenames
  • 2Encrypt entries with a simple XOR cipher (or Fernet from cryptography)
  • 3Search all entries for a keyword
  • 4Export selected entries to a single Markdown file
  • 5Model the game world as a graph of Room objects
  • 6Implement Player state (inventory, health, location)
  • 7Parse two-word commands: go north, take sword, use key
  • 8Load the entire world map from world.json
  • 9Implement subcommands with add_subparsers
  • 10Read config from ~/.toolrc (JSON or TOML)
  • 11Add --verbose and --quiet logging levels
  • 12Write a setup.py / pyproject.toml entry point
  • 13Load and validate CSV with Pandas
  • 14Filter, group, and aggregate data
  • 15Render an HTML report with a Jinja2 template
  • 16Export filtered data to a new CSV

Project 11 — Diary App

Write encrypted daily journal entries, search past entries by keyword or date, and export to Markdown.

Entry Format

text
# 2024-05-15
Mood: 😊
Weather: Sunny

Today I started a new Python project. The weather was great,
and I managed to finish the basic structure in a few hours...

Commands

  • write [date] — open editor for today's entry (or specified date)
  • read [date] — display entry for a date
  • search <keyword> — find all entries containing keyword
  • export [from] [to] — export date range to diary.md
  • stats — word count, mood distribution, writing streak

Project 12 — Text Adventure Game

Build a text adventure game with rooms, items, NPCs, and a simple command parser. Load the world map from a JSON file.

Commands

  • go <north|south|east|west> — move between rooms
  • look — describe current room
  • take <item> / drop <item>
  • use <item> [on <target>]
  • inventory — show carried items
  • talk <npc> — NPC dialogue
  • save / load — save and restore game state

Sample Session

text
You are in a dark dungeon entrance.
Exits: north, east
Items: torch, rusty key

> take torch
You pick up the torch.
> go north
You enter a locked iron door room.
The door is locked.
> use rusty key on door
The door opens with a creak!
> go north
You enter the treasure room. You win!

Project 13 — Argparse CLI Tool

Build a professional command-line tool with argparse subcommands, a config file, logging, and a pip-installable entry point.

Usage

bash
# Install
pip install -e .

# Usage
mytool --help
mytool init [--name NAME]
mytool run <file> [--dry-run] [--output FILE]
mytool config set <key> <value>
mytool config get <key>

Config File

json
// ~/.toolrc
{
  "output_dir": "./output",
  "log_level": "INFO",
  "max_workers": 4
}

Common Mistakes (FAQ)

Q. How do I structure subcommands like `git commit`?

sub = parser.add_subparsers(dest='command'); then sub.add_parser('init'), sub.add_parser('run'), each with its own add_argument. Dispatch on args.command. Set required=True (Py3.7+) so running with no subcommand shows help instead of silently doing nothing.

Q. My numeric argument arrives as a string.

argparse keeps everything as str unless you say otherwise: add_argument('--workers', type=int). Same for float. Without type=, '4' + 1 raises a TypeError.

Q. How do I make a boolean flag like --dry-run?

Use action='store_true' (and 'store_false' for the inverse). The flag then takes no value: --dry-run sets args.dry_run = True, absent = False.

Q. After `pip install -e .` the `mytool` command isn't found.

Define a console_scripts entry point in pyproject.toml ([project.scripts] mytool = 'pkg.cli:main'), reinstall with pip install -e ., and reopen the shell so PATH picks up the new script.

Q. Reading ~/.toolrc fails the first time.

Expand the home dir with Path.home() / '.toolrc' (not a literal '~'), and handle the missing-file case: if it doesn't exist, fall back to defaults instead of crashing.

Project 14 — CSV Report CLI

Analyse a CSV file from the command line: filter rows, compute statistics, and generate HTML and Markdown reports using Pandas and Jinja2 templates.

Usage

bash
csvreport data.csv --group department --agg mean --cols salary,age
csvreport data.csv --filter 'salary > 50000' --output filtered.csv
csvreport data.csv --html report.html
csvreport data.csv --md report.md

Common Mistakes (FAQ)

Q. A comma inside a field splits my row wrong.

Don't parse CSV with line.split(','). Use pandas.read_csv (or the stdlib csv module) — they correctly handle quoted fields like "Smith, John" and embedded commas/newlines.

Q. I get a UnicodeDecodeError or mojibake on a CSV from Excel.

Excel often saves UTF-8 with a BOM. Read with encoding='utf-8-sig' (handles BOM and plain UTF-8); for legacy Korean files try 'cp949'. Always pass an explicit encoding rather than relying on the OS default.

Q. --filter 'salary > 50000' — how do I apply it safely?

Use df.query("salary > 50000") instead of eval(). Column names with spaces need backticks in the query string: df.query("`net pay` > 50000").

Q. My exported CSV has a blank line between every row (Windows).

With the csv module, open the file with newline='' . With pandas, df.to_csv('out.csv', index=False) avoids both the blank-line issue and an unwanted index column.

Q. group + aggregate returns a weird multi-index.

df.groupby('department')[['salary','age']].mean().reset_index() flattens it back to plain columns — call reset_index() before rendering to HTML/Markdown.

📝 Exercises

Try them yourself first, then open the solution to compare.

Exercise 1

Build the diary app

Goal: Implement write, read, search, and export with optional encryption.

Requirements
  • Date-based file naming
  • read/write commands
  • Keyword search across all entries
  • Markdown export
Exercise 2

Build the text adventure

Goal: Implement a playable 5-room adventure with items and a win condition.

Requirements
  • 5+ rooms with connections
  • 3+ items with use actions
  • JSON world file
  • Save/load game state
Exercise 3

Build the CLI tool

Goal: Implement a CLI with at least 3 subcommands, config file, and entry point.

Requirements
  • 3+ subcommands with argparse
  • Config read/write with ~/.toolrc
  • --verbose/-v flag
  • pip-installable entry point
Exercise 4

Build the CSV report CLI

Goal: Implement filtering, grouping, and HTML/Markdown output.

Requirements
  • --filter flag with pandas query
  • --group and --agg flags
  • HTML report with Jinja2
  • CSV export of filtered results
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗

Comments 0

No comments yet. Be the first.

Only members can comment.

Comments with ads, abuse, personal information or illegal content are hidden or removed. Comments are shown with your nickname. Privacy Policy