Aiocsv
Python: Asynchronous CSV reading/writing
Install / Use
/learn @MKuranowski/AiocsvREADME
aiocsv
Asynchronous CSV reading and writing.
Installation
pip install aiocsv. Python 3.8+ is required.
This module contains an extension written in C. Pre-build binaries may not be available for your configuration. You might need a C compiler and Python headers to install aiocsv.
Usage
AsyncReader & AsyncDictReader accept any object that has a read(size: int) coroutine,
which should return a string.
AsyncWriter & AsyncDictWriter accept any object that has a write(b: str) coroutine.
Reading is implemented using a custom CSV parser, which should behave exactly like the CPython parser.
Writing is implemented using the synchronous csv.writer and csv.DictWriter objects - the serializers write data to a StringIO, and that buffer is then rewritten to the underlying asynchronous file.
Example
Example usage with aiofiles.
import asyncio
import csv
import aiofiles
from aiocsv import AsyncReader, AsyncDictReader, AsyncWriter, AsyncDictWriter
async def main():
# simple reading
async with aiofiles.open("some_file.csv", mode="r", encoding="utf-8", newline="") as afp:
async for row in AsyncReader(afp):
print(row) # row is a list
# dict reading, tab-separated
async with aiofiles.open("some_other_file.tsv", mode="r", encoding="utf-8", newline="") as afp:
async for row in AsyncDictReader(afp, delimiter="\t"):
print(row) # row is a dict
# simple writing, "unix"-dialect
async with aiofiles.open("new_file.csv", mode="w", encoding="utf-8", newline="") as afp:
writer = AsyncWriter(afp, dialect="unix")
await writer.writerow(["name", "age"])
await writer.writerows([
["John", 26], ["Sasha", 42], ["Hana", 37]
])
# dict writing, all quoted, "NULL" for missing fields
async with aiofiles.open("new_file2.csv", mode="w", encoding="utf-8", newline="") as afp:
writer = AsyncDictWriter(afp, ["name", "age"], restval="NULL", quoting=csv.QUOTE_ALL)
await writer.writeheader()
await writer.writerow({"name": "John", "age": 26})
await writer.writerows([
{"name": "Sasha", "age": 42},
{"name": "Hana"}
])
asyncio.run(main())
Differences with csv
aiocsv strives to be a drop-in replacement for Python's builtin csv module.
However, there are a few notable differences, due to technical limitations or CPython bugs:
- Readers accept objects with async
readmethods, instead of an AsyncIterable over lines from a file. AsyncDictReader.fieldnamescan beNone- useawait AsyncDictReader.get_fieldnames()instead.- Changes to
csv.field_size_limitare not picked up by existing Reader instances. The field size limit is cached on Reader instantiation to avoid expensive function calls on each character of the input. QUOTE_NOTNULLandQUOTE_STRINGSwork on readers even in 3.12. aiocsv does not replicate CPython bug #113732.
Other, minor, differences include:
AsyncReader.line_num,AsyncDictReader.line_numandAsyncDictReader.dialectare not settable,AsyncDictReader.readeris ofAsyncReadertype,AsyncDictWriter.writeris ofAsyncWritertype,AsyncDictWriterprovides an extra, read-onlydialectproperty.
Reference
aiocsv.AsyncReader
AsyncReader(
asyncfile: aiocsv.protocols.WithAsyncRead,
dialect: str | csv.Dialect | Type[csv.Dialect] = "excel",
**csv_dialect_kwargs: Unpack[aiocsv.protocols.CsvDialectKwargs],
)
An object that iterates over records in the given asynchronous CSV file. Additional keyword arguments are understood as dialect parameters.
Iterating over this object returns parsed CSV rows (List[str]).
Methods:
__aiter__(self) -> selfasync __anext__(self) -> List[str]
Read-only properties:
dialect(aiocsv.protocols.DialectLike): The dialect used when parsingline_num(int): The number of lines read from the source file. This coincides with a 1-based index of the line number of the last line of the recently parsed record.
aiocsv.AsyncDictReader
AsyncDictReader(
asyncfile: aiocsv.protocols.WithAsyncRead,
fieldnames: Optional[Sequence[str]] = None,
restkey: Optional[str] = None,
restval: Optional[str] = None,
dialect: str | csv.Dialect | Type[csv.Dialect] = "excel",
**csv_dialect_kwargs: Unpack[aiocsv.protocols.CsvDialectKwargs],
)
An object that iterates over records in the given asynchronous CSV file. All arguments work exactly the same was as in csv.DictReader.
Iterating over this object returns parsed CSV rows (Dict[str, str]).
Methods:
__aiter__(self) -> selfasync __anext__(self) -> Dict[str, str]async get_fieldnames(self) -> List[str]
Properties:
fieldnames(List[str] | None): field names used when converting rows to dictionaries
⚠️ Unlike csv.DictReader, this property can't read the fieldnames if they are missing - it's not possible toawaiton the header row in a property getter. Useawait reader.get_fieldnames().reader = csv.DictReader(some_file) reader.fieldnames # ["cells", "from", "the", "header"] areader = aiofiles.AsyncDictReader(same_file_but_async) areader.fieldnames # ⚠️ None await areader.get_fieldnames() # ["cells", "from", "the", "header"]restkey(str | None): If a row has more cells then the header, all remaining cells are stored under this key in the returned dictionary. Defaults toNone.restval(str | None): If a row has less cells then the header, then missing keys will use this value. Defaults toNone.reader: Underlyingaiofiles.AsyncReaderinstance
Read-only properties:
dialect(aiocsv.protocols.DialectLike): Link toself.reader.dialect- the current csv.Dialectline_num(int): The number of lines read from the source file. This coincides with a 1-based index of the line number of the last line of the recently parsed record.
aiocsv.AsyncWriter
AsyncWriter(
asyncfile: aiocsv.protocols.WithAsyncWrite,
dialect: str | csv.Dialect | Type[csv.Dialect] = "excel",
**csv_dialect_kwargs: Unpack[aiocsv.protocols.CsvDialectKwargs],
)
An object that writes csv rows to the given asynchronous file. In this object "row" is a sequence of values.
Additional keyword arguments are passed to the underlying csv.writer instance.
Methods:
async writerow(self, row: Iterable[Any]) -> None: Writes one row to the specified file.async writerows(self, rows: Iterable[Iterable[Any]]) -> None: Writes multiple rows to the specified file.
Readonly properties:
dialect(aiocsv.protocols.DialectLike): Link to underlying's csv.writer'sdialectattribute
aiocsv.AsyncDictWriter
AsyncDictWriter(
asyncfile: aiocsv.protocols.WithAsyncWrite,
fieldnames: Sequence[str],
restval: Any = "",
extrasaction: Literal["raise", "ignore"] = "raise",
dialect: str | csv.Dialect | Type[csv.Dialect] = "excel",
**csv_dialect_kwargs: Unpack[aiocsv.protocols.CsvDialectKwargs],
)
An object that writes csv rows to the given asynchronous file. In this object "row" is a mapping from fieldnames to values.
Additional keyword arguments are passed to the underlying csv.DictWriter instance.
Methods:
async writeheader(self) -> None: Writes header row to the specified file.async writerow(self, row: Mapping[str, Any]) -> None: Writes one row to the specified file.async writerows(self, rows: Iterable[Mapping[str, Any]]) -> None: Writes multiple rows to the specified file.
Properties:
fieldnames(Sequence[str]): Sequence of keys to identify the order of values when writing rows to the underlying filerestval(Any): Placeholder value used when a key from fieldnames is missing in a row, defaults to""extrasaction(Literal["raise", "ignore"]): Action to take when there are keys in a row, which are not present in fieldnames, defaults to"raise"which causes ValueError to be raised on extra keys, may be also set to"ignore"to ignore any extra keyswriter: Link to the underlyingAsyncWriter
Readonly properties:
dialect(aiocsv.protocols.DialectLike): Link to underlying's csv.reader'sdialectattribute
aiocsv.protocols.WithAsyncRead
A typing.Protocol describing an asynchronous file, which can be read.
aiocsv.protocols.WithAsyncWrite
A typing.Protocol describing an asynchronous file, which can be written to.
aiocsv.protocols.DialectLike
Type of an instantiated dialect property. Thank CPython for an incredible mess of
having unrelated and disjoint csv.Dialect and _csv.Dialect classes.
aiocsv.protocols.CsvDialectArg
Type of the dialect argument, as used in the csv module.
aiocsv.protocols.CsvDialectKwargs
Keyword arguments used by csv module to override the dialect settings during reader/writer
instantiation.
Development
Contributions are welcome, however please open an issue beforehand. aiocsv is meant as
a replacement for the built-in csv, any features not present in the latter will be rejected.
Building from source
To create a wheel (and a source tarball), run python -m build.
For local development, use a virtual environment.
pip install --editable . will build the C extension and make it available for the current
venv. This is required for running the tests. However, due to the mess of Python packaging
this will force an optimized build without debugging symbols. If you need to debug the C part
of aiocsv and build the library with e.g. debugging symbols, the only sane way is to
run `python setup.
Related Skills
qqbot-channel
351.2kQQ 频道管理技能。查询频道列表、子频道、成员、发帖、公告、日程等操作。使用 qqbot_channel_api 工具代理 QQ 开放平台 HTTP 接口,自动处理 Token 鉴权。当用户需要查看频道、管理子频道、查询成员、发布帖子/公告/日程时使用。
claude-opus-4-5-migration
110.6kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
docs-writer
100.5k`docs-writer` skill instructions As an expert technical writer and editor for the Gemini CLI project, you produce accurate, clear, and consistent documentation. When asked to write, edit, or revie
model-usage
351.2kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
