Lesson 1 of 0
In Progress

Unit 6 – Teachers Guide

Unit 6 · Teacher's Guide | Knowledge Pillars · Code Quest
📚 Teacher's Guide Code Quest · Coding Fundamentals

Unit 6 · Files, JSON, Errors & Modules

Your day-to-day companion for delivering Unit 6 — pacing, standards, lesson plans, misconceptions, differentiation, and a Python error appendix. Unit 6 is the unit where students' code stops being alone. They learn to talk to files on disk, lean on Python's standard library, recover from errors with try/except, save structured data with JSON, and split projects across multiple files using their own modules. The capstone — the Persistent Contact Vault — turns the Unit 5 vault into real software whose data survives between runs.

📂 5 Lessons + Capstone
⏱️ 8–10 class periods
🎓 Florida Course #9009200

👋 Welcome — How to Use This Guide

This Teacher's Guide is your day-to-day companion for delivering Unit 6 of the Code Quest curriculum. Unit 6 is the unit where students' programs stop being alone. Their code now talks to files on disk, leans on Python's standard library, recovers from errors with try/except, speaks the JSON language of every web API, and gets organized across multiple files using their own modules. The capstone — the Persistent Contact Vault — turns the Unit 5 vault into real software whose data survives between runs. It picks up after Unit 5 and assumes students are fluent with all four data structures (list, dict, tuple, string), functions, the SDLC, and the modular thinking from Unit 4.

What this guide contains

  • A pacing guide showing how Unit 6 maps to roughly 8–10 class periods. All five lessons run 50 minutes (lesson 5 is a 2-day capstone). Unit 6 carries the heaviest combined "Python toolbox" load of any unit — file I/O, exception handling, JSON, modules, and custom modules all in one stretch.
  • A standards & exam crosswalk. Unit 6 is the home of standards 03.01 (file types) and 03.02 (file operations), and provides the deepest coverage of 07.07 (debugging via exception handling).
  • A unit vocabulary glossary with all 21 key terms students will encounter — most are concrete Python tools (functions, keywords, modules) they'll use repeatedly for the rest of their career.
  • Five detailed lesson plans using the same 7-section format from prior guides.
  • An appendix covering file/exception/JSON/import errors: FileNotFoundError, PermissionError, json.JSONDecodeError, ModuleNotFoundError, the silent bug of forgetting with, and the classic "circular import" pitfall.

How each lesson plan is structured

Same 7-section format used in prior units:

  • At-a-Glance — objective, time, materials, vocabulary, standards box
  • Lesson Flow — a 50-minute breakdown: warm-up, instruction, guided practice, lab, exit ticket
  • Watch For — the 3–5 most common student misconceptions and how to address each
  • Differentiation — early finishers and struggling students
  • Discussion Prompts — questions to spark whole-class conversation
  • Real-World Connections — answering "why does this matter?"
  • Lesson-Specific Vocabulary — terms introduced or reinforced

How to read this in conjunction with the student lessons

  • Before class: read this lesson plan (5–10 min) and skim the student HTML, noting the interactive widgets — the Standard Library Explorer in L4 is the unit's marquee tool, with live random/datetime/math/os playgrounds
  • During class: follow the lesson flow; the student HTML is the textbook + lab
  • After class: grade Knowledge Checks and labs against this guide's expectations
💡 Unit 6 is the "professionalization" unit. After Unit 6, students are no longer writing scripts — they're building software. The capstone (Persistent Contact Vault) is the hinge: it turns the in-memory toy from Unit 5 into a real app whose data survives. Don't shortcut the capstone's two-file architecture. The discipline of separating contact_vault.py (UI) from vault_io.py (disk & timestamps) is exactly the discipline professional projects are built on. The student who internalizes Unit 6 well writes Python that looks like Python from a real codebase from this point forward.

🗺️ Unit 6 Overview

The big picture

Unit 6 is "Files, JSON, Errors & Modules" — the four tools that turn scripts into software. Lesson 1 introduces file I/O with the with open() pattern. Lesson 2 adds try/except for handling the inevitable disasters that file work brings. Lesson 3 introduces JSON — Python's universal data-saving format and the language every web API speaks. Lesson 4 introduces the standard library — Python's giant pre-built toolbox. Lesson 5 teaches custom modules (any .py file is a module) and culminates in the Persistent Contact Vault, the Unit 5 vault upgraded with real disk-backed memory.

What students learn

  • Open, read, write, and append to text files using the with open() pattern
  • Choose the right file mode: "r" (read), "w" (write — overwrites), "a" (append), "r+" (read+write)
  • Read files three ways: .read(), .readlines(), and the line-by-line iteration pattern (for line in file)
  • Catch and handle errors gracefully with try, except, else, finally
  • Catch specific exceptions (FileNotFoundError, ValueError) — never bare except:
  • Save and load Python data using JSON with json.dump/json.load (file) and json.dumps/json.loads (string)
  • Recognize that JSON is just nested dicts and lists in text form — Python and JSON look almost identical
  • Pretty-print JSON with the indent=2 argument
  • Import modules from Python's standard library using three forms: import x, from x import y, import x as y
  • Use random (randomness), datetime (timestamps), math (sqrt, π), and os (file paths)
  • Discover module capabilities with dir(module) and help(function)
  • Recognize that any .py file is a module — and split projects into multiple files that import each other
  • Use the if __name__ == "__main__": guard to make modules both importable AND runnable
  • Build the Persistent Contact Vault: a two-file architecture (UI + I/O) with full SDLC, error handling, and timestamps

Prerequisites

Units 1–5. Students must be fluent with: variables, all data types, conditionals, both loops, lists, dictionaries (especially .get()), tuples, string methods, functions with parameters & returns, scope, the SDLC, and the algorithm-first planning habit. Unit 6 doesn't introduce new syntax beyond with, try/except, and import — most of the unit is wiring familiar tools to disk.

What comes next

Unit 7 introduces Object-Oriented Programming — classes and methods. Students will learn to bundle data and behavior together into reusable objects. Unit 6's modules become the natural home for those classes. The Persistent Contact Vault from Unit 6 becomes the foundation that Unit 8's Weather Dashboard builds on (real APIs replace local JSON files).

Materials you'll need

  • Computers with web browser access (one per student, or pairs)
  • Knowledge Pillars CodeSkills Lab access
  • Projector or large screen — Unit 6's interactive widgets (Standard Library Explorer in L4 especially) work best in projection
  • Whiteboard with multiple colors — used heavily in Lesson 1 (file modes), Lesson 2 (control-flow diagrams for try/except), and Lesson 5 (two-file architecture diagram)
  • Optional: printed file-mode reference card (one per student) — tape to monitor for Lesson 1 labs
  • Optional: printed standard-library cheat sheet — Lesson 4 students reach for this constantly
🎯 Course alignment. Unit 6 is the home of Florida CTE standards 03.01 (file types) and 03.02 (basic file operations — open, read, write, close), and provides the deepest coverage of 07.07 (debugging) via exception handling. The unit also introduces 06.02 (apply troubleshooting in the SDLC) at full depth — try/except IS troubleshooting in code form. Exam Objective 4 (write & debug simple programs) is the unit's flagship objective. See the Standards Crosswalk below for full detail.

⏱️ Pacing Guide

Unit 6 is designed for 8–10 class periods. All five lessons run 50 minutes; Lesson 5 is a 2-day capstone. The unit moves fast — five distinct tools in five lessons — but each tool builds on the last. Don't compress unless your class has shown strong fluency through Unit 5.

Recommended pacing — 9-day plan

DayLessonFocusHomework
Day 1L1: Reading & Writing FilesWhat a file is. with open() pattern. File modes. Reading 3 ways. Writing/appending. Lab 6.1A.Read L1 Section 5 (writing examples)
Day 2L1: Files (continued) + L2 introFinish file labs. Knowledge check. Preview L2 motivation.Read L2 Sections 1–3 (try/except basics)
Day 3L2: try / exceptException types. try/except control flow. Specific exceptions. else/finally. Lab 6.2A.Read L3 Sections 1–2 (JSON intro)
Day 4L3: JSONWhy JSON exists. Python ↔ JSON mirror. The 4 functions (dump, load, dumps, loads). Pretty-printing. Safe loading. Lab 6.3A.Plan a "save my favorites" mini-app
Day 5L4: Modules & Standard LibraryModule concept. Three import forms. Standard Library Explorer (random, datetime, math, os). Recipes. Lab 6.4A.Read L5 Sections 1–3 (custom modules)
Day 6L5: Custom ModulesAny .py is a module. The __main__ guard. Two-file project. Walk through capstone scaffold. Plan starts.Continue planning capstone
Day 7L5: Capstone (pt 1)SDLC stages 1–2: Plan + Code. Build vault_io.py first. Then wire contact_vault.py to use it.Continue building at home
Day 8L5: Capstone (pt 2)SDLC stages 3–5: Test + Fix + Maintain. Especially: corrupt-file recovery test. Showcase. Submit.—

Compressed 8-day pacing

If you need to compress: combine Day 1 and Day 2 (cover all of Lesson 1 in one period). Most classes can — file I/O is conceptually simple after Unit 5's data-structure work. But the pattern with open() needs repeated practice; if students aren't using it automatically by the end of Day 1, slow down.

Extended 10-day pacing

If your class needs more time: split Lesson 5 across three days. Day 6 covers custom modules in isolation (no capstone yet). Day 7 = capstone Plan + Code. Day 8 = capstone Test + Fix. Day 9 = capstone Maintain + Showcase. The two-file architecture is one of the most professionally valuable concepts in the entire course; give it room.

⏱️ Where the time usually goes. Lesson 1 (files) often runs FAST — the with open() pattern is intuitive after Unit 5. Lesson 2 (try/except) takes longer than expected because the control flow is genuinely new — students need to TRACE through what runs when an exception fires. Lesson 3 (JSON) often clicks immediately ("oh, it's just dicts as text"). Lesson 4 (standard library) is fun and energetic if you use the Explorer widget heavily. Lesson 5 always benefits from the full 2 days; the two-file architecture is the unit's hinge.

Suggested grading weights for Unit 6

ComponentWeightNotes
Lesson Knowledge Checks (×4)15%3 questions each, completed in-platform
Lab Exercises (×8)30%CodeSkills Lab + a few file-on-disk labs in L1 and L3
Persistent Contact Vault Final Project45%Capstone — 100-pt rubric in Lesson 5 plan
Class participation10%Whiteboard work, Standard Library Explorer demos, peer testing

Note: Persistent Contact Vault is the third 45%-weighted capstone in a row (Mad Libs 4.0, Contact Vault, Persistent Contact Vault). The pattern is intentional — second-half-of-year capstones are heavier because they integrate more skills. A student who does well on this capstone has demonstrated end-to-end software thinking: file I/O, error handling, JSON, modules, AND everything from Units 1–5.

🎓 Standards & Exam Crosswalk

This crosswalk shows exactly which Florida CTE standards and Coding Fundamentals exam objectives each lesson addresses. Use this for admin reviews, IEP documentation, or to prove alignment when adopting the curriculum. Unit 6's primary "new" standards are 03.01 (file types), 03.02 (file operations), and 06.02 (troubleshooting in the SDLC). The capstone (Persistent Contact Vault) covers the broadest set of standards in any unit so far — file I/O + JSON + try/except + modules + everything from Units 1–5.

Florida CTE Standards — Course #9009200

Standards from the Florida Department of Education Coding Fundamentals curriculum framework that Unit 6 addresses:

StandardDescriptionLessons
01.01Use specialized computer coding software to solve problems.All (CodeSkills Lab)
01.02Demonstrate proficiency using specialized computer software (e.g., Python).All
02.02Explain the components of programming languages.L1, L2, L3, L4, L5
03.01Identify and describe text-based file types (txt, csv, json).L1, L3 — primary unit standard
03.02Demonstrate basic file operations (open, read, write, close).L1, L3, L5 — primary unit standard
04.03Demonstrate sorting and filtering of data sets.L5 (vault search/filter)
05.06Recognize that more than one algorithm can solve a given problem.L1 (3 ways to read a file), L2 (try/except patterns)
05.07Create a program that implements an algorithm to achieve a given goal.L5 (Persistent Contact Vault)
06.02Apply troubleshooting techniques within the SDLC.L2, L5 — primary unit standard
06.03Apply iterative debugging within the SDLC.L5 (capstone testing)
07.01Describe the structure of a simple program; explain why sequencing is important.L5 (modular architecture)
07.05Explain the types and use of variables in programming.L1 (file objects), L4 (module-scoped names)
07.07Troubleshoot and debug errors in code.L2, L5 — full depth via exception handling

Coding Fundamentals Exam Objectives

Exam objectives that Unit 6 prepares students for. Objective 4 (write & debug simple programs) is the unit's flagship; the capstone is its culminating performance task.

ObjTitleCoverage in Unit 6Lessons
1Core programming conceptsContinued — file I/O and modules are coreL1, L4, L5
3Algorithm understanding & designReinforced — capstone planningL5
4Write and debug simple programsFull coverage — primary objective for the unitL1, L2, L3, L4, L5
5Data manipulationJSON ties Unit 5 data shapes to diskL3, L5
7Debugging techniquesFull coverage — try/except as systematic recoveryL2, L5

Lesson-by-lesson alignment

LessonFlorida StandardsExam Objectives
L1: Reading & Writing Files01.01, 01.02, 02.02, 03.01, 03.02, 07.051, 4 (primary)
L2: try / except01.01, 01.02, 02.02, 05.06, 06.02, 06.03, 07.074, 7 (primary)
L3: JSON01.01, 01.02, 02.02, 03.01, 03.02, 05.071, 4, 5 (primary)
L4: Modules & Standard Library01.01, 01.02, 02.02, 07.051, 4 (primary)
L5: Custom Modules + Persistent Vault01.01, 01.02, 02.02, 03.02, 04.03, 05.06, 05.07, 06.02, 06.03, 07.01, 07.05, 07.071, 3, 4 (primary), 5, 7
📋 What's not in Unit 6. These standards are NOT addressed in Unit 6 and appear in later units: 03.03 (binary file types — images, audio) — touched in Unit 7+ but not depth · 04.01 (data types — primitives) — already covered in Unit 1 · 04.02 (data types — collections) — already covered in Units 5 & 6 · 07.02 (algorithms, deeper) — already covered in Unit 3 · 07.03 (loops, deeper) — already covered in Unit 2 · 07.04 (selection structures, deeper) — already covered in Units 1–2 · 07.06 (pseudocode/flowcharts) — already covered in Unit 3 · 07.08 (databases) — Unit 10. Note: students APPLY 07.02–07.05 throughout Unit 6 even though those standards are not its focus.

📖 Unit 6 Vocabulary Glossary

All 21 key terms students will encounter in Unit 6. The "Intro" column shows the lesson where each term first appears. Each lesson plan also includes its own focused vocabulary list. Most of Unit 6's vocabulary is concrete Python — keywords, functions, and modules students will type and run repeatedly.

TermDefinitionExampleIntro
FileA named chunk of bytes on disk. Text files contain readable characters; binary files contain raw bytes (images, etc).contacts.jsonL1
open()Built-in function that creates a file object Python can read or write.open("notes.txt", "r")L1
with statementContext manager that auto-closes a file when the block ends — even if an error fires. The pro pattern for file work.with open(...) as f:L1
File ModeThe string passed to open() declaring what you'll do: "r" read, "w" write (overwrites), "a" append, "r+" read+write.open(f, "a")L1
.read() / .readlines()Two ways to slurp a file's contents. .read() = one big string. .readlines() = list of lines.f.read(), f.readlines()L1
ExceptionAn error event that interrupts normal program flow. Python raises one when something unexpected happens.FileNotFoundErrorL2
try / exceptBlock syntax for catching exceptions. Code in try runs; if an exception fires, the matching except runs instead of crashing.try: ... except: ...L2
else / finallyOptional add-ons. else runs if try succeeded. finally ALWAYS runs (cleanup).finally: file.close()L2
Specific ExceptionCatching a NAMED exception (e.g. except FileNotFoundError) rather than a bare except:. The professional pattern.except ValueError:L2
Bare exceptCatching ALL exceptions with except: — almost always wrong. Hides bugs. Use specific exceptions.except: ⚠️ AVOIDL2
JSONJavaScript Object Notation. A text format for structured data. Looks almost identical to Python dicts/lists. The universal data-exchange format.{"name": "Alex"}L3
json.dump() / json.load()FILE versions: dump writes Python data to a file as JSON; load reads JSON from a file back to Python.json.dump(data, f)L3
json.dumps() / json.loads()STRING versions: dumps turns Python data into a JSON STRING; loads parses a JSON string. The "s" = string.json.dumps(d, indent=2)L3
ModuleA Python file containing reusable code (functions, classes, constants). Loaded with import.import mathL4
Standard LibraryThe collection of modules that ship free with every Python install. random, datetime, json, os, math, etc.No install needed!L4
importKeyword that loads a module. Goes at the top of the file.import randomL4
from / asVariants of import. from x import y grabs ONE tool. as renames it locally.from random import randintL4
random / datetime / math / osThe four standard-library modules students use most. Random numbers, dates & times, math functions, file paths.random.randint(1, 6)L4
Custom ModuleA .py file YOU wrote that another file imports. Same mechanism as standard library; same syntax.import vault_ioL5
__main__A special variable Python sets to "__main__" when a file is run directly. Used to make modules importable AND runnable.if __name__ == "__main__":L5
Two-File ArchitectureSplitting a project into a UI/main file plus one or more helper modules. The Unit 6 capstone uses this pattern.contact_vault.py + vault_io.pyL5
📖 Teaching tip. 21 terms is heavy — but the four students MUST own by end of unit are: open() (talk to files), try/except (handle errors), JSON (save structured data), and import (use other code). Master those four and the rest follow naturally. The five lesson plans each have their own focused vocab subset; this glossary is the unit-wide reference.

📄 Lesson 1 · Reading & Writing Files

Lesson 1 · Reading & Writing Files

Lesson Plan

At-a-Glance

Objective
Students will use the with open() pattern to safely read and write text files, choose the correct file mode ("r", "w", "a") for the task, read files three ways (.read(), .readlines(), line-by-line iteration), and recognize that "w" mode OVERWRITES — a critical safety point.
Time
50 minutes
Materials
Computer, CodeSkills Lab, projector, optional printed file-mode reference card
Vocabulary
File, open(), with statement, File Mode, .read(), .readlines()
FL Standards
01.01, 01.02, 02.02, 03.01, 03.02, 07.05
Exam Obj.
Objectives 1, 4 (primary)

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Project the Mad Libs 4.0 from Unit 4 with this question: "When you closed the program, where did the words go?" Take answers — they vanished.
  • Reveal: today is the day Python's programs stop being amnesiac. We're going to make data SURVIVE. The tool: text files on disk.

🎤 Direct Instruction (15 min)

  • Open Lesson 6.1 on the projector. Walk through Section 1 ("What Is a File, Really?"). A file = a named chunk of bytes on disk. Text files are readable; binary files are images, audio, etc. Today is text files.
  • Walk through Section 2 ("The with open() Pattern"). Live-code:
    with open("notes.txt", "w") as f:
        f.write("Hello!")
  • The two parts: open("filename", "mode") creates a file object; with ... as f: auto-closes it when the block ends — even if an error fires. The professional pattern.
  • Walk through Section 3 ("File Modes"). Drill the three:
    • "r" — read existing file. Crashes if it doesn't exist.
    • "w" — write. OVERWRITES the entire file. Creates if missing. Drill this safety point.
    • "a" — append. Adds to the end. Creates if missing. Use when you don't want to lose existing content.
  • Walk through Section 4 ("Reading From a File"). Three ways:
    • content = f.read() — entire file as one string. Use for small files.
    • lines = f.readlines() — list of lines (with \n at end of each).
    • for line in f: — line-by-line iteration. Memory-efficient for huge files.
  • Walk through Section 5 ("Writing to a File"). f.write("text") doesn't add newlines automatically — students must add "\n" themselves if they want one. Common surprise.

🤝 Guided Practice (8 min)

  • On the whiteboard, present 4 scenarios. For each, the class names the right mode:
    • "Add a new entry to a journal file" → "a"
    • "Read student names from a roster" → "r"
    • "Replace a file with new content" → "w"
    • "Show a help file to the user" → "r"
  • Live-demo the "w" safety risk: create a file with content, open it in "w" mode, write nothing, close. Reopen and read — empty. The "w" mode wiped it. Drill this.

💻 Independent Lab (17 min)

  • Lab 6.1A — "Journal Writer": students build a tiny journal program. Prompts for an entry, appends to journal.txt with a timestamp prefix, then reads back and prints all entries. Required: "a" mode for writes, "r" for reads.
  • Lab 6.1B — "Word Counter": students read poem.txt (provided) line-by-line, count total words across all lines, print the count. Required: for line in f: pattern.
  • Circulate. Common bugs: forgetting with (file stays open and locked); using "w" when they meant "a" (data wiped on every save — students panic when their journal "loses" entries); forgetting \n when writing (everything runs together on one line).

🚪 Exit Ticket (5 min)

  • On paper: "What's the difference between open(f, "w") and open(f, "a")? Give one example of when you'd use each."
  • Answer: "w" overwrites everything in the file; "a" adds to the end. Use "w" when you want to replace (saving a config). Use "a" when you want to add (logging, journals).

⚠️ Watch For — Common Misconceptions

1. ""w" mode appends."
What you'll see: A student writes 10 journal entries in "w" mode. Only the LAST one is in the file. Panic. Tears.
How to address: Drill the safety rule: "w" WIPES. It opens the file empty. Whatever was there is GONE. For adding, use "a". The mnemonic: "w" = wipe + write; "a" = add. Recover lost data only if a backup exists; this is why pros version-control everything.
2. "Forgetting with."
What you'll see: f = open("x.txt"); content = f.read() with no f.close(). File stays open, gets locked, sometimes data isn't flushed to disk.
How to address: Drill the with open() as f: pattern as the default. It auto-closes — handles cleanup even when errors fire. Manual open()+close() exists but is the wrong pattern for this course. Mark a deduction in the rubric for any file work without with.
3. "f.write() adds newlines automatically."
What you'll see: f.write("Alex"); f.write("Sam") — file contains "AlexSam" on one line. Surprise.
How to address: f.write() does NOT add newlines. You must include \n yourself: f.write("Alex\n"). print() adds newlines automatically, but file writes don't. Different functions, different defaults.
4. "Reading a file twice in a row."
What you'll see: data1 = f.read(); data2 = f.read() — second read returns empty string. Confusion.
How to address: Files have a "cursor." After .read(), the cursor is at the end. To re-read, you'd need to seek back or reopen. For most beginner work: read once, store the result in a variable, use that variable.

🎯 Differentiation

For early finishers
Challenge: write a "log file rotator" — read the existing log; if it has more than 100 lines, keep only the last 50; write back. Stretch: research seek() and tell() (file cursor control) and explain in 2 sentences when they're useful.
For struggling students
Skip Lab 6.1B. Stay on Lab 6.1A and focus on: write to a file with "a", then read back with "r". The win: a working journal that adds entries and reads them. The line-by-line iteration pattern can be revisited.

💬 Discussion Prompts

  • Why does Python automatically close files at the end of a with block? (Files are scarce OS resources. Open files stay locked. Forgetting to close has historically been a major bug source. The with pattern automates the cleanup.)
  • What kinds of data would you NEVER store in a text file? (Passwords (use hashed storage). Credit cards (use a secure DB). Anything binary like images (use binary mode). Anything that needs concurrent access by many users (use a database — Unit 10).)
  • How is reading a file like reading a book? (There's a "cursor" — the page you're on. Once you read forward, you're past those pages. To re-read, you flip back. Files work the same way.)

🌍 Real-World Connections

  • Save files in games. Every game-save is a file write — usually JSON or a custom format. When you "load," it's a file read. Same pattern as today's lesson.
  • Configuration files. Almost every app has one — .gitconfig, settings.json, preferences.plist. They're text files with structured data.
  • Logs. Every server, every web app, every IoT device writes log files — typically in append mode, never overwriting. When something breaks, engineers read the logs to find out what happened.
  • Receipts and invoices. When your phone emails you a receipt, somewhere a system wrote a file (or DB record). Files are the basic unit of "data that survives the program."

📖 Lesson-Specific Vocabulary

File — A named chunk of bytes on disk.
open() — Built-in function that creates a file object.
with statement — Context manager that auto-closes a file when the block ends.
File Mode — "r" read, "w" write (overwrites!), "a" append.
.read() / .readlines() — Two ways to slurp a file's contents. .read() = one big string. .readlines() = list of lines.
↑ Back to top

🛡️ Lesson 2 · try / except — Catching Exceptions Gracefully

Lesson 2 · try / except

Lesson Plan

At-a-Glance

Objective
Students will use try / except to catch exceptions, name SPECIFIC exception types (never bare except:), trace the control flow when an exception fires, and apply the optional else and finally clauses correctly.
Time
50 minutes
Materials
Computer, CodeSkills Lab, projector, whiteboard with multiple colors for control-flow diagrams
Vocabulary
Exception, try / except, else / finally, Specific Exception, Bare except
FL Standards
01.01, 01.02, 02.02, 05.06, 06.02, 06.03, 07.07
Exam Obj.
Objectives 4, 7 (primary)

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Project a Lesson-1-style file-read program. Then run it with a filename that doesn't exist. Show the FileNotFoundError traceback. Ask: "Should our program crash like this every time someone makes a typo?"
  • Reveal: today we learn how to recover instead of crash. The tool: try / except.

🎤 Direct Instruction (18 min)

  • Open Lesson 6.2 on the projector. Walk through Section 1 ("What Is an Exception?"). An exception = an error event Python raises when something unexpected happens. Up till now, exceptions = your program crashes.
  • Walk through Section 2 ("The try / except Block"). Live-code:
    try:
        f = open("missing.txt")
        content = f.read()
    except FileNotFoundError:
        print("File not found — using defaults.")
        content = ""
  • Walk through Section 3 ("Watch the Control Flow"). On the whiteboard, draw the control flow:
    1. Try block runs.
    2. If NO exception: skip the except. Continue past the block.
    3. If an exception MATCHES: run the except block. Continue past the block.
    4. If an exception DOESN'T MATCH: propagate up — the program might still crash if no outer except catches it.
  • Walk through Section 4 ("Catch Specific Exceptions, Not Everything"). The professional rule: name the exception. except FileNotFoundError: is right; except: is the WRONG pattern. Bare except catches BugReports too — silencing them.
  • Walk through Section 5 ("The Full Block: try/except/else/finally"). Drill:
    • try: — code that might fail
    • except XError: — runs IF that error fires
    • else: — runs IF try succeeded (no exception)
    • finally: — ALWAYS runs (cleanup, even on uncaught errors)
  • Walk through Section 6 ("Real-World Patterns"). Three patterns students will use constantly:
    • Safe file open: FileNotFoundError → use defaults
    • Safe int conversion: ValueError → re-prompt user
    • Safe dict lookup: KeyError → use .get() instead (cheaper)

🤝 Guided Practice (7 min)

  • On the projector, walk through 3 broken programs. For each, students name the exception type and write the right except clause:
    • int("abc") → ValueError
    • nums[10] on a 5-item list → IndexError
    • 5 / 0 → ZeroDivisionError
  • Reinforce: each one is a SPECIFIC exception. Bare except: would catch all 3 — but students wouldn't know which fired.

💻 Independent Lab (15 min)

  • Lab 6.2A — "Safe Calculator": students write a program that asks for two numbers and divides them. Must handle TWO exceptions: ValueError (user types non-number) and ZeroDivisionError. Each gets its own except clause with a friendly message.
  • Lab 6.2B — "Resilient File Reader": students write a function load_safely(filename) that reads a file. On FileNotFoundError, returns "(no file yet)". On any OTHER error, lets it propagate (don't catch what you don't know how to handle).
  • Circulate. The biggest anti-pattern: bare except:. Stop students from writing it. Make them name the specific exception.

🚪 Exit Ticket (5 min)

  • On paper: "Why is except: (bare) almost always the wrong choice? Name two reasons."
  • Looking for: (1) it catches BUGS — silently hides programmer errors. (2) it catches keyboard interrupts (Ctrl-C) — making the program impossible to quit. Either alone earns the point.

⚠️ Watch For — Common Misconceptions

1. "Bare except: is the safe choice."
What you'll see: A student writes except: with no exception name. The program no longer crashes — but it ALSO swallows real bugs silently. Worse than crashing.
How to address: Drill: name the exception. except FileNotFoundError:. except ValueError:. The unnamed form is the wrong pattern in 99% of cases. Mark deductions on the rubric.
2. "else runs whether try succeeded or not."
What you'll see: Confusion about when else runs vs finally.
How to address: else = "things ran fine, here's what to do next." Only runs if try succeeded with no exception. finally = "no matter what happened, do this cleanup." Always runs. Drill with a control-flow diagram on the whiteboard.
3. "try/except can fix any bug."
What you'll see: Students wrap buggy code in try/except hoping the bug "goes away." It doesn't — the bug just runs silently.
How to address: try/except handles EXPECTED errors that you can recover from (file missing, bad input). It does NOT fix logic bugs. Use try/except for "things outside your control" — files, networks, user input. Use the 4-step debugging strategy from Unit 4 for actual bugs.
4. "Catch the wrong exception type."
What you'll see: except FileNotFoundError wrapping int(input()). The exception fires, doesn't match, propagates, program crashes. Student doesn't know why.
How to address: RUN the bad input first. SEE the actual exception type in the traceback. Match it. Don't guess. The traceback's last line names the exception — that's exactly what goes after except.
5. "Wrap EVERYTHING in try/except."
What you'll see: Defensive over-wrapping. Every line gets its own try/except. Code becomes unreadable.
How to address: Wrap the SMALLEST block that could fail. Usually a single risky operation (file open, type conversion, network call). Most lines don't need try/except. The pattern is precision, not paranoia.

🎯 Differentiation

For early finishers
Challenge: write a "robust input function" get_int(prompt) that loops until the user gives a valid integer. Use while True: + try/except ValueError + break. Stretch: research the raise keyword and explain when you'd raise an exception yourself rather than catch one.
For struggling students
Skip Lab 6.2B. Stay on Lab 6.2A and focus on a SINGLE try/except handling ONE specific exception. The win: their division program doesn't crash on letters or zero.

💬 Discussion Prompts

  • What's the difference between an EXCEPTION and a BUG? (Bug = a programmer error, the code is wrong. Exception = an EVENT, an unexpected condition that the code might not control. File missing isn't a bug; division by zero might or might not be — depends on whether you should have validated input first.)
  • Which is "better" — preventing errors, or recovering from them? (Both are needed. Some things you can prevent (validate input). Some you can't (network goes down, file gets deleted by another program). Use prevention when possible; use try/except for what's beyond your control.)
  • If your program catches an exception, should it ALWAYS recover silently? (No. Sometimes you catch, log the error, and re-raise. Sometimes you catch and convert to a friendlier error. The right move depends on context. The wrong move is ALWAYS to swallow silently.)

🌍 Real-World Connections

  • Every web request. When an app fetches data from the internet, the server might be down, slow, or unreachable. Apps use try/except (or equivalent) to gracefully retry or show "connection error" — never to crash.
  • Banking software. Try/except is mandatory in financial code. A network glitch in the middle of a transfer can't crash the program — money is at stake. Robust error handling is a regulatory requirement.
  • Self-driving cars. Sensor data sometimes fails. The car can't crash (literally) when one camera goes offline. It must catch the failure and keep running on the remaining sensors.
  • Mars rovers. NASA can't reboot a rover from Earth quickly. Every line of rover code is wrapped in defensive error handling. A crashed rover is millions of dollars lost.

📖 Lesson-Specific Vocabulary

Exception — An error event that interrupts normal flow.
try / except — Block syntax for catching exceptions.
else / finally — Optional clauses. else runs if try succeeded. finally ALWAYS runs.
Specific Exception — Named exception type. The professional pattern.
Bare except — Catching ALL exceptions with except:. Almost always wrong.
↑ Back to top

📦 Lesson 3 · JSON — Saving Structured Data

Lesson 3 · JSON

Lesson Plan

At-a-Glance

Objective
Students will explain why JSON exists, recognize that Python dicts/lists and JSON look almost identical, use the four json functions correctly (dump/load for files, dumps/loads for strings), pretty-print JSON with indent=2, and combine JSON with try/except to load files safely.
Time
50 minutes
Materials
Computer, CodeSkills Lab, projector, whiteboard
Vocabulary
JSON, json.dump(), json.load(), json.dumps(), json.loads()
FL Standards
01.01, 01.02, 02.02, 03.01, 03.02, 05.07
Exam Obj.
Objectives 1, 4, 5 (primary)

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Project a Unit 5 contact dict: {"name": "Alex", "phone": "555-1234"}. Ask: "What if I want to save this to a file?" Take answers — students suggest writing strings, parsing on read, etc.
  • Reveal: there's already a universal solution that EVERY app on the planet uses. It's called JSON. And the best part — it looks almost EXACTLY like Python.

🎤 Direct Instruction (15 min)

  • Open Lesson 6.3 on the projector. Walk through Section 1 ("Why Do We Need JSON?"). Without JSON, saving a dict requires hand-rolled string parsing. With JSON, one line. Plus: every modern web API speaks JSON.
  • Walk through Section 2 ("Python & JSON Look Almost Identical"). Project both side by side:
    Python:  {"name": "Alex", "tags": ["a", "b"]}
    JSON:    {"name": "Alex", "tags": ["a", "b"]}
  • The differences: JSON keys must be strings in double quotes. JSON has true/false/null (lowercase) instead of Python's True/False/None. JSON tuples don't exist — they become lists. That's it.
  • Walk through Section 3 ("Try the Translation Yourself"). Use the lesson's interactive translator. Project. Click through 3–4 examples; have the class predict the JSON output before reveal.
  • Walk through Section 4 ("The Four Functions of json"). Drill the matrix:
    • json.dump(data, file) — write Python data to FILE as JSON
    • json.load(file) — read JSON FILE back to Python data
    • json.dumps(data) — convert Python data to a JSON STRING
    • json.loads(string) — parse a JSON STRING back to Python
  • The "s" suffix = string. dump/load = files. dumps/loads = strings. Drill this distinction — students confuse them constantly.
  • Walk through Section 5 ("Pretty-Print"). json.dump(data, f, indent=2) — adds indentation, makes the file human-readable. Default is one giant line. Use indent for any file a human will look at.
  • Walk through Section 6 ("Safe Loading"). Combine with Lesson 2's try/except:
    try:
        with open("data.json") as f:
            data = json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        data = []   # start fresh
  • Two exceptions to catch: file missing (FileNotFoundError) AND file corrupted (json.JSONDecodeError). The capstone explicitly tests both.

🤝 Guided Practice (8 min)

  • On the whiteboard, walk through writing a Unit-5 vault to JSON, then reading it back. Show that the data round-trips perfectly — except tuples become lists. (This is why the capstone's location is documented as a list-not-tuple after JSON: a known gotcha.)
  • Show a real-world JSON file (a GitHub API response works well — paste a small one). The class identifies the dict, the lists inside it, the nested structures. Same shape they've been building all year.

💻 Independent Lab (17 min)

  • Lab 6.3A — "Save My Profile": students build a Python dict representing themselves (5+ keys, including a list of hobbies). Save to profile.json with indent=2. Open the file in a text editor and verify it's readable. Then read it back into a new variable and verify it matches.
  • Lab 6.3B — "Safe Loader": students write a function load_data(filename) that uses try/except to handle BOTH FileNotFoundError AND JSONDecodeError. Returns an empty dict on either error. Test by deleting the file (recovers); corrupting the file by hand (recovers).
  • Circulate. Common bug: confusing dump with dumps. dump takes a file; dumps takes nothing extra. The "s" matters.

🚪 Exit Ticket (5 min)

  • On paper: "Match each function to what it does:"
    1. json.dump
    2. json.load
    3. json.dumps
    4. json.loads
    Options: A) write Python data to a FILE as JSON; B) read JSON from a FILE; C) Python data → JSON STRING; D) JSON STRING → Python.
  • Answers: 1A, 2B, 3C, 4D. Common error: getting dump/dumps swapped. The "s" = string is the mnemonic.

⚠️ Watch For — Common Misconceptions

1. "dump vs dumps."
What you'll see: json.dumps(data, file). Crashes — dumps doesn't take a file. Or: json.dump(data) — crashes, missing the file argument.
How to address: The "s" suffix = STRING version. dump writes to a FILE; dumps RETURNS a string. Drill the matrix on the whiteboard. The exam tests this distinction directly.
2. "JSON keys can be unquoted (Python style)."
What you'll see: A student hand-edits a JSON file, removes the quotes around keys ({name: "Alex"}). json.load crashes with JSONDecodeError.
How to address: JSON keys MUST be strings in DOUBLE QUOTES. Python is more flexible — JSON is strict. The fix: always quote keys when hand-writing JSON.
3. "Tuples survive a JSON round trip."
What you'll see: A student writes a tuple like (40.7, -74.0) with json.dump, reads it back, and is confused that it's now a list [40.7, -74.0].
How to address: JSON has no tuple type. Tuples → lists in JSON. After a round trip, your tuple is a list. Document this. The capstone's contact location field is documented as a list-after-JSON for this reason.
4. "Forgetting indent=2."
What you'll see: A student saves a vault with json.dump (no indent). The file is one giant line. Unreadable. They can't see what's wrong when they open it manually.
How to address: Always use indent=2 for files a human might open. The default (no indent) is for transmission over wires where size matters. For human eyes: indent.
5. "Catching only FileNotFoundError."
What you'll see: Safe loader handles missing files but crashes on a corrupted JSON file (someone hand-edited it badly).
How to address: Both errors are likely. Catch BOTH: except (FileNotFoundError, json.JSONDecodeError):. The tuple syntax catches either. The capstone tests this explicitly — it's worth 15 of 100 rubric points.

🎯 Differentiation

For early finishers
Challenge: research how requests + JSON power web APIs. Make a tiny "fetch a joke" program using requests.get(...).json() against a public joke API. Stretch: explore json.dumps(data, indent=2, sort_keys=True) and explain why sorted keys matter for diffs in version control.
For struggling students
Stay on Lab 6.3A. Skip the safe loader. The win: save a profile dict to JSON, open the file, and read it back. The four-function matrix can be revisited; for now they need just dump and load.

💬 Discussion Prompts

  • Why did JSON win? It's not the only data format — there's XML, YAML, CSV, others. (Simplicity. JSON is small, readable, language-agnostic. It looks like Python (and JavaScript). Easy to parse. Just enough features. Often "good enough beats best.")
  • Could you store a Python function in JSON? (No. JSON has no function/class type. It can store DATA only — strings, numbers, booleans, lists, dicts, null. To save a function, you'd need a different mechanism (pickle in Python, but that's risky).)
  • What does it mean that "JSON is a data format"? (It defines what shapes data can take. It does NOT define what those shapes mean — that's the application's job. JSON is the envelope; the contents are up to you.)

🌍 Real-World Connections

  • Every web API on the planet. When your phone fetches data from a server, 99% of the time it comes back as JSON. Reading JSON is the most fundamental "talk to the internet" skill.
  • Configuration files. package.json (Node.js), tsconfig.json (TypeScript), composer.json (PHP), VS Code settings — JSON is everywhere developers configure things.
  • Game saves. Modern game saves are JSON or close-to-JSON. Some games (Stardew Valley, Civilization VI) use plain JSON you can edit by hand.
  • NoSQL databases. MongoDB, Firebase, DynamoDB all store JSON-like documents. Master JSON now and you've previewed how the world's modern databases work.

📖 Lesson-Specific Vocabulary

JSON — JavaScript Object Notation. Universal text format for structured data.
json.dump() / json.load() — FILE versions. dump writes Python → JSON; load reads JSON → Python.
json.dumps() / json.loads() — STRING versions. The "s" = string. dumps = Python → JSON string; loads = JSON string → Python.
indent=2 — Pretty-print JSON for human-readability.
↑ Back to top

📦 Lesson 4 · Modules & the Standard Library

Lesson 4 · Modules & the Standard Library

Lesson Plan

At-a-Glance

Objective
Students will define what a module is, use the three forms of import (import x, from x import y, import x as y), apply four standard-library modules (random, datetime, math, os), and discover module capabilities with dir() and help().
Time
50 minutes
Materials
Computer, CodeSkills Lab, projector, optional printed standard-library cheat sheet
Vocabulary
Module, Standard Library, import, from, as, random, datetime, math, os
FL Standards
01.01, 01.02, 02.02, 07.05
Exam Obj.
Objectives 1, 4 (primary)

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Ask the class: "How would you generate a random number from 1 to 6 in Python?" Take answers — most students will start writing some kind of formula or guess.
  • Reveal: someone already wrote it. import random; random.randint(1, 6). Done. Today is the day students stop reinventing wheels.

🎤 Direct Instruction (15 min)

  • Open Lesson 6.4 on the projector. Walk through Section 1 ("What Is a Module?"). A module = a Python file containing reusable code. Students have used one already: import json in Lesson 3. Today: meet the rest of the toolbox.
  • The standard library = modules that ship with Python. No install. Just import.
  • Walk through Section 2 ("Three Ways to Import"):
    • import random — load the whole module. Use as random.randint(...).
    • from random import randint — load just one function. Use as randint(...).
    • import datetime as dt — load with a shorter alias. Use as dt.datetime.now().
  • The PEP 8 rule: imports go at the TOP of the file, one per line.
  • Walk through Section 3 ("Try Each Module — Live"). Open the Standard Library Explorer widget. Project. Click through:
    • random.randint(1, 6), random.choice([...]), random.shuffle([...])
    • datetime.now(), datetime.now().strftime("%Y-%m-%d %H:%M")
    • math.sqrt(16), math.pi, math.ceil(3.2)
    • os.path.exists("file.txt"), os.listdir(".")
  • Walk through Section 4 ("Real Recipes Using These Modules"). Five recipes: random greetings, timestamps for saves, dice rolls, distance formula, "check if file exists before opening." All real, all reusable.
  • Walk through Section 5 ("Discovering What a Module Can Do"). Two discovery tools:
    • dir(random) — lists everything in the module
    • help(random.randint) — shows the docstring/usage
  • Pros use these constantly. They DON'T memorize the standard library — they look things up.

🤝 Guided Practice (8 min)

  • On the whiteboard, present 5 problems. For each, students name the right module:
    • "Pick a random winner" → random.choice
    • "Get today's date" → datetime.datetime.today()
    • "Compute a square root" → math.sqrt
    • "Check if a save file exists" → os.path.exists
    • "Wait for 3 seconds" → time.sleep(3) (introduce time module briefly)
  • Reinforce: the question to ask is always "is there a module for this?" The answer is almost always yes.

💻 Independent Lab (17 min)

  • Lab 6.4A — "Use Three Modules": students write a single program that uses ALL THREE import forms. Roll a random die (import random), greet with the date (from datetime import datetime), compute a circle's area (import math as m). Each form used at least once.
  • Lab 6.4B — "Discover & Use": students pick ONE module they haven't seen (statistics, string, collections) and use dir() + help() to find ONE function in it. Apply that function in a 5-line program. The lesson: discoverability is a skill.
  • Circulate. Common bugs: writing random.randint after only doing from random import randint (must use randint alone now); forgetting that from datetime import datetime imports the CLASS, so it's datetime.now() not datetime.datetime.now() (this trips even pros).

🚪 Exit Ticket (5 min)

  • On paper: "What's the difference between import math and from math import sqrt? Show how you'd USE each one."
  • Looking for: import math → use as math.sqrt(16). from math import sqrt → use as sqrt(16) (no prefix). Both produce 4.0; the import style determines how you call.

⚠️ Watch For — Common Misconceptions

1. "Mixing the import forms in one call."
What you'll see: import random at the top, then randint(1, 6) in code. Crashes — randint not defined at module level.
How to address: Match the form to the call. import random → use as random.randint(1,6). from random import randint → use as randint(1,6). Don't mix.
2. "datetime.datetime.now() is too long, must be wrong."
What you'll see: Confusion about datetime being a module containing a CLASS also called datetime.
How to address: Yes, the standard library does this. import datetime; datetime.datetime.now() is correct (long). from datetime import datetime; datetime.now() is shorter. Most code uses the second form. Don't fight the design.
3. "math.pi is a function — needs parens."
What you'll see: math.pi(). Crashes — pi is a value, not a function.
How to address: Some module attributes are FUNCTIONS (parens), some are VALUES (no parens). Use help(math.pi) to find out which. Drill: math.pi = 3.14159..., a constant.
4. "random.shuffle returns a shuffled list."
What you'll see: x = random.shuffle(my_list). x is None. Confusion.
How to address: shuffle() mutates the list IN PLACE and returns None. Same mistake pattern as list.sort(). Read the docs (help(random.shuffle)) to know which functions mutate vs return.
5. "Imports ANYWHERE in the file are fine."
What you'll see: Imports scattered through the code. Hard to find what's needed.
How to address: PEP 8 says imports go at the TOP, one per line. Standard library first, then third-party, then your own modules — separated by blank lines. The capstone rubric checks for this.

🎯 Differentiation

For early finishers
Challenge: explore collections.Counter using help(). Use it to count word frequencies in a paragraph. Stretch: research itertools, pick one function (permutations or combinations), and demo it.
For struggling students
Stay on Lab 6.4A but with just ONE module. Pick random. The win: import random and random.randint(1, 6) work correctly in their program. The other forms can be revisited.

💬 Discussion Prompts

  • Why does Python ship with so much "standard" stuff? ("Batteries included" — Python's design philosophy. Most common needs (random, math, dates, files, JSON, sockets) are pre-built. Saves everyone from rewriting them.)
  • What's a "module" really? (Just a .py file. import math finds math.py in Python's library and loads it. You'll see in Lesson 5 — your own .py files work the exact same way.)
  • If pros don't memorize the standard library, what DO they memorize? (The names of common modules and the GENERAL idea of what each does. They remember "random has shuffle, choice, randint" — and look up the exact signatures with help() or docs.)

🌍 Real-World Connections

  • Every Python project on GitHub. Open any project. The top of every file: imports. The standard library is the foundation under everything.
  • Pip and PyPI. Beyond the standard library, Python has 400,000+ third-party modules on PyPI. pip install requests and you can talk to any web API. (Preview Unit 8.)
  • Data science. NumPy, Pandas, Matplotlib — all third-party modules. Master import in Unit 6 and you've unlocked the entire data-science Python ecosystem.
  • Reading other people's code. Every code review, every Stack Overflow answer, every tutorial uses imports. Reading them = the gateway to understanding modern Python.

📖 Lesson-Specific Vocabulary

Module — A Python file containing reusable code.
Standard Library — The collection of modules that ship with Python.
import — Keyword that loads a module.
from / as — Variants. from x import y grabs ONE tool. as renames locally.
random / datetime / math / os — The four most-used standard-library modules.
↑ Back to top

📇 Lesson 5 · Custom Modules + Persistent Contact Vault

Lesson 5 · Custom Modules + Persistent Contact Vault

Project Plan

At-a-Glance

Objective
Students will recognize that any .py file is a module, split a project across two files (UI + helpers), use the if __name__ == "__main__": guard correctly, and integrate every Unit 6 skill into the Persistent Contact Vault — a two-file app whose data survives between runs.
Time
Two class periods (70–100 minutes total)
Materials
Computer, CodeSkills Lab, projector, paper for SDLC plan stage, whiteboard for two-file architecture diagram
Vocabulary
Custom Module, __main__, Two-File Architecture
FL Standards
01.01, 01.02, 02.02, 03.02, 04.03, 05.06, 05.07, 06.02, 06.03, 07.01, 07.05, 07.07
Exam Obj.
Objectives 1, 3, 4 (primary), 5, 7 — broadest standards coverage of any unit so far
⚠️ The unit's culminating project. Persistent Contact Vault integrates EVERY skill from Unit 6 (file I/O, try/except, JSON, modules, datetime) plus the Unit 5 vault. It's the third 45%-weighted capstone in a row. The two-file architecture (contact_vault.py + vault_io.py) is the single most professionally valuable concept in the course. Don't compress. Day 1 covers custom modules + Plan + Code stages. Day 2 covers Test + Fix + Maintain + Showcase. The 2-day pacing is non-negotiable.

Project Flow (90+ min across 2 days)

📅 Day 1 — Custom Modules + Plan + Code (45–55 min)

  • Warm-up (5 min): Project the Unit 5 Contact Vault. Run it. Add 3 contacts. Quit. Restart. Vault is empty. Ask: "What's missing?" Answer: persistence. Today's project: give the vault a memory.
  • Custom Modules (15 min): Walk through Lesson 6.5 Sections 1–3. The big reveal: any .py file is a module. Live-demo: write greetings.py with two functions; write main.py that imports and uses it. Two files, one program.
  • The if __name__ == "__main__": guard. Why: when a file is RUN directly, Python sets __name__ to "__main__". When a file is IMPORTED, __name__ equals the module name. The guard means "only run main() when this file is executed directly — not when it's imported." Drill this. Most students don't get it the first time.
  • Capstone introduction (10 min): Project the two-file architecture diagram:
    contact_vault.py        vault_io.py
    ─────────────────       ─────────────────
    import vault_io          import json, os, datetime
    vault = []
    def add_contact():       def load_vault(filename):
    def remove_contact():        try/except → list
    def search_contacts():
    def list_contacts():     def save_vault(vault, filename):
    def main():                  json.dump(...)
    if __name__ == "__main__":
        main()                def now_string():
                                  datetime.now().strftime(...)
  • Two files. Two responsibilities. Main file = UI/menu/state. Helper file = disk/timestamp work. The capstone rubric is built around this split.
  • SDLC Stage 1 — Plan (5 min): Distribute paper. Students answer 4 questions: (1) Which functions go in which file? (2) What's the data shape — including the new created_at field? (3) What 2 exceptions does load_vault need to catch? (4) Where does the guard go and why? Stage 1 deliverable.
  • SDLC Stage 2 — Code (15–20 min): Students build vault_io.py FIRST (helper module). It's smaller and more focused. Then they wire contact_vault.py to use it via import vault_io. The order matters — students who try to build the main file first usually get tangled.

📅 Day 2 — Test + Fix + Maintain + Showcase (45 min)

  • SDLC Stage 3 — Test (15 min): Students apply edge-case testing. The unit's signature test: corrupt-file recovery. Students CORRUPT contacts.json by hand (delete a brace, add garbage), then restart. App should NOT crash — should start fresh. This is the rubric's hardest test, worth 15 of 100 points.
  • Other tests: persistence across restart (most important — 20 of 100), missing file recovery, empty vault listing, weird input characters. Document a test-case worksheet at the bottom of contact_vault.py.
  • SDLC Stage 4 — Fix (10 min): Apply the 4-step debugging strategy. Pair-test where time allows. Common Day 2 bugs: forgetting to call save_vault after add/remove (state lives in memory but never persists); using "w" when meant "a" on accidental file work; importing the WHOLE menu when they only meant to import helpers (the guard fixes this).
  • SDLC Stage 5 — Maintain (10 min): Polish for long-term. Header comment block, docstrings on every function in BOTH files, organized imports, version notes at bottom. Ensure the helper module imports cleanly without running the menu (the guard test).
  • Showcase & Submit (10 min): Pick 3–5 volunteers. Run their app, add a contact, quit, restart, see the contact STILL THERE. The audible "ohh" is the unit's emotional payoff. Project the two-file architecture briefly. Note: different students will have organized helpers differently — that's standard 05.06 (multiple algorithms) made visible.

⚠️ Watch For — Common Project Pitfalls

1. "Forgetting to save_vault after add/remove."
What you'll see: Vault works in-session. Add a contact. Quit. Restart. Contact gone. Confusion.
How to address: Persistence requires explicit saves. Every mutation function (add_contact, remove_contact) should END with vault_io.save_vault(vault, "contacts.json"). Without that line, the vault lives in memory only. Drill: "every change writes to disk."
2. "Importing the helper but typing functions without prefix."
What you'll see: import vault_io at top, then save_vault(...) in code. NameError.
How to address: With import vault_io, all helper functions need the vault_io. prefix. Either keep the prefix (preferred — explicit) OR change to from vault_io import save_vault, load_vault, now_string (then no prefix). Don't mix.
3. "Forgetting the __main__ guard."
What you'll see: Without the guard, main() would run when the file is imported elsewhere. With our 2-file setup, it might not be obvious until students run a test. Stage 5 deduction.
How to address: Drill: any file you might import — even later — needs the guard. The pattern is one line: if __name__ == "__main__": main(). Worth 10 of 100 rubric points; not optional.
4. "Catching only one of the two load errors."
What you'll see: except FileNotFoundError works for first run. Hand-edit corrupts the JSON. Restart. JSONDecodeError crashes the app.
How to address: Catch BOTH: except (FileNotFoundError, json.JSONDecodeError):. The tuple syntax. Test it the way the rubric does: hand-corrupt the file, then restart. App must start fresh, not crash. 15 of 100 rubric points.
5. "Tuple location turns into a list silently."
What you'll see: Student copies the Unit 5 vault into Unit 6, saves to JSON, reads back, then is confused that contact["location"][0] still works (it does — but it's now a list, not a tuple).
How to address: JSON has no tuple type. After a JSON round trip, tuples are lists. The capstone explicitly documents location as a list-after-JSON. Code that worked on tuples in Unit 5 still works on the list — just don't assume immutability anymore.
6. "Missing the created_at field."
What you'll see: Unit 5 vault copied as-is, no timestamp added on add.
How to address: The new field is "created_at": vault_io.now_string(). Goes in add_contact() when building the dict. The rubric checks for it (10 of 100 points).

🎯 Differentiation

For students who finish early
Direct them to stretch goals from the lesson: alphabetical sort (vault.sort(key=lambda c: c["name"].lower())), filter by date added, random pick (random.choice(vault)), pretty phone format on display, dedup on add. Each adds +5 pts (max +20).
For struggling students
It's OK if their version has only ONE save point (after add) instead of saving on every operation. They still demonstrate persistence. The win: contacts survive a restart. The corrupt-file recovery test can be revisited.

💬 Discussion Prompts

  • Why split into two files? Couldn't this all be in one file? (Yes — but: 1) The helper module is reusable in OTHER projects. 2) Each file is shorter and easier to read. 3) Code reviews are easier — different reviewers can look at UI vs I/O independently. 4) Bugs are easier to isolate — if persistence breaks, you know to look in vault_io.py. The split is the SAME modular thinking from Unit 4 functions, but at the file level.)
  • What does the __main__ guard actually protect against? (Without it, importing the file would RUN the menu loop. Imagine if import vault_io launched a menu — would be chaos. The guard ensures only DIRECT execution runs main.)
  • The Persistent Contact Vault has the same data shape as a real CRM. What ELSE would a real CRM add? (User accounts, sync across devices, search by phone/email/etc, contact history, notes per contact, encryption. This capstone is the SKELETON; production CRMs are this PLUS dozens of features. But the bones are these bones.)

🌍 Real-World Connections

  • Every desktop app on the planet. Save game files. Document files. Browser bookmarks. Settings. They all use the same pattern: load on startup, save on change, recover from corruption. The Persistent Contact Vault is a tiny version of every desktop app's persistence layer.
  • Two-file architecture is everywhere. React: components.jsx + utils.js. Django: views.py + models.py. Express: routes.js + db.js. Real apps split UI from data. Unit 6 is the entry point.
  • NoSQL databases. The capstone's contacts.json file IS a tiny JSON-document database. MongoDB, Firebase, CouchDB — they're this pattern at scale, with networking and concurrency added. Master the simple version first.
  • Resume bullet point. "Built a multi-file Python application with JSON persistence, exception handling, and timestamped records." Not a stretch — that's literally what students did.

📋 Persistent Contact Vault Project Rubric (100 points)

The rubric matches the one in the student lesson exactly. Share with students at the start of Day 1.

CategoryWhat to look forPts
Two-File ArchitectureCode split into contact_vault.py + vault_io.py. Main file imports the helper module and uses it via prefix.15
Persistence WorksContacts survive program restart. Adds and removes are saved immediately. JSON file on disk reflects current state.20
Error HandlingBoth FileNotFoundError AND json.JSONDecodeError are caught. App starts fresh on either, doesn't crash.15
TimestampsEach contact has a created_at field set via datetime.strftime. Visible in JSON and when listing.10
Use of __main__contact_vault.py has a guarded main() call. Helper module imports cleanly without running the menu.10
String CleanupInputs cleaned (strip, lower, replace) — same standard as Unit 5 capstone.10
Clean Code Stylesnake_case, 4-space indent, docstrings on every function, organized imports, no bare except.10
Works CorrectlyAll 9 test cases from Stage 3 pass. Especially: persistence across restart and corrupt-file recovery.10
TOTAL100

🎁 Stretch Goals (extra credit)

  • Alphabetical sort with sorted(... key=lambda): +5 pts
  • "Show contacts added today" filter using created_at.startswith(today): +5 pts
  • Random pick — random.choice(vault) for "who should I call?": +5 pts
  • Pretty phone format on display via slicing: +5 pts
  • Duplicate detection on add (case-insensitive name match): +5 pts

Maximum stretch credit: +20 points. Document each stretch in version notes at the bottom of contact_vault.py.

💡 Showcase tip. Day 2's emotional payoff: students see their app SURVIVE a restart. That moment — quit, reopen, contacts still there — is when they realize they've built real software. Project both the two-file architecture briefly AND the saved JSON file (open it in a text editor to show the human-readable indented format). The visible JSON file is what makes the abstract concept of "persistence" concrete.

📖 Lesson-Specific Vocabulary

Custom Module — A .py file YOU wrote that another file imports.
__main__ — Special variable. Python sets it to "__main__" when a file is run directly. Used by the guard.
Two-File Architecture — Splitting a project into UI/main + helper modules. The Unit 6 capstone uses this pattern.
↑ Back to top

🛠️ Appendix · Common Python Errors in Unit 6

This appendix lists the most common Python error messages students will see in Unit 6. File and module work introduces a new family of errors — FileNotFoundError, PermissionError, json.JSONDecodeError, ModuleNotFoundError, plus the silent bugs of forgetting with, using "w" when meant "a", and circular imports. Apply Unit 4's 4-step strategy: Reproduce → Read → Hypothesize → Fix & Verify, ONE change at a time.

ERRORFileNotFoundError: [Errno 2] No such file or directory: 'contacts.json'

What it usually means: Tried to read a file that doesn't exist yet. Common on first run.

How to fix: Wrap in try/except FileNotFoundError and start fresh on miss. The capstone tests this explicitly. Or check os.path.exists() before opening — but try/except is cleaner.

ERRORjson.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

What it usually means: The file isn't valid JSON. Either empty, or a human edited it badly (missing brace, unquoted key, trailing comma).

How to fix: Catch json.JSONDecodeError alongside FileNotFoundError: except (FileNotFoundError, json.JSONDecodeError):. App starts fresh. The capstone's signature test.

ERRORPermissionError: [Errno 13] Permission denied

What it usually means: The file exists but the OS won't let Python read or write it. On school computers, this happens when files are owned by another user.

How to fix: Save in a writable directory (your home folder or the project folder, not /etc or C:\Windows). Use a relative path like "contacts.json" and let the file land in the current working directory.

ERRORTypeError: Object of type tuple is not JSON serializable

What it usually means: Most Python types serialize to JSON. Tuples actually do (they become lists). But custom classes (Unit 7) don't, and neither do sets or datetimes by default.

How to fix: Convert to JSON-friendly types BEFORE saving. set → list(my_set). datetime → dt.strftime("%Y-%m-%d %H:%M"). The capstone uses the second pattern for created_at.

ERRORModuleNotFoundError: No module named 'vault_io'

What it usually means: Your vault_io.py file isn't in the same folder as contact_vault.py. Or the filename has a typo.

How to fix: Both files in the same folder. Filenames match the import statement EXACTLY (case-sensitive on Mac/Linux). import vault_io means the file is vault_io.py.

ERRORAttributeError: module 'random' has no attribute 'rangint'

What it usually means: Typo in a function name. Common with randint (the "i" before "n").

How to fix: Spell it correctly: random.randint. Use dir(random) if unsure — it lists everything available.

SILENT("w" mode wiped the file)

What it usually means: Used "w" when meant "a". The file is now empty (or just contains the latest write).

How to fix: Use "a" for append. Use "w" ONLY when intentionally replacing the entire file. Drill the safety: "w" = wipe.

SILENT(file content didn't save / file appears empty)

What it usually means: File was opened without with and never explicitly closed. Buffered writes never flushed to disk.

How to fix: Always use with open(...) as f:. Auto-closes; auto-flushes. Avoids this entire class of bug.

SILENT(circular import — both files import each other)

What it usually means: File A imports B, B imports A. Python tries to load both at once, hangs or partially loads, mysterious AttributeError later.

How to fix: Restructure so dependencies go ONE WAY. In the capstone: contact_vault.py imports vault_io.py; vault_io.py imports nothing project-local. The helper file shouldn't know about the UI.

CARRYOVERCarryover errors from Units 1–5

Watch list — these still happen in Unit 6 capstones:

  • KeyError in nested dict access — use .get() or guard with if key in d.
  • Mutating a list during iteration — find indices first, then delete.
  • Functions returning None — print instead of return. Echo of Unit 4.
  • Forgetting to .strip() input — leading/trailing whitespace breaks search and dedup.
  • Indentation errors when functions, loops, and try/except all nest deeply.
🛟 Unit 6 debugging adds two diagnostic questions to the 4-step strategy. Before applying Reproduce → Read → Hypothesize → Fix & Verify, ask: (A) "Is the file actually there?" Print os.path.exists(filename). (B) "What does the file actually contain?" Open it in a text editor. Most Unit 6 bugs are FILE-SHAPE bugs — the file exists but doesn't contain what the code assumes. Once you can see the file's actual contents, the fix is usually obvious.
📘 Companion document. A Unit 6 Answer Key with Knowledge Check answers and lab solutions can be authored separately on request. The Teacher's Guide + Answer Key are designed to be used together.

— End of Unit 6 Teacher's Guide —

↑ Back to top