JSON and CSV · practice
Preserve the Value Types
read_csv_rows now knows that each row has five cells. It still returns "0", "7.25", and "false" as
Conversion is part of the boundary
The output schema decides each Python type before the JSON serializer sees it:
{
"sku": "GM-204",
"name": "Dice, Set of 6",
"quantity": 0,
"unit_price": 7.25,
"in_stock": False,
}
json will later map that
For sku and name, remove surrounding whitespace and reject an empty result. For quantity, require decimal digit text before calling int. This keeps values such as "4.5" and "many" out. Then reject a negative result.
For unit_price, float handles ordinary decimal spellings, but it also accepts special values such as nan and inf. Those are not finite prices and the schema excludes them. math.isfinite(price) closes that gap.
A boolean is not non-empty text
This is wrong:
in_stock = bool(row["in_stock"])
It is worth watching that fail rather than taking my word for it:
Both "true" and "false" are True, because bool on a string asks “is there anything in it?” and both have five or four characters in them. Only the empty string is False.
Compare against the two permitted spellings instead:
if row["in_stock"] == "true":
in_stock = True
elif row["in_stock"] == "false":
in_stock = False
else:
raise ValueError("in_stock must be true or false")
The strict lowercase rule is deliberate. Quietly accepting five spellings makes upstream mistakes harder to notice.
Your turn
Implement parse_row(row, row_number) and read_catalog_csv(path).
parse_row must return a new dictionary with exactly the five schema keys and the declared row_number in every row-
read_catalog_csv should call read_csv_rows, convert each row in order, and return the item
Make a temporary copy of catalog.csv, add a fourth product with values unlike the existing three, and call read_catalog_csv with that copy’s path. Confirm the converted output follows your new row. Keep the original three-row catalog.csv unchanged for submission. A converter that only handles the rows it was written beside is not yet a converter.
Why is bool(row["in_stock"]) the wrong way to read "false"?
Why check math.isfinite(price) after calling float?
Task
Implement parse_row(row, row_number) and read_catalog_csv(path).
Return exact item sku and name quantity an integer, unit_price a finite float, and in_stock a real true or false.