rapcsv 0.1.2__cp310-cp310-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rapcsv/__init__.py +58 -0
- rapcsv/_rapcsv.cp310-win_amd64.pyd +0 -0
- rapcsv/_rapcsv.pyi +32 -0
- rapcsv/py.typed +0 -0
- rapcsv-0.1.2.dist-info/METADATA +361 -0
- rapcsv-0.1.2.dist-info/RECORD +7 -0
- rapcsv-0.1.2.dist-info/WHEEL +4 -0
rapcsv/__init__.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Streaming async CSV — no fake async, no GIL stalls.
|
|
2
|
+
|
|
3
|
+
rapcsv provides true async CSV reading and writing for Python, backed by Rust and Tokio.
|
|
4
|
+
Unlike libraries that wrap blocking I/O in async syntax, rapcsv guarantees that all CSV
|
|
5
|
+
operations execute **outside the Python GIL**, ensuring event loops never stall under load.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- True async CSV reading and writing
|
|
9
|
+
- Streaming support for large files (incremental reading, no full file load)
|
|
10
|
+
- Context manager support (`async with`)
|
|
11
|
+
- aiocsv compatibility (AsyncReader/AsyncWriter aliases)
|
|
12
|
+
- CSV-specific exception types (CSVError, CSVFieldCountError)
|
|
13
|
+
- RFC 4180 compliant CSV parsing and writing
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
>>> import asyncio
|
|
17
|
+
>>> from rapcsv import Reader, Writer
|
|
18
|
+
>>>
|
|
19
|
+
>>> async def main():
|
|
20
|
+
... async with Writer("output.csv") as writer:
|
|
21
|
+
... await writer.write_row(["name", "age"])
|
|
22
|
+
... await writer.write_row(["Alice", "30"])
|
|
23
|
+
...
|
|
24
|
+
... async with Reader("output.csv") as reader:
|
|
25
|
+
... row = await reader.read_row()
|
|
26
|
+
... print(row) # ['name', 'age']
|
|
27
|
+
>>>
|
|
28
|
+
>>> asyncio.run(main())
|
|
29
|
+
|
|
30
|
+
For more information, see: https://github.com/eddiethedean/rapcsv
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from typing import List
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
from _rapcsv import Reader, Writer, CSVError, CSVFieldCountError # type: ignore[import-not-found]
|
|
37
|
+
except ImportError:
|
|
38
|
+
try:
|
|
39
|
+
from rapcsv._rapcsv import Reader, Writer, CSVError, CSVFieldCountError
|
|
40
|
+
except ImportError:
|
|
41
|
+
raise ImportError(
|
|
42
|
+
"Could not import _rapcsv. Make sure rapcsv is built with maturin."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# API compatibility with aiocsv
|
|
46
|
+
# aiocsv uses AsyncReader and AsyncWriter as class names
|
|
47
|
+
AsyncReader = Reader
|
|
48
|
+
AsyncWriter = Writer
|
|
49
|
+
|
|
50
|
+
__version__: str = "0.1.2"
|
|
51
|
+
__all__: List[str] = [
|
|
52
|
+
"Reader",
|
|
53
|
+
"Writer",
|
|
54
|
+
"AsyncReader", # aiocsv compatibility
|
|
55
|
+
"AsyncWriter", # aiocsv compatibility
|
|
56
|
+
"CSVError",
|
|
57
|
+
"CSVFieldCountError",
|
|
58
|
+
]
|
|
Binary file
|
rapcsv/_rapcsv.pyi
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Type stubs for _rapcsv Rust extension module."""
|
|
2
|
+
|
|
3
|
+
from typing import Coroutine, Any, List, Optional
|
|
4
|
+
|
|
5
|
+
class Reader:
|
|
6
|
+
def __init__(self, path: str) -> None: ...
|
|
7
|
+
def read_row(self) -> Coroutine[Any, Any, List[str]]: ...
|
|
8
|
+
def __aenter__(self) -> Coroutine[Any, Any, "Reader"]: ...
|
|
9
|
+
def __aexit__(
|
|
10
|
+
self,
|
|
11
|
+
exc_type: Optional[Any],
|
|
12
|
+
exc_val: Optional[Any],
|
|
13
|
+
exc_tb: Optional[Any],
|
|
14
|
+
) -> Coroutine[Any, Any, None]: ...
|
|
15
|
+
|
|
16
|
+
class Writer:
|
|
17
|
+
def __init__(self, path: str) -> None: ...
|
|
18
|
+
def write_row(self, row: List[str]) -> Coroutine[Any, Any, None]: ...
|
|
19
|
+
def close(self) -> Coroutine[Any, Any, None]: ...
|
|
20
|
+
def __aenter__(self) -> Coroutine[Any, Any, "Writer"]: ...
|
|
21
|
+
def __aexit__(
|
|
22
|
+
self,
|
|
23
|
+
exc_type: Optional[Any],
|
|
24
|
+
exc_val: Optional[Any],
|
|
25
|
+
exc_tb: Optional[Any],
|
|
26
|
+
) -> Coroutine[Any, Any, None]: ...
|
|
27
|
+
|
|
28
|
+
class CSVError(Exception):
|
|
29
|
+
def __init__(self, message: str) -> None: ...
|
|
30
|
+
|
|
31
|
+
class CSVFieldCountError(Exception):
|
|
32
|
+
def __init__(self, message: str) -> None: ...
|
rapcsv/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rapcsv
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Summary: Streaming async CSV — no fake async, no GIL stalls.
|
|
16
|
+
Keywords: async,csv,streaming,async-io
|
|
17
|
+
Author: RAP Project
|
|
18
|
+
License: MIT
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
21
|
+
|
|
22
|
+
# rapcsv
|
|
23
|
+
|
|
24
|
+
**Streaming async CSV — no fake async, no GIL stalls.**
|
|
25
|
+
|
|
26
|
+
[](https://pypi.org/project/rapcsv/)
|
|
27
|
+
[](https://pepy.tech/project/rapcsv)
|
|
28
|
+
[](https://www.python.org/downloads/)
|
|
29
|
+
[](https://opensource.org/licenses/MIT)
|
|
30
|
+
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
`rapcsv` provides true async CSV reading and writing for Python, backed by Rust and Tokio. Unlike libraries that wrap blocking I/O in `async` syntax, `rapcsv` guarantees that all CSV operations execute **outside the Python GIL**, ensuring event loops never stall under load, even when processing large files.
|
|
34
|
+
|
|
35
|
+
**Roadmap Goal**: Achieve drop-in replacement compatibility with `aiocsv`, enabling seamless migration with true async performance. See [docs/ROADMAP.md](https://github.com/eddiethedean/rapcsv/blob/main/docs/ROADMAP.md) for details.
|
|
36
|
+
|
|
37
|
+
## Why `rap*`?
|
|
38
|
+
|
|
39
|
+
Packages prefixed with **`rap`** stand for **Real Async Python**. Unlike many libraries that merely wrap blocking I/O in `async` syntax, `rap*` packages guarantee that all I/O work is executed **outside the Python GIL** using native runtimes (primarily Rust). This means event loops are never stalled by hidden thread pools, blocking syscalls, or cooperative yielding tricks. If a `rap*` API is `async`, it is *structurally non-blocking by design*, not by convention. The `rap` prefix is a contract: measurable concurrency, real parallelism, and verifiable async behavior under load.
|
|
40
|
+
|
|
41
|
+
See the [rap-manifesto](https://github.com/eddiethedean/rap-manifesto) for philosophy and guarantees.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- ✅ **True async** CSV reading and writing
|
|
46
|
+
- ✅ **Streaming support** for large files
|
|
47
|
+
- ✅ **Native Rust-backed** execution (Tokio)
|
|
48
|
+
- ✅ **Zero Python thread pools**
|
|
49
|
+
- ✅ **Event-loop-safe** concurrency under load
|
|
50
|
+
- ✅ **GIL-independent** I/O operations
|
|
51
|
+
- ✅ **Verified** by Fake Async Detector
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
- Python 3.8+ (including Python 3.13 and 3.14)
|
|
56
|
+
- Rust 1.70+ (for building from source)
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install rapcsv
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Building from Source
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/eddiethedean/rapcsv.git
|
|
68
|
+
cd rapcsv
|
|
69
|
+
pip install maturin
|
|
70
|
+
maturin develop
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import asyncio
|
|
79
|
+
from rapcsv import Reader, Writer
|
|
80
|
+
|
|
81
|
+
async def main():
|
|
82
|
+
# Write CSV file (one row per Writer instance for MVP)
|
|
83
|
+
writer = Writer("output.csv")
|
|
84
|
+
await writer.write_row(["name", "age", "city"])
|
|
85
|
+
|
|
86
|
+
# Read CSV file (reads first row)
|
|
87
|
+
reader = Reader("output.csv")
|
|
88
|
+
row = await reader.read_row()
|
|
89
|
+
print(row) # Output: ['name', 'age', 'city']
|
|
90
|
+
|
|
91
|
+
asyncio.run(main())
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Writing Multiple Rows
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import asyncio
|
|
98
|
+
from rapcsv import Writer
|
|
99
|
+
|
|
100
|
+
async def main():
|
|
101
|
+
# Write multiple rows with a single Writer instance (file handle reused)
|
|
102
|
+
writer = Writer("output.csv")
|
|
103
|
+
rows = [
|
|
104
|
+
["name", "age", "city"],
|
|
105
|
+
["Alice", "30", "New York"],
|
|
106
|
+
["Bob", "25", "London"],
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
for row in rows:
|
|
110
|
+
await writer.write_row(row)
|
|
111
|
+
|
|
112
|
+
# Verify file contents
|
|
113
|
+
with open("output.csv") as f:
|
|
114
|
+
print(f.read())
|
|
115
|
+
|
|
116
|
+
asyncio.run(main())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Note**: The Writer reuses the file handle across multiple `write_row()` calls for efficient writing. The Reader maintains position state across `read_row()` calls and streams data incrementally without loading the entire file into memory.
|
|
120
|
+
|
|
121
|
+
### Using Context Managers
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import asyncio
|
|
125
|
+
from rapcsv import Reader, Writer
|
|
126
|
+
|
|
127
|
+
async def main():
|
|
128
|
+
# Using context managers for automatic resource cleanup
|
|
129
|
+
async with Writer("output.csv") as writer:
|
|
130
|
+
await writer.write_row(["name", "age", "city"])
|
|
131
|
+
await writer.write_row(["Alice", "30", "New York"])
|
|
132
|
+
|
|
133
|
+
async with Reader("output.csv") as reader:
|
|
134
|
+
row = await reader.read_row()
|
|
135
|
+
print(row) # Output: ['name', 'age', 'city']
|
|
136
|
+
|
|
137
|
+
asyncio.run(main())
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### aiocsv Compatibility
|
|
141
|
+
|
|
142
|
+
`rapcsv` provides compatibility aliases for `aiocsv`:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from rapcsv import AsyncReader, AsyncWriter # aiocsv-compatible names
|
|
146
|
+
|
|
147
|
+
async def main():
|
|
148
|
+
async with AsyncWriter("output.csv") as writer:
|
|
149
|
+
await writer.write_row(["col1", "col2"])
|
|
150
|
+
|
|
151
|
+
async with AsyncReader("output.csv") as reader:
|
|
152
|
+
row = await reader.read_row()
|
|
153
|
+
print(row)
|
|
154
|
+
|
|
155
|
+
asyncio.run(main())
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## API Reference
|
|
159
|
+
|
|
160
|
+
### `Reader(path: str)`
|
|
161
|
+
|
|
162
|
+
Create a new async CSV reader.
|
|
163
|
+
|
|
164
|
+
**Parameters:**
|
|
165
|
+
- `path` (str): Path to the CSV file to read
|
|
166
|
+
|
|
167
|
+
**Example:**
|
|
168
|
+
```python
|
|
169
|
+
reader = Reader("data.csv")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### `Reader.read_row() -> List[str]`
|
|
173
|
+
|
|
174
|
+
Read the next row from the CSV file.
|
|
175
|
+
|
|
176
|
+
**Returns:**
|
|
177
|
+
- `List[str]`: A list of string values for the row, or an empty list if EOF
|
|
178
|
+
|
|
179
|
+
**Raises:**
|
|
180
|
+
- `IOError`: If the file cannot be read
|
|
181
|
+
- `CSVError`: If the CSV file is malformed or cannot be parsed
|
|
182
|
+
|
|
183
|
+
**Note**: The Reader maintains position state across `read_row()` calls, reading sequentially through the file. Files are streamed incrementally without loading the entire file into memory.
|
|
184
|
+
|
|
185
|
+
**Context Manager Support:**
|
|
186
|
+
```python
|
|
187
|
+
async with Reader("data.csv") as reader:
|
|
188
|
+
row = await reader.read_row()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### `Writer(path: str)`
|
|
192
|
+
|
|
193
|
+
Create a new async CSV writer.
|
|
194
|
+
|
|
195
|
+
**Parameters:**
|
|
196
|
+
- `path` (str): Path to the CSV file to write
|
|
197
|
+
|
|
198
|
+
**Example:**
|
|
199
|
+
```python
|
|
200
|
+
writer = Writer("output.csv")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `Writer.write_row(row: List[str]) -> None`
|
|
204
|
+
|
|
205
|
+
Write a row to the CSV file.
|
|
206
|
+
|
|
207
|
+
**Parameters:**
|
|
208
|
+
- `row` (List[str]): A list of string values to write as a CSV row
|
|
209
|
+
|
|
210
|
+
**Raises:**
|
|
211
|
+
- `IOError`: If the file cannot be written
|
|
212
|
+
|
|
213
|
+
**Note**: The Writer reuses the file handle across multiple `write_row()` calls for efficient writing. Proper RFC 4180 compliant CSV escaping and quoting is applied automatically.
|
|
214
|
+
|
|
215
|
+
### `Writer.close() -> None`
|
|
216
|
+
|
|
217
|
+
Explicitly close the file handle and flush any pending writes.
|
|
218
|
+
|
|
219
|
+
**Example:**
|
|
220
|
+
```python
|
|
221
|
+
writer = Writer("output.csv")
|
|
222
|
+
await writer.write_row(["col1", "col2"])
|
|
223
|
+
await writer.close()
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Context Manager Support:**
|
|
227
|
+
```python
|
|
228
|
+
async with Writer("output.csv") as writer:
|
|
229
|
+
await writer.write_row(["col1", "col2"])
|
|
230
|
+
# File is automatically closed and flushed on exit
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Exception Types
|
|
234
|
+
|
|
235
|
+
#### `CSVError`
|
|
236
|
+
|
|
237
|
+
Raised when a CSV parsing error occurs (e.g., malformed CSV file).
|
|
238
|
+
|
|
239
|
+
#### `CSVFieldCountError`
|
|
240
|
+
|
|
241
|
+
Raised when there's a mismatch in the number of fields between rows.
|
|
242
|
+
|
|
243
|
+
## Testing
|
|
244
|
+
|
|
245
|
+
`rapcsv` includes comprehensive test coverage with tests adapted from the [aiocsv test suite](https://github.com/MKuranowski/aiocsv/tree/master/tests) to validate compatibility:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Run all tests
|
|
249
|
+
pytest
|
|
250
|
+
|
|
251
|
+
# Run aiocsv compatibility tests
|
|
252
|
+
pytest test_aiocsv_compatibility.py -v
|
|
253
|
+
|
|
254
|
+
# Run all tests with coverage
|
|
255
|
+
pytest --cov=rapcsv --cov-report=html
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The test suite includes:
|
|
259
|
+
- Basic read/write operations
|
|
260
|
+
- Context manager support
|
|
261
|
+
- Quoted fields with special characters
|
|
262
|
+
- Large file streaming
|
|
263
|
+
- Concurrent operations
|
|
264
|
+
- aiocsv compatibility validation
|
|
265
|
+
|
|
266
|
+
## Benchmarks
|
|
267
|
+
|
|
268
|
+
This package passes the [Fake Async Detector](https://github.com/eddiethedean/rap-bench). Benchmarks are available in the [rap-bench](https://github.com/eddiethedean/rap-bench) repository.
|
|
269
|
+
|
|
270
|
+
Run the detector yourself:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
pip install rap-bench
|
|
274
|
+
rap-bench detect rapcsv
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Roadmap
|
|
278
|
+
|
|
279
|
+
See [docs/ROADMAP.md](https://github.com/eddiethedean/rapcsv/blob/main/docs/ROADMAP.md) for detailed development plans. Key goals include:
|
|
280
|
+
- Drop-in replacement for `aiocsv` (Phase 1)
|
|
281
|
+
- Full streaming support for large files
|
|
282
|
+
- Comprehensive CSV dialect support
|
|
283
|
+
- Zero-copy optimizations
|
|
284
|
+
|
|
285
|
+
## Related Projects
|
|
286
|
+
|
|
287
|
+
- [rap-manifesto](https://github.com/eddiethedean/rap-manifesto) - Philosophy and guarantees
|
|
288
|
+
- [rap-bench](https://github.com/eddiethedean/rap-bench) - Fake Async Detector CLI
|
|
289
|
+
- [rapfiles](https://github.com/eddiethedean/rapfiles) - True async filesystem I/O
|
|
290
|
+
- [rapsqlite](https://github.com/eddiethedean/rapsqlite) - True async SQLite
|
|
291
|
+
|
|
292
|
+
## Limitations
|
|
293
|
+
|
|
294
|
+
**Current limitations:**
|
|
295
|
+
- No advanced CSV dialect support (delimiters, quote characters, line terminators) - planned for Phase 2
|
|
296
|
+
- No header detection or manipulation - planned for Phase 2
|
|
297
|
+
- Not designed for synchronous use cases
|
|
298
|
+
|
|
299
|
+
**Phase 1 improvements:**
|
|
300
|
+
- ✅ Streaming file reading - files are read incrementally without loading entire file into memory
|
|
301
|
+
- ✅ Context manager support (`async with`) for automatic resource cleanup
|
|
302
|
+
- ✅ CSV-specific exception types (`CSVError`, `CSVFieldCountError`)
|
|
303
|
+
- ✅ Improved error handling with detailed error messages
|
|
304
|
+
- ✅ `close()` method for explicit file handle closure
|
|
305
|
+
- ✅ aiocsv compatibility aliases (`AsyncReader`, `AsyncWriter`)
|
|
306
|
+
- ✅ Comprehensive test coverage (29 tests including aiocsv compatibility tests)
|
|
307
|
+
- ✅ aiocsv test suite migration - tests adapted from [aiocsv test suite](https://github.com/MKuranowski/aiocsv/tree/master/tests)
|
|
308
|
+
|
|
309
|
+
## Changelog
|
|
310
|
+
|
|
311
|
+
### v0.1.1 (2026-01-16)
|
|
312
|
+
|
|
313
|
+
**Python 3.14 Support:**
|
|
314
|
+
- ✅ Added Python 3.14 support with ABI3 forward compatibility
|
|
315
|
+
- ✅ Updated CI/CD workflows to test and build for Python 3.14
|
|
316
|
+
|
|
317
|
+
**Python 3.13 Support:**
|
|
318
|
+
- ✅ Added Python 3.13 support with ABI3 forward compatibility
|
|
319
|
+
- ✅ Updated CI/CD workflows to test and build for Python 3.13
|
|
320
|
+
- ✅ Fixed exception handling for ABI3 compatibility (using `create_exception!` macro)
|
|
321
|
+
- ✅ Explicitly registered exception classes in Python module
|
|
322
|
+
|
|
323
|
+
**Bug Fixes:**
|
|
324
|
+
- Fixed exception registration issue where exceptions created with `create_exception!` were not accessible from Python
|
|
325
|
+
|
|
326
|
+
**Compatibility:**
|
|
327
|
+
- Python 3.8 through 3.14 supported
|
|
328
|
+
- All platforms: Ubuntu (x86-64, aarch64), macOS (aarch64, x86-64), Windows (x86-64, aarch64)
|
|
329
|
+
|
|
330
|
+
### v0.1.0 (2025-01-12)
|
|
331
|
+
|
|
332
|
+
**Version 0.1.0 - Phase 1 Complete:**
|
|
333
|
+
- ✅ Streaming file reading - files are read incrementally without loading entire file into memory
|
|
334
|
+
- ✅ Context manager support (`async with`) for automatic resource cleanup
|
|
335
|
+
- ✅ CSV-specific exception types (`CSVError`, `CSVFieldCountError`)
|
|
336
|
+
- ✅ Improved error handling with detailed error messages
|
|
337
|
+
- ✅ `close()` method for explicit file handle closure
|
|
338
|
+
- ✅ aiocsv compatibility aliases (`AsyncReader`, `AsyncWriter`)
|
|
339
|
+
- ✅ Comprehensive test coverage (29 tests including aiocsv compatibility tests)
|
|
340
|
+
- ✅ aiocsv test suite migration - tests adapted from [aiocsv test suite](https://github.com/MKuranowski/aiocsv/tree/master/tests)
|
|
341
|
+
|
|
342
|
+
**Previous improvements (v0.0.2):**
|
|
343
|
+
- ✅ Security fixes: Upgraded dependencies (pyo3 0.27, pyo3-async-runtimes 0.27), fixed CSV injection vulnerability
|
|
344
|
+
- ✅ Position tracking: Reader now maintains position state across `read_row()` calls
|
|
345
|
+
- ✅ File handle reuse: Writer reuses file handle across multiple `write_row()` calls
|
|
346
|
+
- ✅ CSV escaping: Implemented RFC 4180 compliant CSV escaping and quoting
|
|
347
|
+
- ✅ Input validation: Added path validation (non-empty, no null bytes)
|
|
348
|
+
- ✅ Improved error handling: Enhanced error messages with file path context
|
|
349
|
+
- ✅ Type stubs: Added `.pyi` type stubs for better IDE support and type checking
|
|
350
|
+
|
|
351
|
+
**Roadmap**: See [docs/ROADMAP.md](https://github.com/eddiethedean/rapcsv/blob/main/docs/ROADMAP.md) for planned improvements. Our goal is to achieve drop-in replacement compatibility with `aiocsv` while providing true async performance with GIL-independent I/O.
|
|
352
|
+
|
|
353
|
+
## Contributing
|
|
354
|
+
|
|
355
|
+
Contributions are welcome! Please see our [contributing guidelines](https://github.com/eddiethedean/rapcsv/blob/main/CONTRIBUTING.md) (coming soon).
|
|
356
|
+
|
|
357
|
+
## License
|
|
358
|
+
|
|
359
|
+
MIT
|
|
360
|
+
|
|
361
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
rapcsv\__init__.py,sha256=lkw3qdaeQLBcdO5HDNBsZOnLGebbI1ARLCyoh1hHJ0U,2002
|
|
2
|
+
rapcsv\_rapcsv.cp310-win_amd64.pyd,sha256=Wmq5iEbs1HLt1cPJOMH9tNoAUqJQXzVFoCTnM76Pdao,1205248
|
|
3
|
+
rapcsv\_rapcsv.pyi,sha256=VCoCuVZq5bj6kTvRIOCZZy6vzBuYAOzg3pYEY0u4gus,1077
|
|
4
|
+
rapcsv\py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
rapcsv-0.1.2.dist-info\METADATA,sha256=t731B-XkGE76TaV6xBakRfLMwkJBZBJYOTvtnMzC0Dw,12559
|
|
6
|
+
rapcsv-0.1.2.dist-info\WHEEL,sha256=L_nHnx2hhpjVM_Xfu45p0kXGA_F4gVVL8EpDS6M9jpM,97
|
|
7
|
+
rapcsv-0.1.2.dist-info\RECORD,,
|