Fix the CSV parser in a contact import

Review the AI's codeMedium20 min

Your task

An AI wrote a contact import that read the uploaded CSV with text.split('\n') and then line.split(','). It worked on a 20-row demo file. Real exports have quoted commas, quoted line breaks and Windows line endings, so names were mangled and the header row was imported as a contact. Your team is replacing it with a parser that reports every row's status and caps the number of rows.

An assistant wrote parse_contact_import(csv_text, max_rows). It is in the editor. It has a bug. Find it and fix it.

Input and output:

  • csv_text: the uploaded file's text, with a header line and then one contact per record: name, then email.
  • max_rows: the most data rows to return.
  • Return one [status, name, email] list per data row, in file order.

Rules the tests check:

  • Read the text one character at a time, as CSV:
    • Outside quotes, , ends a field and a line break ends a record. A line break is \r\n, \n or \r.
    • " starts a quoted part. Inside it, , and line breaks are ordinary characters and "" stands for one ". The next single " ends the quoted part. The quote marks are not part of the field.
    • A file that ends with a line break has no extra empty record after it.
  • If max_rows is 0 or less, return [].
  • Skip blank records: a record with one field that is empty after trimming spaces, tabs and \r. They do not count toward max_rows. Rows with a bad status do count.
  • The first record that is not blank is the header. Drop it.
  • Return the first max_rows data rows at most.
  • The name is field 1 and the email is field 2, or "" when there is no field 2. Trim spaces, tabs and \r from both ends of each.
  • The status is the first of these that applies:
    • "bad_field_count": the record does not have exactly 2 fields.
    • "bad_name": the name is empty.
    • "bad_email": the email contains a space, a tab, a line break or ,; or it does not have exactly one @; or nothing comes before the @; or the domain, the part after the @, has no ., or its last . is its first or last character.
    • "ok" otherwise.

Examples

parse_contact_import(csv_text: str, max_rows: int) -> list[list[str]]
Example 1
Inputparse_contact_import("name,email\nAda Lovelace,ada@example.com\nAlan Turing,alan@example.org\n", 100)
Output[["ok", "Ada Lovelace", "ada@example.com"], ["ok", "Alan Turing", "alan@example.org"]]
Example 2
Inputparse_contact_import("name,email\r\n\"Lovelace, Ada\",ada@example.com\r\nGrace Hopper,grace@navy.mil\r\n", 100)
Output[["ok", "Lovelace, Ada", "ada@example.com"], ["ok", "Grace Hopper", "grace@navy.mil"]]
Example 3
Inputparse_contact_import("name,email\nAda,ada@example.com\nBob,not-an-email\n", 100)
Output[["ok", "Ada", "ada@example.com"], ["bad_email", "Bob", "not-an-email"]]