tha-csv-runner 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/PKG-INFO +6 -7
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/README.md +5 -6
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/pyproject.toml +1 -1
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/src/tha_csv_runner/__init__.py +1 -1
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/src/tha_csv_runner/runner.py +6 -8
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/test_runner.py +8 -6
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/uv.lock +1 -1
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/.github/workflows/ci.yml +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/.github/workflows/publish.yml +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/.gitignore +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/LICENSE +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/src/tha_csv_runner/__main__.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/src/tha_csv_runner/errors.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/__init__.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/conftest.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/fixtures/__init__.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/fixtures/processors.py +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/fixtures/simple.csv +0 -0
- {tha_csv_runner-0.2.0 → tha_csv_runner-0.2.2}/tests/fixtures/with_errors.csv +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tha-csv-runner
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Run a function over every row of a CSV — with progress, header validation, and structured per-row errors.
|
|
5
5
|
Project-URL: Homepage, https://github.com/tha-guy-nate/tha-csv-runner
|
|
6
6
|
Project-URL: Issues, https://github.com/tha-guy-nate/tha-csv-runner/issues
|
|
@@ -47,7 +47,7 @@ def process(row: dict) -> None:
|
|
|
47
47
|
|
|
48
48
|
runner = ThaCSV()
|
|
49
49
|
|
|
50
|
-
runner.read("Step 1 of 1", "data.csv", ["name", "email"], process)
|
|
50
|
+
rows = runner.read("Step 1 of 1", "data.csv", ["name", "email"], process)
|
|
51
51
|
runner.write("Step 1 of 1", "output.csv")
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ runner.write("Step 1 of 1", "output.csv")
|
|
|
55
55
|
|
|
56
56
|
1. Opens the CSV and validates that all `required_headers` are present — raises immediately if any are missing
|
|
57
57
|
2. Iterates every row with a `tqdm` progress bar labelled with `desc`
|
|
58
|
-
3. Calls your `
|
|
58
|
+
3. Calls your `validator(row)` function — if it raises, that row is marked as an error and processing continues
|
|
59
59
|
4. Appends three columns to every row: `row number`, `row status`, and `message`
|
|
60
60
|
- On success: `row status` and `message` are blank
|
|
61
61
|
- On error: `row status = "error"`, `message = str(exception)`
|
|
@@ -76,15 +76,14 @@ runner.read(
|
|
|
76
76
|
"Step 2 of 10", # progress bar label — pass None to use the filename
|
|
77
77
|
"data.csv", # path to input CSV
|
|
78
78
|
["a", "b"], # columns that must exist — raises ConfigError if missing
|
|
79
|
-
|
|
80
|
-
sample=100, # optional: process only the first N rows
|
|
79
|
+
validator=my_func, # optional: callable(row: dict) -> None
|
|
81
80
|
enrich=True, # optional: set False to skip row number/status/message columns
|
|
82
81
|
)
|
|
83
82
|
```
|
|
84
83
|
|
|
85
|
-
Reads and processes all rows.
|
|
84
|
+
Reads and processes all rows. Returns the rows as a `list[dict]` (same object as `runner.rows`).
|
|
86
85
|
|
|
87
|
-
When `enrich=False`,
|
|
86
|
+
When `enrich=False`, validator exceptions are re-raised instead of captured.
|
|
88
87
|
|
|
89
88
|
### `runner.write()`
|
|
90
89
|
|
|
@@ -22,7 +22,7 @@ def process(row: dict) -> None:
|
|
|
22
22
|
|
|
23
23
|
runner = ThaCSV()
|
|
24
24
|
|
|
25
|
-
runner.read("Step 1 of 1", "data.csv", ["name", "email"], process)
|
|
25
|
+
rows = runner.read("Step 1 of 1", "data.csv", ["name", "email"], process)
|
|
26
26
|
runner.write("Step 1 of 1", "output.csv")
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ runner.write("Step 1 of 1", "output.csv")
|
|
|
30
30
|
|
|
31
31
|
1. Opens the CSV and validates that all `required_headers` are present — raises immediately if any are missing
|
|
32
32
|
2. Iterates every row with a `tqdm` progress bar labelled with `desc`
|
|
33
|
-
3. Calls your `
|
|
33
|
+
3. Calls your `validator(row)` function — if it raises, that row is marked as an error and processing continues
|
|
34
34
|
4. Appends three columns to every row: `row number`, `row status`, and `message`
|
|
35
35
|
- On success: `row status` and `message` are blank
|
|
36
36
|
- On error: `row status = "error"`, `message = str(exception)`
|
|
@@ -51,15 +51,14 @@ runner.read(
|
|
|
51
51
|
"Step 2 of 10", # progress bar label — pass None to use the filename
|
|
52
52
|
"data.csv", # path to input CSV
|
|
53
53
|
["a", "b"], # columns that must exist — raises ConfigError if missing
|
|
54
|
-
|
|
55
|
-
sample=100, # optional: process only the first N rows
|
|
54
|
+
validator=my_func, # optional: callable(row: dict) -> None
|
|
56
55
|
enrich=True, # optional: set False to skip row number/status/message columns
|
|
57
56
|
)
|
|
58
57
|
```
|
|
59
58
|
|
|
60
|
-
Reads and processes all rows.
|
|
59
|
+
Reads and processes all rows. Returns the rows as a `list[dict]` (same object as `runner.rows`).
|
|
61
60
|
|
|
62
|
-
When `enrich=False`,
|
|
61
|
+
When `enrich=False`, validator exceptions are re-raised instead of captured.
|
|
63
62
|
|
|
64
63
|
### `runner.write()`
|
|
65
64
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tha-csv-runner"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Run a function over every row of a CSV — with progress, header validation, and structured per-row errors."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -27,10 +27,9 @@ class ThaCSV:
|
|
|
27
27
|
desc: str | None,
|
|
28
28
|
input_path: str | Path,
|
|
29
29
|
required_headers: list[str],
|
|
30
|
-
|
|
31
|
-
sample: int | None = None,
|
|
30
|
+
validator: Callable[[dict], None] | None = None,
|
|
32
31
|
enrich: bool = True,
|
|
33
|
-
) ->
|
|
32
|
+
) -> list[dict]:
|
|
34
33
|
self._input_path = Path(input_path)
|
|
35
34
|
|
|
36
35
|
with open(self._input_path, newline="", encoding="utf-8") as f:
|
|
@@ -42,9 +41,6 @@ class ThaCSV:
|
|
|
42
41
|
raise ConfigError(f"Missing required headers: {missing}")
|
|
43
42
|
raw_rows = list(reader)
|
|
44
43
|
|
|
45
|
-
if sample is not None:
|
|
46
|
-
raw_rows = raw_rows[:sample]
|
|
47
|
-
|
|
48
44
|
self.rows = []
|
|
49
45
|
self._read = True
|
|
50
46
|
|
|
@@ -55,8 +51,8 @@ class ThaCSV:
|
|
|
55
51
|
else:
|
|
56
52
|
enriched = dict(row)
|
|
57
53
|
try:
|
|
58
|
-
if
|
|
59
|
-
|
|
54
|
+
if validator is not None:
|
|
55
|
+
validator(enriched)
|
|
60
56
|
except Exception as exc:
|
|
61
57
|
if enrich:
|
|
62
58
|
enriched["row status"] = "error"
|
|
@@ -65,6 +61,8 @@ class ThaCSV:
|
|
|
65
61
|
raise
|
|
66
62
|
self.rows.append(enriched)
|
|
67
63
|
|
|
64
|
+
return self.rows
|
|
65
|
+
|
|
68
66
|
def write(
|
|
69
67
|
self,
|
|
70
68
|
desc: str | None,
|
|
@@ -23,6 +23,13 @@ def test_happy_path(simple_csv: Path) -> None:
|
|
|
23
23
|
assert all(r["row status"] == "" for r in runner.rows)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def test_read_returns_rows(simple_csv: Path) -> None:
|
|
27
|
+
runner = ThaCSV()
|
|
28
|
+
result = runner.read(None, simple_csv, ["name"])
|
|
29
|
+
assert result is runner.rows
|
|
30
|
+
assert len(result) == 3
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
def test_row_number_injected(simple_csv: Path) -> None:
|
|
27
34
|
runner = ThaCSV()
|
|
28
35
|
runner.read(None, simple_csv, ["name"])
|
|
@@ -58,11 +65,6 @@ def test_missing_required_header_raises(simple_csv: Path) -> None:
|
|
|
58
65
|
runner.read(None, simple_csv, ["id", "phone"])
|
|
59
66
|
|
|
60
67
|
|
|
61
|
-
def test_sample_limits_rows(simple_csv: Path) -> None:
|
|
62
|
-
runner = ThaCSV()
|
|
63
|
-
runner.read(None, simple_csv, ["name"], sample=2)
|
|
64
|
-
assert len(runner.rows) == 2
|
|
65
|
-
|
|
66
68
|
|
|
67
69
|
def test_original_columns_preserved(simple_csv: Path) -> None:
|
|
68
70
|
runner = ThaCSV()
|
|
@@ -217,7 +219,7 @@ def test_enrich_false_preserves_original_columns(simple_csv: Path) -> None:
|
|
|
217
219
|
assert runner.rows[0]["email"] == "alice@example.com"
|
|
218
220
|
|
|
219
221
|
|
|
220
|
-
def
|
|
222
|
+
def test_enrich_false_validator_error_still_raises(simple_csv: Path) -> None:
|
|
221
223
|
runner = ThaCSV()
|
|
222
224
|
with pytest.raises(ValueError, match="Bob is not allowed"):
|
|
223
225
|
runner.read(None, simple_csv, ["name"], fail_on_bob, enrich=False)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|