← Course Home
Module 5

Mixed Recap

No new syntax here — just everything from Modules 1–4, applied to the real fixture data instead of small made-up examples.

Concept

Meet the Real Fixture

Everything so far used tiny examples you typed by hand. Now you're working with USERS — 12 real-shaped user records — and LOGIN_COUNTS, a separate lookup dict. Same list-of-dicts shape you already know, just bigger and messier, like real API data actually is.

from fixture import USERS, LOGIN_COUNTS
print(USERS[0])

Before doing anything else: create fixture.py in your module-5/problems/ folder by typing in the data from DAY1_01_FIXTURE.md yourself — don't paste it. Everything in this module imports from that file.

Lab 1

Print USERS[0] whole — see the full shape of one record.

A big nested dict with id, status, lastLogin, profile, groups
Lab 2

Print len(USERS).

12
Lab 3

Print len(LOGIN_COUNTS).

9
Lab 4

Print type(USERS), then print type(USERS[0]) — confirm it's a list of dicts.

<class 'list'> then <class 'dict'>
Lab 5

Print USERS[0]["id"].

00u001
Now go practice

Open problems/01_meet_the_fixture.py — but first, type fixture.py into that same folder from DAY1_01_FIXTURE.md.

Concept

Indexing Into the List of Dicts

Same indexing from Module 2 — USERS[0] is the first record, USERS[-1] is the last. Just applied to real, bigger data now.

print(USERS[0]["id"])    # 00u001
print(USERS[-1]["id"])   # 00u012
Lab 1

Print USERS[0]["id"].

00u001
Lab 2

Print USERS[-1]["id"].

00u012
Lab 3

Print USERS[5]["id"].

00u006
Lab 4

Print USERS[11]["id"], then print USERS[-1]["id"] — same record, two ways.

both 00u012
Lab 5

Print USERS[1]["status"].

ACTIVE
Now go practice

Open problems/02_indexing.py and do all 5 problems locally.

Concept

Chaining Into a Record's Fields

Same nested access from Module 3 — chain the brackets to reach a specific field inside a specific record.

print(USERS[0]["profile"]["email"])   # jrivera@example.com
Lab 1

Print USERS[0]["profile"]["email"].

jrivera@example.com
Lab 2

Print USERS[1]["profile"]["firstName"].

Amy
Lab 3

Print USERS[2]["status"].

SUSPENDED
Lab 4

Print USERS[6]["profile"]["department"].

Security
Lab 5

Print USERS[9]["profile"]["lastName"].

Foster
Predict first

USERS[7] (Layla Haddad) is missing something. What happens with print(USERS[7]["profile"]["department"])?

Check
CrashesKeyError: 'department'

This is the fixture's real planted bug — record 8 (USERS[7]) has no department key at all. Real API data does this constantly.

Now go practice

Open problems/03_chaining.py and do all 6 problems locally.

Concept

Safe Chained Access

Use .get() at the level that might be missing, same as Module 3, to avoid the crash you just saw.

print(USERS[7]["profile"].get("department", "Unknown"))   # Unknown -- no crash
Lab 1

Print USERS[7]["profile"].get("department", "Unknown").

Unknown
Lab 2

Print USERS[7]["profile"].get("email") — a key that does exist.

lhaddad@example.com
Lab 3

Print USERS[3]["lastLogin"] directly — record 4 (Dana) has this set to None. No crash, it just prints None.

None
Lab 4

Print USERS[3].get("lastLogin") — same result, safer habit.

None
Predict first

What happens with print(USERS[3]["lastLogin"] + " ago")?

Check
CrashesTypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

Same bug family from Module 1 — you can't glue text onto None. This is the fixture's second planted bug, now hit for real.

Lab 5

Print USERS[0]["profile"].get("department", "Unknown") — a record where the key IS present, default gets ignored.

IT
Lab 6 · Checkpoint

One script, three lines: safely get USERS[7]'s department with a default, safely get USERS[3]'s lastLogin, and safely get USERS[0]'s department (present this time).

Unknown, None, IT
Now go practice

Open problems/04_safe_access.py — 6 problems, #6 is a checkpoint combining sub-skills 1–4.

Concept

Working With a Record's Groups List

Each record's groups is a list — but not a list of plain names. It's a list of dicts, each with its own id and name. One more chain step than you might expect.

print(USERS[0]["groups"][0])          # {'id': 'g01', 'name': 'Engineering'} -- a dict, not a string
print(USERS[0]["groups"][0]["name"])  # Engineering -- now you have the string
Lab 1

Print USERS[0]["groups"][0]["name"].

Engineering
Lab 2

Print USERS[0]["groups"][-1]["name"].

VPN-Users
Lab 3

Print len(USERS[0]["groups"]) — how many groups.

2
Lab 4

Print USERS[3]["groups"] — record 4 (Dana) has zero groups.

[]
Lab 5

Print bool(USERS[3]["groups"]).

False
Lab 6

Marcus (USERS[9]) has 3 groups. Print USERS[9]["groups"][1]["name"].

Admins
Now go practice

Open problems/05_groups_list.py and do all 6 problems locally.

Concept

Joining Two Data Sources by a Shared Key

Pull a record's email, then use it to look something up in the other dict, LOGIN_COUNTS. This is exactly how you'd join two different API responses in a real script.

email = USERS[0]["profile"]["email"]
print(LOGIN_COUNTS.get(email))   # 142
Lab 1

email = USERS[0]["profile"]["email"]. Print LOGIN_COUNTS.get(email).

142
Predict first

email = USERS[4]["profile"]["email"] (Kelly O'Connor). Print LOGIN_COUNTS.get(email). Will it find her count?

Check
None — not found

This is a real bug, not a coincidence: LOGIN_COUNTS has a typo — "koonnor@example.com" instead of Kelly's real email "kokonnor@example.com". The lookup silently fails instead of crashing, which is worse — you'd never notice unless you checked.

Lab 2

Print "koonnor@example.com" in LOGIN_COUNTS — the misspelled key IS there.

True
Lab 3

Print USERS[4]["profile"]["email"] in LOGIN_COUNTS — her real email is not.

False
Lab 4

email = USERS[5]["profile"]["email"] (Tri Nguyen). Print LOGIN_COUNTS.get(email, 0) — genuinely missing this time, not a typo.

0
Lab 5

Print LOGIN_COUNTS.get(USERS[4]["profile"]["email"], 0) — same typo case, with a default this time.

0 (still wrong data, just doesn't crash)
Lab 6

email = USERS[8]["profile"]["email"] (Rosa Gomez). Print LOGIN_COUNTS.get(email, 0).

0
Now go practice

Open problems/06_join_by_key.py and do all 6 problems locally.

Concept

Comparing Two Records

Pull a field from two different records and compare with == — same operator, applied to real records instead of small examples.

print(USERS[0]["status"] == USERS[1]["status"])   # True -- both ACTIVE
Lab 1

Print USERS[0]["status"] == USERS[1]["status"].

True
Lab 2

Print USERS[2]["status"] == USERS[8]["status"] — Bina and Rosa.

True (both SUSPENDED)
Lab 3

Print USERS[0]["profile"]["department"] == USERS[3]["profile"]["department"] — Julio and Dana.

True (both IT)
Lab 4

Print USERS[0] == USERS[1] — the whole records, not just one field.

False
Lab 5

Print USERS[5]["status"] == USERS[11]["status"] — Tri and Pat.

True (both DEPROVISIONED)
Now go practice

Open problems/07_compare_records.py and do all 5 problems locally.

Concept

Building a Report Line From One Record

The payoff: an f-string (Module 1) combined with everything else — chained access, safe .get(), list length — into one clean printed line. This is what a real report script actually produces.

user = USERS[0]
name = user["profile"]["firstName"] + " " + user["profile"]["lastName"]
dept = user["profile"].get("department", "Unknown")
group_count = len(user["groups"])
print(f"{name} ({dept}) -- {group_count} groups")
# Julio Rivera (IT) -- 2 groups
Lab 1

Build the same report line for USERS[1] (Amy Chen).

Amy Chen (Security) -- 3 groups
Lab 2

Build it for USERS[7] (Layla) — her missing department should show "Unknown", not crash.

Layla Haddad (Unknown) -- 1 groups
Lab 3

Build it for USERS[3] (Dana) — zero groups.

Dana Morris (IT) -- 0 groups
Lab 4

Add the login count to the line for USERS[0], using LOGIN_COUNTS.get() with a default of 0.

includes 142
Lab 5

Build the full line (name, dept, groups, login count) for USERS[4] (Kelly) — remember her login count won't be found due to the typo.

login count shows 0
Lab 6 · Final checkpoint

Print one report line each for USERS[0] and USERS[7], back to back — a mini two-user report combining every sub-skill in this module.

Two full report lines, one per user.
Now go practice

Open problems/08_report_line.py — 6 problems, #6 is the final checkpoint for all of Module 5.

Complete

Module 5 done

meet the fixture → index → chain → safe access → groups list → join by key → compare records → report line.

Run python check.py in problems/ to grade everything.