Capstone: A Persistent Lending Tool · practice
Import Starter Items Without Duplicates
A starter import has two useful results: rows inserted for the first time and rows already present in exact agreement. The command must print both counts, but only after the entire CSV has been validated and the
The visible demo first initializes its temporary catalog. It then makes these exact calls:
main(["import-items", str(database_path), str(csv_path)])
main(["import-items", str(database_path), str(csv_path)])
The demo writes the exact three starter rows to csv_path inside the same temporary directory. For each call, argparse gives import_items_command a namespace with args.database and args.csv. Add import_error_is_documented(error), add import_items_command(args), and add this branch to main:
def import_error_is_documented(error):
message = str(error)
if setup_error_is_documented(error):
return True
if message in (
"CSV file does not exist.",
"CSV must be UTF-8 text.",
"CSV is not valid.",
"CSV must contain at least one item row.",
"CSV headers must be exactly: id,asset_tag,name,category,loan_days.",
):
return True
for prefix in ("CSV row ", "CSV contains ", "CSV item "):
if message.startswith(prefix):
return True
return False
if args.command == "import-items":
return import_items_command(args)
Check Path(args.database).exists() before doing anything with the CSV. Every non-init command follows this rule. If the database is missing, report exactly Error: Database does not exist. Run init first. on stderr and return 1. The check must not create the named file, even when the CSV exists.
For an existing database, call import_items_csv(args.database, args.csv). Do not open the CSV, parse rows, issue SQL, or repeat schema setup in lending.py. That
Catch import_error_is_documented returns False. A documented missing CSV becomes Error: CSV file does not exist.; validation, disagreement, and schema refusal messages keep their existing text. Each expected failure returns 1, leaves stdout empty, and writes one stderr line. An unrelated ValueError or another exception still propagates.
On success, unpack (inserted, unchanged). Print only after the call returns:
Items inserted: N
Items unchanged: M
Then return 0. Keeping both prints after the boundary prevents a first success-looking line from escaping when a later row makes the transaction roll back.
Press Run. The same three-row CSV is imported twice:
== import-items ==
First status: 0
Items inserted: 3
Items unchanged: 0
Second status: 0
Items inserted: 0
Items unchanged: 3
stderr: <empty>
A thorough check also uses a later-row disagreement and unseen paths. It confirms that no partial row survives and that a programming error is not relabeled as an import refusal.
Task
Add the exact import_error_is_documented(error) import_items_command(args), and add this branch in main:
if args.command == "import-items":
return import_items_command(args)
Refuse a missing args.database before calling import_items_csv(args.database, args.csv). On success, print Items inserted: N followed by Items unchanged: M and return 0. Report only a