Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I validate a CSV column against a set of allowed values?

Quick answer

Read the CSV with csv.DictReader, define the allowed strings in a set, and compare each field value directly against that set. A direct comparison is case-sensitive and does not trim whitespace, so open and Open are unexpected if only open is allowed. Report the data-record number and original value; if you choose to normalize for matching, keep the original value for the report.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a CSV with a status column. How can I check that every value is one of a specific set, such as open or closed, and see which rows need attention?

Geez

Define the permitted strings in a set and compare each parsed field value directly against it. csv.DictReader maps each data row to a dictionary keyed by the header fields, and the field values are strings. [S1]

import csv

allowed = {"open", "closed"}

with open("input.csv", newline="", encoding="utf-8") as file:
    reader = csv.DictReader(file)
    for data_row_number, row in enumerate(reader, start=1):
        original = row.get("status")
        if original not in allowed:
            print(
                f"Data row {data_row_number}: "
                f"status={original!r} is not allowed; "
                f"allowed values are {sorted(allowed)!r}"
            )

The example counts the first record after the header as data row 1. The !r display makes spaces in the original value visible. If you want spreadsheet row numbers and the file has one header line, add 1 to the displayed number. The example assumes the header is exactly status; adjust it if your column has a different name. The allowed set is your rule, not a decision made by the CSV reader. [S1]

Follow-up question

What happens with Open or OPEN? I don’t want the script to quietly change what was actually in the file.

Geez

With the direct set comparison above, matching is exact: " Open " and "OPEN" do not match "open". The CSV reader does not silently trim spaces or ignore letter case. [S1] The script flags those values and reports the original parsed string; it does not rewrite the source data.

If you want a different matching rule, make it explicit and keep the original value for reporting. For example, say whether your comparison ignores surrounding whitespace, letter case, or both. Don’t change the rule silently: people reviewing the report need to know what counted as a match.

Follow-up question

Can you show what the output would look like for a few sample rows, including a missing or blank status?

Geez

Assume this sample has a status header and these data records:

status
open
 Open 
closed

With exact matching, the second data record is unexpected because its spaces and capitalization differ from open. The final blank field is an empty string, so it is also unexpected. The output could be:

Data row 2: status=' Open ' is not allowed; allowed values are ['closed', 'open']
Data row 4: status='' is not allowed; allowed values are ['closed', 'open']

These are data-record numbers, with the header excluded. A blank field and a missing status key are different cases. In this example, row.get("status") returns None if the key is absent, and that value also fails the set check and is reported as None.

Follow-up question

What should I verify before using the report to clean the CSV?

Geez

Confirm the rule with whoever owns the data: are spaces and capitalization meaningful, and is a blank status permitted? Check that the header is status and that the allowed set contains every valid spelling. The CSV reader handles parsing; the allowed values and matching rule are application choices. [S1]

Keep validation separate from editing. Review the reported original values, decide how each should be handled, and write any changes to a separate output if you choose to transform the data. The example only reads and reports; it does not change the input.

You can make the rule clear in the report with wording like this:

Rule: exact match; no trimming or case folding.
Allowed values: ['closed', 'open'].
Finding: data row [N], original status=[VALUE].

Replace the bracketed fields with the row number and original value. If you choose a different comparison rule, state it in the report.

A practical checklist

  • Confirm the CSV header name matches the key used in the script.

  • Write the allowed strings explicitly and confirm them with the rule owner.

  • Decide whether comparison is exact or explicitly normalized.

  • Keep the original field value for reporting, even if matching uses a normalized copy.

  • Label row numbers as data-record numbers or spreadsheet row numbers.

  • Review unexpected values before making edits to the source file.

A few more useful answers

Does a direct set comparison ignore capitalization or surrounding spaces?

No. It compares the strings exactly, so Open and open differ from open. [S1]

Does this validation decide which values should be allowed?

No. The allowed set and whether to normalize values are application choices; confirm them with the relevant data owner. [S1]

Will the example change the CSV?

No. It reads the file and reports values that are not in the allowed set; it does not write changes.

Sources

References used for this guide.

  1. [S1] Python 3.14 csv module: reading rows as dictionaries
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work