Example CSV validations#
Demonstrating validate_csv:
This notebook shows simple, self-contained examples of the validate_csv function.
It supports two modes:
Direct validation of a local path,
Path, or URL → returnsTrue/FalseDecorator mode → the decorated function runs only after the CSV argument passes validation (raises
CsvValidationErroron failure)
Correct import (the package also provides a similar validate_json):
from fileaudit.csv_check import validate_csv, CsvValidationError
# Install if needed (already present in many environments)
# !pip install fileaudit -q
from pathlib import Path
from fileaudit.csv_check import (
validate_csv,
CsvValidationError,
DEFAULT_MAX_FILE_SIZE,
DEFAULT_MAX_ROWS,
DEFAULT_MAX_COLUMNS,
)
print("Defaults:")
print(f" max_file_size = {DEFAULT_MAX_FILE_SIZE} bytes ({DEFAULT_MAX_FILE_SIZE / 1024 / 1024:.1f} MB)")
print(f" max_rows = {DEFAULT_MAX_ROWS}")
print(f" max_columns = {DEFAULT_MAX_COLUMNS}")
Defaults:
max_file_size = 10485760 bytes (10.0 MB)
max_rows = 100000
max_columns = 1000
1. Direct validation of a local CSV file#
validate_csv(path) returns True on success and False on failure.
# Create a simple valid CSV
valid_path = Path("valid_demo.csv")
valid_path.write_text("name,age,city\nAlice,30,NYC\nBob,25,London\n", encoding="utf-8")
result = validate_csv(valid_path)
print(f"validate_csv({valid_path!r}) → {result}")
# Also works with a plain string path
print(f"validate_csv('valid_demo.csv') → {validate_csv('valid_demo.csv')}")
validate_csv(PosixPath('valid_demo.csv')) → True
validate_csv('valid_demo.csv') → True
2. Reject formula injection (default behaviour)#
Fields that look like spreadsheet formulas (=, +, -, @ …) are rejected when reject_formula_injection=True (the default).
formula_path = Path("formula_demo.csv")
formula_path.write_text(
"name,formula,score\n"
"Alice,=2+2,90\n"
"Bob,normal,85\n",
encoding="utf-8",
)
print("With reject_formula_injection=True (default):")
print(" →", validate_csv(formula_path))
print("\nWith reject_formula_injection=False:")
print(" →", validate_csv(formula_path, reject_formula_injection=False))
With reject_formula_injection=True (default):
Exception: FileAudit Security Validation Failed - Rejected field at row 2, column 2: possible spreadsheet formula injection
→ False
With reject_formula_injection=False:
→ True
3. Size / shape limits#
You can restrict file size, number of rows, columns, etc.
# A CSV with more rows than our limit
many_rows = Path("many_rows_demo.csv")
with many_rows.open("w", encoding="utf-8", newline="") as f:
f.write("id,value\n")
for i in range(15):
f.write(f"{i},val{i}\n")
print("File has 15 data rows + header.")
print("max_rows=10 →", validate_csv(many_rows, max_rows=10))
print("max_rows=20 →", validate_csv(many_rows, max_rows=20))
print("max_columns=1 →", validate_csv(many_rows, max_columns=1)) # two columns present
print("max_file_size=50 (bytes) →", validate_csv(many_rows, max_file_size=50))
File has 15 data rows + header.
Exception: FileAudit Security Validation Failed - CSV contains more than 10 rows
max_rows=10 → False
max_rows=20 → True
Exception: FileAudit Security Validation Failed - Rejected row 1: contains 2 columns, exceeding maximum of 1
max_columns=1 → False
Exception: FileAudit Security Validation Failed - File size exceeds maximum of 50 bytes
max_file_size=50 (bytes) → False
4. Decorator usage – first argument is the CSV path#
When used as @validate_csv (or @validate_csv()), the first parameter of the decorated function is treated as the CSV path.
@validate_csv
def process_csv(csv_path):
"""Simple processing that only runs after validation succeeds."""
text = Path(csv_path).read_text(encoding="utf-8")
return f"Processed {len(text.splitlines())} lines from {csv_path}"
# Valid file → function is called
print(process_csv("valid_demo.csv"))
# Invalid file (formula) → CsvValidationError is raised
try:
print(process_csv("formula_demo.csv"))
except CsvValidationError as e:
print(f"Caught expected error: {type(e).__name__}: {e}")
Processed 3 lines from valid_demo.csv
Caught expected error: CsvValidationError: FileAudit Security Validation Failed - Rejected field at row 2, column 2: possible spreadsheet formula injection
5. Decorator with explicit argument name and custom limits#
@validate_csv(
"input_file", # name of the parameter that holds the CSV path
max_rows=5,
reject_formula_injection=True,
)
def analyse(input_file, extra_info="none"):
return f"Analysed {input_file} (extra={extra_info})"
print(analyse("valid_demo.csv", extra_info="demo"))
# Too many rows
try:
analyse("many_rows_demo.csv")
except CsvValidationError as e:
print(f"Caught expected error (max_rows): {e}")
Analysed valid_demo.csv (extra=demo)
Caught expected error (max_rows): FileAudit Security Validation Failed - CSV contains more than 5 rows
6. Decorator with @validate_csv() (empty call) – same as bare @validate_csv#
@validate_csv()
def count_rows(path):
return sum(1 for _ in Path(path).open(encoding="utf-8"))
print("Row count (including header):", count_rows("valid_demo.csv"))
Row count (including header): 3
7. Control characters rejection#
By default reject_control_characters=True rejects most C0 control characters.
# Create a file containing a control character (ASCII 0x01)
ctrl_path = Path("ctrl_demo.csv")
# Write binary-ish content carefully
ctrl_path.write_bytes(b"name,note\nAlice,hello\x01world\nBob,ok\n")
print("reject_control_characters=True →", validate_csv(ctrl_path))
print("reject_control_characters=False →", validate_csv(ctrl_path, reject_control_characters=False))
Exception: FileAudit Security Validation Failed - Rejected field at row 2, column 2: contains control character U+0001
reject_control_characters=True → False
reject_control_characters=False → True
8. Using a pathlib.Path object and checking return values#
p = Path("valid_demo.csv")
assert validate_csv(p) is True
assert validate_csv(Path("formula_demo.csv")) is False
print("All direct-mode assertions passed.")
Exception: FileAudit Security Validation Failed - Rejected field at row 2, column 2: possible spreadsheet formula injection
All direct-mode assertions passed.
Cleanup (optional)#
for f in Path(".").glob("*_demo.csv"):
f.unlink(missing_ok=True)
print("Demo CSV files removed.")
Demo CSV files removed.
Summary of capabilities demonstrated#
Feature |
Example |
|---|---|
Direct validation (local path / |
|
Formula-injection protection |
default |
Control-character rejection |
default |
Size / row / column limits |
|
Decorator (first arg) |
|
Decorator (named arg + options) |
|
Error signalling |
|