CISV Python Bindings (nanobind)
High-performance Python bindings for the CISV CSV parser using nanobind.
Performance
These bindings are 10-100x faster than the ctypes-based bindings because they:
- Use the batch API: All data is parsed in C and returned at once, eliminating millions of per-field callbacks
- Use nanobind: Much lower overhead than ctypes or pybind11
- Release the GIL: Parallel parsing runs without holding the Python GIL
| File Size | ctypes | nanobind | Speedup |
|---|---|---|---|
| 142MB (1M rows × 10 cols) | ~20s | <0.8s | 25x+ |
Installation
From PyPI (recommended)
pip install cisv
From source
cd cisv
pip install .
Development install
cd cisv
pip install -e .
Usage
import cisv
# Parse a file
rows = cisv.parse_file('data.csv')
# Parse with options
rows = cisv.parse_file(
'data.csv',
delimiter=';',
quote="'",
trim=True,
skip_empty_lines=True
)
# Parse large files in parallel (faster on multi-core systems)
rows = cisv.parse_file('large.csv', parallel=True)
# Parse a string
rows = cisv.parse_string("a,b,c\n1,2,3")
# Count rows quickly (SIMD-accelerated)
count = cisv.count_rows('data.csv')
# Row-by-row iteration (memory efficient, supports early exit)
with cisv.CisvIterator('large.csv') as reader:
for row in reader:
print(row) # List[str]
if row[0] == 'stop':
break # Early exit - no wasted work
# Or use the convenience function
for row in cisv.open_iterator('data.csv', delimiter=',', trim=True):
process(row)
API Reference
parse_file(path, delimiter=',', quote='"', *, trim=False, skip_empty_lines=False, parallel=False, num_threads=0)
Parse a CSV file and return all rows.
Parameters:
path: Path to the CSV filedelimiter: Field delimiter character (default: ',')quote: Quote character (default: '"')trim: Whether to trim whitespace from fieldsskip_empty_lines: Whether to skip empty linesparallel: Use multi-threaded parsing (faster for large files)num_threads: Number of threads for parallel parsing (0 = auto-detect)
Returns: List of rows, where each row is a list of field values.
parse_string(content, delimiter=',', quote='"', *, trim=False, skip_empty_lines=False)
Parse a CSV string and return all rows.
Parameters:
content: CSV content as a stringdelimiter: Field delimiter character (default: ',')quote: Quote character (default: '"')trim: Whether to trim whitespace from fieldsskip_empty_lines: Whether to skip empty lines
Returns: List of rows, where each row is a list of field values.
count_rows(path)
Count the number of rows in a CSV file without full parsing.
This is very fast as it only scans for newlines using SIMD instructions.
Parameters:
path: Path to the CSV file
Returns: Number of rows in the file.
CisvIterator(path, delimiter=',', quote='"', *, trim=False, skip_empty_lines=False)
Row-by-row iterator for streaming CSV parsing with minimal memory footprint.
Provides fgetcsv-style iteration that supports early exit - breaking out of iteration stops parsing immediately with no wasted work.
Parameters:
path: Path to the CSV filedelimiter: Field delimiter character (default: ',')quote: Quote character (default: '"')trim: Whether to trim whitespace from fieldsskip_empty_lines: Whether to skip empty lines
Methods:
next(): Get the next row asList[str], orNoneif at end of fileclose(): Close the iterator and release resourcesclosed: Property indicating whether the iterator has been closed
Protocols:
- Iterator protocol: Use in
forloops withfor row in iterator - Context manager: Use with
withstatement for automatic cleanup
Example:
# Context manager (recommended)
with cisv.CisvIterator('data.csv') as reader:
for row in reader:
if row[0] == 'target':
print(f"Found: {row}")
break # Early exit
# Manual iteration
reader = cisv.CisvIterator('data.csv')
try:
while True:
row = reader.next()
if row is None:
break
process(row)
finally:
reader.close()
open_iterator(path, delimiter=',', quote='"', *, trim=False, skip_empty_lines=False)
Convenience function that returns a CisvIterator. Same parameters as CisvIterator.
Example:
for row in cisv.open_iterator('data.csv'):
print(row)
Running Tests
cd cisv
pip install -e ".[test]"
pytest
Benchmarking
pip install -e ".[benchmark]"
python -c "
import cisv
import time
# Create test file
with open('/tmp/test.csv', 'w') as f:
f.write('col1,col2,col3\n')
for i in range(100000):
f.write(f'value{i}_1,value{i}_2,value{i}_3\n')
# Benchmark
start = time.time()
rows = cisv.parse_file('/tmp/test.csv')
print(f'Parsed {len(rows)} rows in {time.time()-start:.3f}s')
"
Metadata
Release files for cisv 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cisv-0.6.0.tar.gz | 92.1 kB | Without provenance | Details for cisv-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cisv-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details for cisv-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
Total release size: 229.7 kB
Release files / cisv-0.6.0.tar.gz
| Download URL | cisv-0.6.0.tar.gz |
|---|---|
| Size | 92.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e783864fc10ce118b3512719fa3a2ddf180f408645a8708b8640df5c910b686d
|
|
BLAKE2b-256 checksum How to use checksums |
58f1984abe51354ea1f6e86696f6b1cd5e138831090163d5615a375f5d4a30db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / cisv-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | cisv-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 137.6 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
426b41c3be8001dc5fda8d241d96a4a2dd68539cb2fd707995edbae2bce6e62f
|
|
BLAKE2b-256 checksum How to use checksums |
da07b232cbceecf4478c4d40117381c7bef002029a29fc411bc8ce2324c32709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for cisv 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.