fauxdata-cli 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.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.
- fauxdata/__init__.py +1 -1
- fauxdata/commands/agent.py +1 -1
- fauxdata/commands/infer.py +24 -2
- fauxdata/validator.py +1 -2
- {fauxdata_cli-0.2.0.dist-info → fauxdata_cli-0.2.2.dist-info}/METADATA +14 -14
- {fauxdata_cli-0.2.0.dist-info → fauxdata_cli-0.2.2.dist-info}/RECORD +9 -9
- {fauxdata_cli-0.2.0.dist-info → fauxdata_cli-0.2.2.dist-info}/WHEEL +1 -1
- {fauxdata_cli-0.2.0.dist-info → fauxdata_cli-0.2.2.dist-info}/entry_points.txt +0 -0
- {fauxdata_cli-0.2.0.dist-info → fauxdata_cli-0.2.2.dist-info}/licenses/LICENSE +0 -0
fauxdata/__init__.py
CHANGED
fauxdata/commands/agent.py
CHANGED
|
@@ -139,7 +139,7 @@ Notes:
|
|
|
139
139
|
|
|
140
140
|
{presets}
|
|
141
141
|
|
|
142
|
-
Presets are locale-aware and coherent within a row (the email matches the name, the city matches the country).
|
|
142
|
+
Presets are locale-aware and coherent within a row (the email matches the name, the city matches the country).
|
|
143
143
|
|
|
144
144
|
## Validation rules
|
|
145
145
|
|
fauxdata/commands/infer.py
CHANGED
|
@@ -31,6 +31,11 @@ _DTYPE_MAP = {
|
|
|
31
31
|
"Date": "date",
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
# Presets pointblank matches on the column name alone, skipping categorical detection.
|
|
35
|
+
# Personal presets (name, phone, address...) are left out on purpose: restoring their
|
|
36
|
+
# source values would copy real people's data into the schema.
|
|
37
|
+
_CATEGORICAL_PRESETS = {"state", "city", "country", "country_code_2", "currency_code", "company", "job"}
|
|
38
|
+
|
|
34
39
|
|
|
35
40
|
def _col_type_from_dtype(dtype: str) -> str:
|
|
36
41
|
"""Map a pointblank/polars dtype name to a fauxdata col_type."""
|
|
@@ -83,6 +88,19 @@ def _field_to_spec(field) -> dict:
|
|
|
83
88
|
return spec
|
|
84
89
|
|
|
85
90
|
|
|
91
|
+
def _restore_categorical(spec: dict, series: pl.Series, threshold: int | float) -> dict:
|
|
92
|
+
"""Replace a name-matched preset with the source values on a low-cardinality column."""
|
|
93
|
+
if spec.get("preset") not in _CATEGORICAL_PRESETS or spec.get("unique"):
|
|
94
|
+
return spec
|
|
95
|
+
limit = threshold if isinstance(threshold, int) else int(threshold * series.len())
|
|
96
|
+
values = series.drop_nulls().unique().sort().to_list()
|
|
97
|
+
if len(values) > limit:
|
|
98
|
+
return spec
|
|
99
|
+
del spec["preset"]
|
|
100
|
+
spec["values"] = values
|
|
101
|
+
return spec
|
|
102
|
+
|
|
103
|
+
|
|
86
104
|
def _build_validation(columns: list[tuple[str, dict]]) -> list[dict]:
|
|
87
105
|
"""Derive validation rules from the inferred column specs."""
|
|
88
106
|
rules: list[dict] = []
|
|
@@ -160,14 +178,18 @@ def run(
|
|
|
160
178
|
if not json_out:
|
|
161
179
|
rprint(f" Loaded [bold]{len(df)}[/bold] rows, [bold]{len(df.columns)}[/bold] columns")
|
|
162
180
|
|
|
181
|
+
threshold = _threshold(categorical_threshold)
|
|
163
182
|
pb_schema = pb.schema_from_tbl(
|
|
164
183
|
df,
|
|
165
|
-
categorical_threshold=
|
|
184
|
+
categorical_threshold=threshold,
|
|
166
185
|
detect_presets=detect_presets,
|
|
167
186
|
sample_size=sample_size,
|
|
168
187
|
)
|
|
169
188
|
|
|
170
|
-
columns = [
|
|
189
|
+
columns = [
|
|
190
|
+
(col_name, _restore_categorical(_field_to_spec(field), df[col_name], threshold))
|
|
191
|
+
for col_name, field in pb_schema.columns
|
|
192
|
+
]
|
|
171
193
|
|
|
172
194
|
schema_name = name or Path(dataset_path).stem
|
|
173
195
|
out_rows = rows if rows is not None else len(df)
|
fauxdata/validator.py
CHANGED
|
@@ -80,8 +80,7 @@ def _add_rule(v: pb.Validate, rule: ValidationRule) -> None:
|
|
|
80
80
|
|
|
81
81
|
def _extract_results(v: pb.Validate, rules: list[ValidationRule]) -> list[dict]:
|
|
82
82
|
"""Extract per-step results as a list of dicts."""
|
|
83
|
-
# validation_info,
|
|
84
|
-
# columns (rows_distinct) in pointblank 1.0.1
|
|
83
|
+
# validation_info carries active and eval_error, used to flag steps that could not run
|
|
85
84
|
steps = {s.i: s for s in v.validation_info}
|
|
86
85
|
results = []
|
|
87
86
|
# Build a flat list of steps (one per column for multi-column rules)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fauxdata-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: CLI for generating and validating fake datasets
|
|
5
5
|
Project-URL: Homepage, https://aborruso.github.io/fauxdata/
|
|
6
6
|
Project-URL: Repository, https://github.com/aborruso/fauxdata
|
|
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Requires-Python: >=3.11
|
|
16
|
-
Requires-Dist: pointblank>=1.0
|
|
16
|
+
Requires-Dist: pointblank>=1.2.0
|
|
17
17
|
Requires-Dist: polars>=1.0
|
|
18
18
|
Requires-Dist: pyfiglet>=1.0
|
|
19
19
|
Requires-Dist: pyyaml>=6.0
|
|
@@ -93,7 +93,7 @@ fauxdata init --name orders
|
|
|
93
93
|
|
|
94
94
|
## Schema format
|
|
95
95
|
|
|
96
|
-
A schema is a YAML file that describes the structure of your dataset. Here is a realistic example for a people dataset:
|
|
96
|
+
A schema is a YAML file that describes the structure of your dataset. Here is a realistic example for a people dataset, adapted from [`schemas/people.yml`](https://github.com/aborruso/fauxdata/blob/main/schemas/people.yml):
|
|
97
97
|
|
|
98
98
|
```yaml
|
|
99
99
|
name: people
|
|
@@ -169,12 +169,12 @@ validation:
|
|
|
169
169
|
|
|
170
170
|
| Type | Description | Options |
|
|
171
171
|
|------|-------------|---------|
|
|
172
|
-
| `int` | Integer | `min`, `max`, `unique` |
|
|
173
|
-
| `float` | Floating point | `min`, `max`, `precision` |
|
|
172
|
+
| `int` | Integer | `min`, `max`, `unique`, `values` |
|
|
173
|
+
| `float` | Floating point | `min`, `max`, `precision`, `unique`, `values` |
|
|
174
174
|
| `string` | Text | `preset`, `values`, `pattern`, `unique`, `min_length`, `max_length` |
|
|
175
175
|
| `bool` | Boolean | — |
|
|
176
|
-
| `date` | Date | `min`, `max` (ISO format) |
|
|
177
|
-
| `datetime` | Datetime | `min`, `max` (ISO format) |
|
|
176
|
+
| `date` | Date | `min`, `max` (ISO format), `unique` |
|
|
177
|
+
| `datetime` | Datetime | `min`, `max` (ISO format), `unique` |
|
|
178
178
|
|
|
179
179
|
### Float precision
|
|
180
180
|
|
|
@@ -269,7 +269,7 @@ fauxdata generate schemas/people.yml --out - --format jsonl | wc -l
|
|
|
269
269
|
| `--rows` | `-r` | from schema | Number of rows to generate |
|
|
270
270
|
| `--out` | `-o` | from schema | Output path — use `-` for stdout |
|
|
271
271
|
| `--format` | `-f` | from schema | Output format: `csv`, `parquet`, `json`, `jsonl`, `jsonlines` |
|
|
272
|
-
| `--seed` | `-s` | from schema | Random seed for reproducibility |
|
|
272
|
+
| `--seed` | `-s` | from schema | Random seed for reproducibility: same seed, same data, on the same pointblank version |
|
|
273
273
|
| `--validate` | `-v` | off | Run validation rules after generating |
|
|
274
274
|
| `--json` | | off | Print only a JSON summary to stdout (see [Using fauxdata with AI agents](#using-fauxdata-with-ai-agents)) |
|
|
275
275
|
|
|
@@ -277,7 +277,7 @@ When `--out -` is used, all output messages are suppressed and only data is writ
|
|
|
277
277
|
|
|
278
278
|
### `fauxdata infer DATASET`
|
|
279
279
|
|
|
280
|
-
Build a YAML schema from a **real** dataset. fauxdata inspects the table (via pointblank's schema inference) and writes a schema with inferred ranges, categorical value sets, string presets (email, url…), uniqueness, null rates, and string lengths — plus matching `validation:` rules. Feed the result back to `fauxdata generate` to produce synthetic data
|
|
280
|
+
Build a YAML schema from a **real** dataset. fauxdata inspects the table (via pointblank's schema inference) and writes a schema with inferred ranges, categorical value sets, string presets (email, url…), uniqueness, null rates, and string lengths — plus matching `validation:` rules. Feed the result back to `fauxdata generate` to produce synthetic data with the same columns, ranges and value sets, without copying the real rows. Each column is generated independently, so correlations between columns, rules such as `end_date > start_date`, and category frequencies are not preserved.
|
|
281
281
|
|
|
282
282
|
```
|
|
283
283
|
fauxdata infer real_data.csv # -> real_data.yml
|
|
@@ -296,7 +296,7 @@ fauxdata infer big.parquet --sample-size 10000 --out - | head # stream to stdou
|
|
|
296
296
|
| `--detect-presets` / `--no-detect-presets` | | on | Match string columns to known presets (email, url…) |
|
|
297
297
|
| `--sample-size` | | all rows | Sample N rows before analysis (for very large tables) |
|
|
298
298
|
|
|
299
|
-
> **Notes.** Low-cardinality columns (≤ `--categorical-threshold` distinct values) are frozen to their exact source values via `values:` — desirable for categories like `status`, but it means sensitive low-cardinality columns are reproduced verbatim. Raise the threshold or edit the schema if that's not what you want. Also, a column inferred as `unique` over a narrow integer range cannot generate many more rows than the source; widen `min`/`max` or drop `unique` to amplify.
|
|
299
|
+
> **Notes.** Low-cardinality columns (≤ `--categorical-threshold` distinct values) are frozen to their exact source values via `values:` — desirable for categories like `status`, but it means sensitive low-cardinality columns are reproduced verbatim. Raise the threshold or edit the schema if that's not what you want. This also applies to columns whose name suggests a place, company or job (`region`, `city`, `company`...). Personal presets are never frozen, so a low-cardinality column such as `product_name` still gets people's names: use `--no-detect-presets` or edit the schema. Also, a column inferred as `unique` over a narrow integer range cannot generate many more rows than the source; widen `min`/`max` or drop `unique` to amplify.
|
|
300
300
|
|
|
301
301
|
### `fauxdata validate DATASET SCHEMA`
|
|
302
302
|
|
|
@@ -365,13 +365,13 @@ fauxdata validate data.csv schema.yml --json
|
|
|
365
365
|
|
|
366
366
|
## Example schemas
|
|
367
367
|
|
|
368
|
-
Three ready-to-use schemas are included in `schemas
|
|
368
|
+
Three ready-to-use schemas are included in [`schemas/`](https://github.com/aborruso/fauxdata/tree/main/schemas):
|
|
369
369
|
|
|
370
370
|
| Schema | Domain | Columns |
|
|
371
371
|
|--------|--------|---------|
|
|
372
|
-
| `people.yml` | Personal data | id, name, email, age, city, country_code, active, signup_date, score |
|
|
373
|
-
| `orders.yml` | E-commerce | order_id, customer_id, product, amount, status, created_at |
|
|
374
|
-
| `events.yml` | Analytics | event_id, user_id, event_type, timestamp, ip, user_agent, session_duration |
|
|
372
|
+
| [`people.yml`](https://github.com/aborruso/fauxdata/blob/main/schemas/people.yml) | Personal data | id, name, email, age, city, country_code, active, signup_date, score |
|
|
373
|
+
| [`orders.yml`](https://github.com/aborruso/fauxdata/blob/main/schemas/orders.yml) | E-commerce | order_id, customer_id, product, amount, status, created_at |
|
|
374
|
+
| [`events.yml`](https://github.com/aborruso/fauxdata/blob/main/schemas/events.yml) | Analytics | event_id, user_id, event_type, timestamp, ip, user_agent, session_duration |
|
|
375
375
|
|
|
376
376
|
---
|
|
377
377
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
fauxdata/__init__.py,sha256=
|
|
1
|
+
fauxdata/__init__.py,sha256=X4QgoKwTbMrq4zssag83Qa2O9IOKqphM7h0ZDJsXsIU,89
|
|
2
2
|
fauxdata/generator.py,sha256=h9QGwPsZWyi12N6F_sFPcISA2JAQrSqLIzMQ1vz0fp0,5057
|
|
3
3
|
fauxdata/jsonmode.py,sha256=XOVqTv1HPKyTzE9a3clSYsiFQXhuLbvgb6qCmkBzicE,498
|
|
4
4
|
fauxdata/main.py,sha256=QDlYe0sDO9GatXSJUALz6bOxKewwTBwu-MANUkUAnC4,7266
|
|
5
5
|
fauxdata/output.py,sha256=VS-aXquONgMxSaLBjoUBvFwQrnOSJl5X9Yzrx3XFzjY,1562
|
|
6
6
|
fauxdata/schema.py,sha256=XXTUeUKiUFddHM-HfSE0vgSfj6KIBNon7sgkCxW6D6c,5943
|
|
7
|
-
fauxdata/validator.py,sha256=
|
|
7
|
+
fauxdata/validator.py,sha256=WHxZGYNKE-TxZyeMQMCLzxB26LnZIeJiNzsV3oc1e4A,4036
|
|
8
8
|
fauxdata/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
fauxdata/commands/agent.py,sha256=
|
|
9
|
+
fauxdata/commands/agent.py,sha256=VddV9Ws-27FmWEJlGwz_N4mpXeqvvs0ckOAy9u5Powo,5091
|
|
10
10
|
fauxdata/commands/generate.py,sha256=vNaOQGJFQWiUhFfx9zOoiNR039i5JVLtD1JcNH5C-rQ,5880
|
|
11
|
-
fauxdata/commands/infer.py,sha256=
|
|
11
|
+
fauxdata/commands/infer.py,sha256=nw0kbBM-2hN5PHwyE_dXsSoNig1VgQPog4kRKYmgGDw,8158
|
|
12
12
|
fauxdata/commands/init.py,sha256=GXJWSvndpKXI5mUe3N6IrZSK-V7JcgmKoWoh-uXljig,2964
|
|
13
13
|
fauxdata/commands/preview.py,sha256=ZR7yjHHoj4QciW28ezH_9k5W2a-muX4xdxOJp5MyNjw,3063
|
|
14
14
|
fauxdata/commands/validate.py,sha256=9I-8ArZnCh-QvFJ-BldtWiXDnPANuGlxBb2t2xP1aZk,2652
|
|
15
|
-
fauxdata_cli-0.2.
|
|
16
|
-
fauxdata_cli-0.2.
|
|
17
|
-
fauxdata_cli-0.2.
|
|
18
|
-
fauxdata_cli-0.2.
|
|
19
|
-
fauxdata_cli-0.2.
|
|
15
|
+
fauxdata_cli-0.2.2.dist-info/METADATA,sha256=ApKicYUJ2vv71uc2hT_eGBkmZfVMwmAxFhjt_K5Iq7A,16165
|
|
16
|
+
fauxdata_cli-0.2.2.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
17
|
+
fauxdata_cli-0.2.2.dist-info/entry_points.txt,sha256=fplnEfv4hunVCf1dWhc7fBdcAP_10PdCAqCfxIOnh1o,47
|
|
18
|
+
fauxdata_cli-0.2.2.dist-info/licenses/LICENSE,sha256=NpzSNzsY_eubQrJ-zE25rLD9BTlCM3zlP-iPVNmndFk,1092
|
|
19
|
+
fauxdata_cli-0.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|