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 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
+ [![PyPI version](https://img.shields.io/pypi/v/rapcsv.svg)](https://pypi.org/project/rapcsv/)
27
+ [![Downloads](https://pepy.tech/badge/rapcsv)](https://pepy.tech/project/rapcsv)
28
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-win_amd64