Find the most common validation failures with Counter
Also published in our Blogger archive.
A validation report is more useful when it identifies recurring categories instead of merely listing every bad record. collections.Counter counts hashable keys, so short stable failure codes are a natural input. The failure_codes() function returns zero, one, or two codes for each record. A generator feeds every returned code into Counter, producing a frequency mapping.
The sample has three email_missing_at failures and two age_below_18 failures. counts.most_common(2) returns pairs from the highest count down, and the assertions check the exact two pairs before they are printed. This makes the output suitable for a small deterministic summary while the original records remain available for detailed investigation.
Choose codes deliberately. A counter cannot tell whether several email failures share one root cause, and broad categories can hide distinct defects. most_common() uses encounter order to break equal counts, so a tie should not be presented as a stronger ranking. Counter also permits zero and negative counts, although a simple failure tally should normally increment only real failures. Its keys must be hashable; return strings, enums, or tuples rather than mutable dictionaries or lists.
AI assistance was used in preparing this article.
Source: Python Counter.most_common() documentation
Example
from collections import Counter
def failure_codes(record):
codes = []
if "@" not in record["email"]:
codes.append("email_missing_at")
if record["age"] < 18:
codes.append("age_below_18")
return codes
records = [
{"email": "invalid", "age": 16},
{"email": "valid@example.test", "age": 17},
{"email": "also-invalid", "age": 21},
{"email": "third-invalid", "age": 25},
]
counts = Counter(
code
for record in records
for code in failure_codes(record)
)
top_failures = counts.most_common(2)
assert counts["email_missing_at"] == 3
assert counts["age_below_18"] == 2
assert top_failures == [("email_missing_at", 3), ("age_below_18", 2)]
for code, count in top_failures:
print(f"{code}: {count}")
Expected stdout
email_missing_at: 3
age_below_18: 2