Capstone: A Persistent Lending Tool · practice
Print the Lending Activity
A lending activity report has one row per loan, whether that loan is active or returned. It is not a two-event timeline. The report must also show the member email that version 2 added, and it must represent missing values honestly.
The demo calls main(["activity", str(database_path)]) twice: once while loan 501 is active and once after its return. Add display_value(value) exactly as shown, then add activity_command(args). Argparse passes only args.database to that command
Refuse a missing database, call prepare_database, and open the application connection. Call list_lending_activity(connection) exactly once and store its returned rows. Close the connection in finally before printing. The query returns plain loan_id, asset_tag, member_code, member_email, checked_out_on, and returned_on.
def display_value(value):
if value is None:
return "NULL"
return str(value)
Use display_value(value) when rendering nullable values. It returns the literal text NULL for Python None; every other returned_on and for an older migrated member whose email is SQL NULL. Do not print Python’s None, an empty field, or an invented event row.
Print this header even when no loans exist:
loan_id | asset_tag | member_code | member_email | checked_out_on | returned_on
Then use a for if args.command == "activity": return activity_command(args) to main.
Press Run to compare the same durable row before and after return:
== activity before return ==
Status: 0
loan_id | asset_tag | member_code | member_email | checked_out_on | returned_on
501 | TL-100 | MB-017 | riley@example.test | 2026-08-26 | NULL
== activity after return ==
Status: 0
loan_id | asset_tag | member_code | member_email | checked_out_on | returned_on
501 | TL-100 | MB-017 | riley@example.test | 2026-08-26 | 2026-08-27
stderr: <empty>
A thorough check supplies several loans in a different insertion order, active and returned rows, Unicode values, and both missing and present email. It checks one row per loan, exact order and columns, no state change, one public query call, and connection closure.
Task
Add the exact display_value(value) activity_command(args), and add this branch in main:
if args.command == "activity":
return activity_command(args)
Refuse a missing database, prepare and open it, call list_lending_activity exactly once, and close in finally. Print the exact six-column header and one pipe-delimited row per returned None as NULL, including a missing email or return label.