quill: add csv_summary.py artifact with sample and verifier
This commit is contained in:
1 parent
8ea25bf50f
commit
558f259da9
3 files changed
+91
No files matched your search
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
"""csv_summary.py — Read a CSV from stdin or a file argument and emit JSON summary statistics."""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import csv
|
||||
from collections import defaultdict
|
||||
from statistics import mean, median
|
||||
|
||||
def summarize_csv(path=None):
|
||||
fh = open(path, newline='') if path else sys.stdin
|
||||
reader = csv.DictReader(fh)
|
||||
rows = list(reader)
|
||||
fh.close() if path else None
|
||||
|
||||
if not rows:
|
||||
return {"rows": 0, "columns": [], "numeric": {}}
|
||||
|
||||
columns = reader.fieldnames or []
|
||||
numeric = {}
|
||||
for col in columns:
|
||||
values = []
|
||||
for row in rows:
|
||||
try:
|
||||
values.append(float(row[col]))
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
if values:
|
||||
numeric[col] = {
|
||||
"count": len(values),
|
||||
"sum": round(sum(values), 4),
|
||||
"mean": round(mean(values), 4),
|
||||
"median": round(median(values), 4),
|
||||
"min": round(min(values), 4),
|
||||
"max": round(max(values), 4),
|
||||
}
|
||||
|
||||
return {
|
||||
"rows": len(rows),
|
||||
"columns": columns,
|
||||
"numeric": numeric,
|
||||
}
|
||||
|
||||
def main():
|
||||
path = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
result = summarize_csv(path)
|
||||
json.dump(result, sys.stdout, indent=2)
|
||||
sys.stdout.write("\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,6 @@
|
||||
name,age,salary,active
|
||||
Alice,30,50000,true
|
||||
Bob,25,45000,false
|
||||
Charlie,35,70000,true
|
||||
Diana,28,52000,true
|
||||
Eve,32,48000,false
|
||||
|
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
"""verify_summary.py — Assert csv_summary.py output matches expected values."""
|
||||
import sys
|
||||
import json
|
||||
|
||||
expected_rows = 5
|
||||
expected_columns = ["name", "age", "salary", "active"]
|
||||
expected_age = {
|
||||
"count": 5,
|
||||
"sum": 150.0,
|
||||
"mean": 30.0,
|
||||
"median": 30.0,
|
||||
"min": 25.0,
|
||||
"max": 35.0,
|
||||
}
|
||||
expected_salary = {
|
||||
"count": 5,
|
||||
"sum": 265000.0,
|
||||
"mean": 53000.0,
|
||||
"median": 50000.0,
|
||||
"min": 45000.0,
|
||||
"max": 70000.0,
|
||||
}
|
||||
|
||||
data = json.load(sys.stdin)
|
||||
assert data["rows"] == expected_rows, f"rows: {data['rows']}"
|
||||
assert data["columns"] == expected_columns, f"columns: {data['columns']}"
|
||||
age = data["numeric"]["age"]
|
||||
for k, v in expected_age.items():
|
||||
assert age[k] == v, f"age.{k}: {age[k]} != {v}"
|
||||
sal = data["numeric"]["salary"]
|
||||
for k, v in expected_salary.items():
|
||||
assert sal[k] == v, f"salary.{k}: {sal[k]} != {v}"
|
||||
print("VERIFIED")
|
||||
Reference in new issue
Block a user