CSV & Delimited Files Adapter (CsvAdapter)
CsvAdapter streams delimited flat files (CSV, TSV, PSV) line-by-line while handling the most common real-world flat-file edge cases.
Key Features
- Multiline Cells in Quotes: Preserves records where cells contain embedded
\nline breaks enclosed in quotes, preventing corrupted field splits. - Sentinel Null Coercion: Automatically cleans string representations of nulls (
"","NULL","N/A","None","\\N") into PythonNonebefore schema validation. - Dual Coordinate Tracking: Reports both physical line numbers (including multiline spans) and logical row indices.
- Flexible Stream Sources: Reads from file paths (
str,Path), file-like objects (io.StringIO), standard input (sys.stdin), or decoded text streams (such asio.TextIOWrapperover a network socket).
Constructor Parameters
adapters.CsvAdapter(
source: Union[str, Path, TextIO],
delimiter: str = ",",
quotechar: str = '"',
escapechar: Optional[str] = None,
null_values: Sequence[str] = ("", "NULL", "N/A"),
encoding: str = "utf-8",
)
| Parameter | Type | Default | Description |
|---|---|---|---|
source |
str \| Path \| TextIO |
Required | File path, file-like object, or standard input stream. |
delimiter |
str |
"," |
Character used to separate fields (e.g. ",", ";", "\t", "\|"). |
quotechar |
str |
'"' |
Character used to quote fields containing delimiters or line breaks. |
escapechar |
Optional[str] |
None |
One-character string used to escape quotes/delimiters. |
null_values |
Sequence[str] |
("", "NULL", "N/A") |
Strings converted to None prior to schema validation. |
encoding |
str |
"utf-8" |
Character encoding when opening file paths. |
Examples
1. Handling Multiline Quotes and Semicolon Separators
from pydantic import BaseModel
from pydantic_stream_file import StreamValidator, adapters
class SupportTicket(BaseModel):
ticket_id: int
customer: str
message: str
# Semicolon delimited file with multiline message cells
adapter = adapters.CsvAdapter(
source="tickets.csv",
delimiter=";",
quotechar='"'
)
for ticket in StreamValidator(adapter, SupportTicket):
print(ticket.ticket_id, ticket.message)
If row 5 has a message spanning lines 5 through 8:
- The ticket is read as a single record.
- In yield_result mode, its location is accurately reported as Lines: 5-8 (Record: 4).
2. Custom Null Values for Legacy Database Dumps
Legacy SQL dumps often represent nulls as \N or 'None':
adapter = adapters.CsvAdapter(
source="database_dump.tsv",
delimiter="\t",
null_values=["\\N", "None", "NULL", ""]
)
Fields defined as Optional[T] = None in your Pydantic model will receive None instead of failing with string parsing errors.
3. Streaming directly from AWS S3 (boto3)
Because CsvAdapter requires text lines, wrap binary stream bodies (such as StreamingBody) using io.TextIOWrapper:
import io
import boto3
from pydantic_stream_file import StreamValidator, adapters
s3 = boto3.client("s3")
obj = s3.get_object(Bucket="my-bucket", Key="huge_dataset.csv")
# Decode the binary stream into text lines
text_stream = io.TextIOWrapper(obj["Body"], encoding="utf-8")
adapter = adapters.CsvAdapter(
source=text_stream
)
for record in StreamValidator(adapter, MyModel):
process(record)