kenze 0.3.0__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.
kenze-0.3.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ken
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
kenze-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: kenze
3
+ Version: 0.3.0
4
+ Summary: Big-file data prep that never runs out of memory — no SQL required. Powered by DuckDB.
5
+ Author: Ken
6
+ License: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/kenze/
8
+ Keywords: duckdb,data,csv,parquet,etl,cli,big-data,dataframe,data-cleaning
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Topic :: Scientific/Engineering
12
+ Classifier: Topic :: Utilities
13
+ Classifier: Environment :: Console
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: duckdb>=0.10
18
+ Requires-Dist: psutil>=5.9
19
+ Provides-Extra: cloud
20
+ Requires-Dist: duckdb>=0.10; extra == "cloud"
21
+ Dynamic: license-file
22
+
23
+ # kenze
24
+
25
+ **Big-file data prep that never runs out of memory — no SQL required.**
26
+
27
+ `kenze` is a tiny command-line tool for cleaning and reshaping data files
28
+ (CSV, Parquet, JSON) that are too big for pandas. It's a friendly front-end
29
+ over [DuckDB](https://duckdb.org): DuckDB does the heavy lifting (streaming,
30
+ disk-spill, all your CPU cores) and `kenze` makes it a one-liner — and
31
+ auto-configures memory so your job doesn't crash.
32
+
33
+ ```bash
34
+ pip install kenze
35
+ ```
36
+
37
+ One name for everything: `pip install kenze` → the `kenze` command → `import kenze`.
38
+
39
+ ## Why
40
+
41
+ - **It doesn't OOM.** Memory is capped to a fraction of *free* RAM and DuckDB
42
+ spills to disk instead of dying. Point it at a file bigger than your RAM; it's fine.
43
+ - **No SQL, no pandas.** Simple verbs, or a readable recipe file.
44
+ - **One streaming pass.** A whole recipe compiles to a single query — no
45
+ intermediate files, so it's fast and light.
46
+ - **Any format, local or cloud.** CSV / Parquet / JSON, plain or `.gz`,
47
+ on disk or on `s3://` / `gs://` / `https://` — auto-detected.
48
+
49
+ ## One-liners
50
+
51
+ ```bash
52
+ kenze profile sales.parquet # schema + row count, instantly
53
+ kenze peek sales.parquet # first rows + types + null counts
54
+ kenze stats sales.parquet # per-column min/max/nulls/unique
55
+ kenze check sales.csv # is the file valid? any bad rows?
56
+
57
+ kenze keep sales.parquet --cols id,city,amount -o small.csv
58
+ kenze drop users.csv --cols email,phone -o clean.parquet
59
+ kenze filter sales.parquet --where "amount > 100" -o big.csv
60
+ kenze rename sales.csv --map "amount:total" -o out.csv
61
+ kenze cast users.csv --types "zip:VARCHAR" -o out.parquet # keep leading zeros
62
+ kenze fillna users.csv --with "city:Unknown" -o out.csv
63
+ kenze mask users.csv --cols email,ssn --method hash -o safe.csv
64
+ kenze dedup users.csv --on id -o unique.parquet
65
+ kenze sample sales.parquet --n 50000 -o sample.csv
66
+ kenze clip points.parquet --bbox -10,35,5,45 -o region.parquet
67
+
68
+ kenze join orders.csv users.parquet --on user_id -o joined.parquet
69
+ kenze diff old.csv new.csv --on id # added / removed / changed
70
+ kenze pivot sales.csv --on city --values amount --agg sum --group region -o wide.csv
71
+ kenze split sales.parquet --by city -o by_city/ # one file per value
72
+ kenze partition sales.parquet --by year -o lake/ # hive year=2026/ folders
73
+ kenze convert sales.parquet -o sales.csv # just change format
74
+
75
+ kenze sql "SELECT *, lag(amount) OVER (ORDER BY ts) FROM 'sales.parquet'" -o out.csv
76
+ ```
77
+
78
+ Read or write the cloud directly (nothing to download first):
79
+
80
+ ```bash
81
+ kenze filter s3://bucket/huge.parquet --where "amount > 0" -o local.csv
82
+ ```
83
+
84
+ Pipe like any Unix tool (use `-` for stdin/stdout):
85
+
86
+ ```bash
87
+ cat data.csv | kenze filter - --where "x > 1" -o - | gzip > out.csv.gz
88
+ ```
89
+
90
+ ## Recipes
91
+
92
+ Chain steps in a readable `.dq` file — they run as one streaming pass:
93
+
94
+ ```yaml
95
+ # clean.dq
96
+ input: data/sales_${DAY}.parquet # ${DAY} filled from --set or the environment
97
+ keep: [id, city, amount]
98
+ types: zip:VARCHAR
99
+ filter: amount > 0
100
+ fillna: city:Unknown
101
+ dedup: id
102
+ sample: 50000
103
+ output: out/clean.csv
104
+ ```
105
+
106
+ ```bash
107
+ kenze run clean.dq --set DAY=2026-07-14
108
+ kenze recipe # show every valid recipe step
109
+ kenze eject clean.dq --to sql # print the raw DuckDB SQL (no lock-in)
110
+ ```
111
+
112
+ ## From Python
113
+
114
+ ```python
115
+ import kenze
116
+ kenze.sift("big.parquet", "clean.csv", keep=["id", "city"], filter="amount > 0", sample=50000)
117
+ rows = kenze.sql("SELECT city, count(*) FROM 'big.parquet' GROUP BY 1")
118
+ kenze.profile("big.parquet")
119
+ ```
120
+
121
+ ## Handy flags
122
+
123
+ - `--memory-limit 8` — pin the RAM budget (GB) for reproducible / SLA runs.
124
+ - `--temp-dir D:/spill` — put disk-spill where there's room.
125
+ - `--skip-bad-lines` — ignore malformed rows in a dirty CSV.
126
+ - `--log run.json` — write a run manifest (inputs, rows, timing).
127
+ - Writes are **atomic** — a cancelled run never leaves a half-written file.
128
+
129
+ ## Commands
130
+
131
+ `profile` · `peek` · `stats` · `check` · `validate` · `keep` · `drop` · `rename` · `cast` ·
132
+ `fillna` · `mask` · `filter` · `dedup` · `sample` · `head` · `clip` · `convert` · `join` ·
133
+ `diff` · `pivot` · `split` · `partition` · `sql` · `eject` · `run` · `recipe`
134
+
135
+ ## Where it stops (on purpose)
136
+
137
+ kenze is one dependency and one machine — that's the whole point. It maxes out
138
+ your cores and spills to disk so a single laptop or VM can chew through files far
139
+ bigger than its RAM. It does **not** run a cluster. If you've genuinely outgrown
140
+ one machine (multi-terabyte, distributed pipelines with SLAs and lineage
141
+ tracking), reach for Spark/Dask — kenze is the tool you use *before* you need those.
142
+
143
+ ## Troubleshooting
144
+
145
+ **`'kenze' is not recognized` / `kenze: command not found`?**
146
+ `pip` installed kenze correctly — the command just landed in a folder that isn't on
147
+ your PATH (this affects every pip-installed CLI). Options:
148
+
149
+ - **Use it now, no setup:** `python -m kenze --help`
150
+ - **Fix it for good:** reinstall Python from [python.org](https://www.python.org/downloads/)
151
+ with **"Add python.exe to PATH"** ticked, or use `python -m pipx install kenze`.
152
+
153
+ MIT licensed.
kenze-0.3.0/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # kenze
2
+
3
+ **Big-file data prep that never runs out of memory — no SQL required.**
4
+
5
+ `kenze` is a tiny command-line tool for cleaning and reshaping data files
6
+ (CSV, Parquet, JSON) that are too big for pandas. It's a friendly front-end
7
+ over [DuckDB](https://duckdb.org): DuckDB does the heavy lifting (streaming,
8
+ disk-spill, all your CPU cores) and `kenze` makes it a one-liner — and
9
+ auto-configures memory so your job doesn't crash.
10
+
11
+ ```bash
12
+ pip install kenze
13
+ ```
14
+
15
+ One name for everything: `pip install kenze` → the `kenze` command → `import kenze`.
16
+
17
+ ## Why
18
+
19
+ - **It doesn't OOM.** Memory is capped to a fraction of *free* RAM and DuckDB
20
+ spills to disk instead of dying. Point it at a file bigger than your RAM; it's fine.
21
+ - **No SQL, no pandas.** Simple verbs, or a readable recipe file.
22
+ - **One streaming pass.** A whole recipe compiles to a single query — no
23
+ intermediate files, so it's fast and light.
24
+ - **Any format, local or cloud.** CSV / Parquet / JSON, plain or `.gz`,
25
+ on disk or on `s3://` / `gs://` / `https://` — auto-detected.
26
+
27
+ ## One-liners
28
+
29
+ ```bash
30
+ kenze profile sales.parquet # schema + row count, instantly
31
+ kenze peek sales.parquet # first rows + types + null counts
32
+ kenze stats sales.parquet # per-column min/max/nulls/unique
33
+ kenze check sales.csv # is the file valid? any bad rows?
34
+
35
+ kenze keep sales.parquet --cols id,city,amount -o small.csv
36
+ kenze drop users.csv --cols email,phone -o clean.parquet
37
+ kenze filter sales.parquet --where "amount > 100" -o big.csv
38
+ kenze rename sales.csv --map "amount:total" -o out.csv
39
+ kenze cast users.csv --types "zip:VARCHAR" -o out.parquet # keep leading zeros
40
+ kenze fillna users.csv --with "city:Unknown" -o out.csv
41
+ kenze mask users.csv --cols email,ssn --method hash -o safe.csv
42
+ kenze dedup users.csv --on id -o unique.parquet
43
+ kenze sample sales.parquet --n 50000 -o sample.csv
44
+ kenze clip points.parquet --bbox -10,35,5,45 -o region.parquet
45
+
46
+ kenze join orders.csv users.parquet --on user_id -o joined.parquet
47
+ kenze diff old.csv new.csv --on id # added / removed / changed
48
+ kenze pivot sales.csv --on city --values amount --agg sum --group region -o wide.csv
49
+ kenze split sales.parquet --by city -o by_city/ # one file per value
50
+ kenze partition sales.parquet --by year -o lake/ # hive year=2026/ folders
51
+ kenze convert sales.parquet -o sales.csv # just change format
52
+
53
+ kenze sql "SELECT *, lag(amount) OVER (ORDER BY ts) FROM 'sales.parquet'" -o out.csv
54
+ ```
55
+
56
+ Read or write the cloud directly (nothing to download first):
57
+
58
+ ```bash
59
+ kenze filter s3://bucket/huge.parquet --where "amount > 0" -o local.csv
60
+ ```
61
+
62
+ Pipe like any Unix tool (use `-` for stdin/stdout):
63
+
64
+ ```bash
65
+ cat data.csv | kenze filter - --where "x > 1" -o - | gzip > out.csv.gz
66
+ ```
67
+
68
+ ## Recipes
69
+
70
+ Chain steps in a readable `.dq` file — they run as one streaming pass:
71
+
72
+ ```yaml
73
+ # clean.dq
74
+ input: data/sales_${DAY}.parquet # ${DAY} filled from --set or the environment
75
+ keep: [id, city, amount]
76
+ types: zip:VARCHAR
77
+ filter: amount > 0
78
+ fillna: city:Unknown
79
+ dedup: id
80
+ sample: 50000
81
+ output: out/clean.csv
82
+ ```
83
+
84
+ ```bash
85
+ kenze run clean.dq --set DAY=2026-07-14
86
+ kenze recipe # show every valid recipe step
87
+ kenze eject clean.dq --to sql # print the raw DuckDB SQL (no lock-in)
88
+ ```
89
+
90
+ ## From Python
91
+
92
+ ```python
93
+ import kenze
94
+ kenze.sift("big.parquet", "clean.csv", keep=["id", "city"], filter="amount > 0", sample=50000)
95
+ rows = kenze.sql("SELECT city, count(*) FROM 'big.parquet' GROUP BY 1")
96
+ kenze.profile("big.parquet")
97
+ ```
98
+
99
+ ## Handy flags
100
+
101
+ - `--memory-limit 8` — pin the RAM budget (GB) for reproducible / SLA runs.
102
+ - `--temp-dir D:/spill` — put disk-spill where there's room.
103
+ - `--skip-bad-lines` — ignore malformed rows in a dirty CSV.
104
+ - `--log run.json` — write a run manifest (inputs, rows, timing).
105
+ - Writes are **atomic** — a cancelled run never leaves a half-written file.
106
+
107
+ ## Commands
108
+
109
+ `profile` · `peek` · `stats` · `check` · `validate` · `keep` · `drop` · `rename` · `cast` ·
110
+ `fillna` · `mask` · `filter` · `dedup` · `sample` · `head` · `clip` · `convert` · `join` ·
111
+ `diff` · `pivot` · `split` · `partition` · `sql` · `eject` · `run` · `recipe`
112
+
113
+ ## Where it stops (on purpose)
114
+
115
+ kenze is one dependency and one machine — that's the whole point. It maxes out
116
+ your cores and spills to disk so a single laptop or VM can chew through files far
117
+ bigger than its RAM. It does **not** run a cluster. If you've genuinely outgrown
118
+ one machine (multi-terabyte, distributed pipelines with SLAs and lineage
119
+ tracking), reach for Spark/Dask — kenze is the tool you use *before* you need those.
120
+
121
+ ## Troubleshooting
122
+
123
+ **`'kenze' is not recognized` / `kenze: command not found`?**
124
+ `pip` installed kenze correctly — the command just landed in a folder that isn't on
125
+ your PATH (this affects every pip-installed CLI). Options:
126
+
127
+ - **Use it now, no setup:** `python -m kenze --help`
128
+ - **Fix it for good:** reinstall Python from [python.org](https://www.python.org/downloads/)
129
+ with **"Add python.exe to PATH"** ticked, or use `python -m pipx install kenze`.
130
+
131
+ MIT licensed.
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "kenze"
7
+ version = "0.3.0"
8
+ description = "Big-file data prep that never runs out of memory — no SQL required. Powered by DuckDB."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Ken" }]
13
+ keywords = ["duckdb", "data", "csv", "parquet", "etl", "cli", "big-data", "dataframe", "data-cleaning"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Topic :: Scientific/Engineering",
18
+ "Topic :: Utilities",
19
+ "Environment :: Console",
20
+ ]
21
+ # psutil is core: the never-OOM memory sizing is the headline feature, so it
22
+ # ships by default rather than hiding behind an optional extra.
23
+ dependencies = ["duckdb>=0.10", "psutil>=5.9"]
24
+
25
+ [project.optional-dependencies]
26
+ cloud = ["duckdb>=0.10"] # S3/GCS/Azure work out of the box via DuckDB httpfs
27
+
28
+ [project.urls]
29
+ Homepage = "https://pypi.org/project/kenze/"
30
+
31
+ [project.scripts]
32
+ kenze = "kenze.cli:main"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
kenze-0.3.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,70 @@
1
+ """kenze - big-file data prep that never runs out of memory.
2
+
3
+ One `pip install`, then simple commands. DuckDB does the heavy lifting under
4
+ the hood (streaming, disk-spill, all cores); kenze just makes it a one-liner
5
+ and auto-configures memory so it doesn't OOM.
6
+
7
+ You can also use it from Python:
8
+
9
+ import kenze
10
+ kenze.sift("big.parquet", "clean.csv", keep=["id", "city"],
11
+ filter="amount > 0", sample=50000)
12
+ rows = kenze.sql("SELECT city, count(*) FROM 'big.parquet' GROUP BY 1")
13
+ kenze.profile("big.parquet")
14
+ """
15
+ from __future__ import annotations
16
+
17
+ from .engine import connect
18
+ from .ops import (
19
+ build_query,
20
+ check,
21
+ diff,
22
+ join,
23
+ partition,
24
+ peek,
25
+ pivot,
26
+ profile,
27
+ run_spec,
28
+ run_sql,
29
+ split,
30
+ stats,
31
+ validate,
32
+ )
33
+
34
+ __version__ = "0.3.0"
35
+
36
+
37
+ def sift(input, output, con=None, quiet=True, **steps):
38
+ """Run one streaming pass. steps = keep/drop/filter/bbox/types/fillna/
39
+ mask/rename/dedup/sample/head (same words as the recipe / CLI)."""
40
+ spec = {"input": input, "output": output, **steps}
41
+ return run_spec(spec, con=con, quiet=quiet)
42
+
43
+
44
+ def run(recipe_path, variables=None, con=None, quiet=True):
45
+ """Run a .dq recipe file from Python."""
46
+ from .recipe import parse
47
+
48
+ with open(recipe_path, encoding="utf-8") as f:
49
+ spec = parse(f.read(), variables=variables)
50
+ return run_spec(spec, con=con, quiet=quiet)
51
+
52
+
53
+ def sql(query, con=None):
54
+ """Run any DuckDB SQL and get the rows back (window functions, aggregates)."""
55
+ own = con is None
56
+ con = con or connect()
57
+ try:
58
+ return con.execute(query).fetchall()
59
+ finally:
60
+ if own:
61
+ con.close()
62
+
63
+
64
+ __all__ = [
65
+ "connect", "sift", "run", "sql",
66
+ "run_spec", "build_query", "run_sql",
67
+ "profile", "stats", "peek", "check", "validate",
68
+ "join", "diff", "split", "partition", "pivot",
69
+ "__version__",
70
+ ]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()