table-validator 0.1.7__tar.gz → 0.1.8__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.
- {table_validator-0.1.7/table_validator.egg-info → table_validator-0.1.8}/PKG-INFO +1 -1
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/wizard.py +56 -0
- {table_validator-0.1.7 → table_validator-0.1.8/table_validator.egg-info}/PKG-INFO +1 -1
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/scm_version.json +2 -2
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_wizard.py +91 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/LICENSE +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/README.md +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/pyproject.toml +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/setup.cfg +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/azure_auth.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/databricks_auth.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/main.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/partition_prompt.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/summary_table.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/manager.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/schema.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/azure_connector.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/databricks_connector.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/engine/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/engine/comparison_engine.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/models.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/reports/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/reports/excel_report.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/blob_discovery.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/catalog_validator.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/row_validator.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/SOURCES.txt +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/dependency_links.txt +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/entry_points.txt +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/requires.txt +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/scm_file_list.json +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/top_level.txt +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/__init__.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_blob_discovery.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_catalog_validator.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_cli.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_databricks_connector.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_excel_report.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_partition_prompt.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_report_command.py +0 -0
- {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_row_validator.py +0 -0
|
@@ -117,6 +117,52 @@ def _prompt_primary_key(existing: Optional[list]) -> Optional[list]:
|
|
|
117
117
|
return [col.strip() for col in answer.split(",") if col.strip()]
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
def _prompt_column_list(prompt_text: str, existing: Optional[list]) -> Optional[list]:
|
|
121
|
+
"""Shared free-text parser for a comma-separated column list answer -
|
|
122
|
+
used by all three customization sub-options below. Returns None for
|
|
123
|
+
a blank answer (caller decides the actual default: None vs [])."""
|
|
124
|
+
default_str = ", ".join(existing) if existing else ""
|
|
125
|
+
answer = _ask(questionary.text(prompt_text, default=default_str))
|
|
126
|
+
if not answer:
|
|
127
|
+
return None
|
|
128
|
+
return [col.strip() for col in answer.split(",") if col.strip()]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _prompt_column_customization(config: ValidatorConfig) -> None:
|
|
132
|
+
"""Optional column-level customization, asked right after the
|
|
133
|
+
primary key - only meaningful for the single named table
|
|
134
|
+
(primary_key's same scope). Skipped entirely (leaving any existing
|
|
135
|
+
only_columns/ignore_columns/ignore_datatype_columns untouched) unless
|
|
136
|
+
the user opts in, so a user who never touches this gets identical
|
|
137
|
+
behavior to before this feature existed."""
|
|
138
|
+
customize = questionary.confirm(
|
|
139
|
+
"Customize column validation? (skip specific columns, compare "
|
|
140
|
+
"only specific columns, or ignore datatype mismatches for "
|
|
141
|
+
"specific columns)",
|
|
142
|
+
default=False,
|
|
143
|
+
).ask()
|
|
144
|
+
|
|
145
|
+
if not customize:
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
config.only_columns = _prompt_column_list(
|
|
149
|
+
"Compare ONLY these columns, comma-separated (leave blank to "
|
|
150
|
+
"compare every common column as usual):",
|
|
151
|
+
config.only_columns,
|
|
152
|
+
)
|
|
153
|
+
config.ignore_columns = _prompt_column_list(
|
|
154
|
+
"SKIP these columns entirely, comma-separated (leave blank to "
|
|
155
|
+
"skip none):",
|
|
156
|
+
config.ignore_columns,
|
|
157
|
+
) or []
|
|
158
|
+
config.ignore_datatype_columns = _prompt_column_list(
|
|
159
|
+
"Ignore DATATYPE mismatches only for these columns, "
|
|
160
|
+
"comma-separated - their other checks (nullable, statistics, "
|
|
161
|
+
"row values) still run (leave blank to skip none):",
|
|
162
|
+
config.ignore_datatype_columns,
|
|
163
|
+
) or []
|
|
164
|
+
|
|
165
|
+
|
|
120
166
|
def _write_env_file(values: Dict[str, str], env_path: Optional[Path] = None) -> None:
|
|
121
167
|
"""
|
|
122
168
|
Write secrets to env_path (default: ENV_PATH, resolved at call time)
|
|
@@ -394,8 +440,18 @@ def run_configure_wizard() -> None:
|
|
|
394
440
|
|
|
395
441
|
if source_table_named and config.target_table.table:
|
|
396
442
|
config.primary_key = _prompt_primary_key(config.primary_key)
|
|
443
|
+
# Column-level customization - same single-table scope as the
|
|
444
|
+
# primary key above (only_columns/ignore_columns/
|
|
445
|
+
# ignore_datatype_columns are only meaningful when there's one
|
|
446
|
+
# specific table to compare). Optional: a user who declines gets
|
|
447
|
+
# identical behavior to before this feature existed.
|
|
448
|
+
typer.echo("\n== Customize validation (optional) ==")
|
|
449
|
+
_prompt_column_customization(config)
|
|
397
450
|
else:
|
|
398
451
|
config.primary_key = None
|
|
452
|
+
config.only_columns = None
|
|
453
|
+
config.ignore_columns = []
|
|
454
|
+
config.ignore_datatype_columns = []
|
|
399
455
|
|
|
400
456
|
# ------------------------------------------------------------------
|
|
401
457
|
# 5. Validations to run
|
|
@@ -335,6 +335,7 @@ def test_databricks_source_type_prompts_for_source_table(tmp_path, monkeypatch):
|
|
|
335
335
|
"src_cat", "bronze", "customers", # source table
|
|
336
336
|
"tgt_cat", "silver", "customers", # target table
|
|
337
337
|
"", # primary key (left blank)
|
|
338
|
+
False, # customize validation? (declined)
|
|
338
339
|
[], # validations
|
|
339
340
|
])
|
|
340
341
|
|
|
@@ -359,12 +360,100 @@ def test_databricks_source_type_prompts_for_primary_key_when_both_tables_named(
|
|
|
359
360
|
"src_cat", "bronze", "customers",
|
|
360
361
|
"tgt_cat", "silver", "customers",
|
|
361
362
|
"id, region_id ", # primary key, comma-separated with stray spaces
|
|
363
|
+
False, # customize validation? (declined)
|
|
362
364
|
[],
|
|
363
365
|
])
|
|
364
366
|
|
|
365
367
|
assert config.primary_key == ["id", "region_id"]
|
|
366
368
|
|
|
367
369
|
|
|
370
|
+
def test_databricks_wizard_declining_customization_leaves_defaults_untouched(
|
|
371
|
+
tmp_path, monkeypatch
|
|
372
|
+
):
|
|
373
|
+
"""Answering No to the customize-validation gate must leave
|
|
374
|
+
only_columns/ignore_columns/ignore_datatype_columns at their defaults
|
|
375
|
+
- a user who never opts in gets identical behavior to before this
|
|
376
|
+
feature existed."""
|
|
377
|
+
config = _run_wizard_with_answers(tmp_path, monkeypatch, [
|
|
378
|
+
"Databricks catalog -> Databricks catalog",
|
|
379
|
+
"https://adb-1.databricks.net", "/sql/1.0/warehouses/x", "tok",
|
|
380
|
+
"src_cat", "bronze", "customers",
|
|
381
|
+
"tgt_cat", "silver", "customers",
|
|
382
|
+
"", # primary key (left blank)
|
|
383
|
+
False, # customize validation? (declined)
|
|
384
|
+
[],
|
|
385
|
+
])
|
|
386
|
+
|
|
387
|
+
assert config.only_columns is None
|
|
388
|
+
assert config.ignore_columns == []
|
|
389
|
+
assert config.ignore_datatype_columns == []
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def test_databricks_wizard_customize_populates_all_three_column_lists(
|
|
393
|
+
tmp_path, monkeypatch
|
|
394
|
+
):
|
|
395
|
+
"""Answering Yes to the customize-validation gate must ask for and
|
|
396
|
+
save all three column lists - only_columns (allowlist),
|
|
397
|
+
ignore_columns (denylist), ignore_datatype_columns."""
|
|
398
|
+
config = _run_wizard_with_answers(tmp_path, monkeypatch, [
|
|
399
|
+
"Databricks catalog -> Databricks catalog",
|
|
400
|
+
"https://adb-1.databricks.net", "/sql/1.0/warehouses/x", "tok",
|
|
401
|
+
"src_cat", "bronze", "customers",
|
|
402
|
+
"tgt_cat", "silver", "customers",
|
|
403
|
+
"id", # primary key
|
|
404
|
+
True, # customize validation? (accepted)
|
|
405
|
+
"id, name ", # only_columns, stray spaces
|
|
406
|
+
"updated_at", # ignore_columns
|
|
407
|
+
"legacy_flag, notes", # ignore_datatype_columns
|
|
408
|
+
[],
|
|
409
|
+
])
|
|
410
|
+
|
|
411
|
+
assert config.only_columns == ["id", "name"]
|
|
412
|
+
assert config.ignore_columns == ["updated_at"]
|
|
413
|
+
assert config.ignore_datatype_columns == ["legacy_flag", "notes"]
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def test_databricks_wizard_customize_all_three_left_blank(tmp_path, monkeypatch):
|
|
417
|
+
"""Opting into customization but leaving all three prompts blank must
|
|
418
|
+
resolve to only_columns=None, ignore_columns=[], ignore_datatype_columns=[] -
|
|
419
|
+
the same effective defaults as declining outright."""
|
|
420
|
+
config = _run_wizard_with_answers(tmp_path, monkeypatch, [
|
|
421
|
+
"Databricks catalog -> Databricks catalog",
|
|
422
|
+
"https://adb-1.databricks.net", "/sql/1.0/warehouses/x", "tok",
|
|
423
|
+
"src_cat", "bronze", "customers",
|
|
424
|
+
"tgt_cat", "silver", "customers",
|
|
425
|
+
"id",
|
|
426
|
+
True, # customize validation? (accepted)
|
|
427
|
+
"", # only_columns left blank
|
|
428
|
+
"", # ignore_columns left blank
|
|
429
|
+
"", # ignore_datatype_columns left blank
|
|
430
|
+
[],
|
|
431
|
+
])
|
|
432
|
+
|
|
433
|
+
assert config.only_columns is None
|
|
434
|
+
assert config.ignore_columns == []
|
|
435
|
+
assert config.ignore_datatype_columns == []
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def test_databricks_wizard_catalog_wide_sweep_skips_customization_prompt(
|
|
439
|
+
tmp_path, monkeypatch
|
|
440
|
+
):
|
|
441
|
+
"""Catalog-wide sweep (no specific table named) must skip the
|
|
442
|
+
customize-validation gate entirely, same scope rule as primary_key -
|
|
443
|
+
a single column list can't apply to many different tables."""
|
|
444
|
+
config = _run_wizard_with_answers(tmp_path, monkeypatch, [
|
|
445
|
+
"Databricks catalog -> Databricks catalog",
|
|
446
|
+
"https://adb-1.databricks.net", "/sql/1.0/warehouses/x", "tok",
|
|
447
|
+
"src_cat", "", "", # source: catalog only
|
|
448
|
+
"tgt_cat", "", "", # target: catalog only
|
|
449
|
+
[], # validations (no customize prompt in between)
|
|
450
|
+
])
|
|
451
|
+
|
|
452
|
+
assert config.only_columns is None
|
|
453
|
+
assert config.ignore_columns == []
|
|
454
|
+
assert config.ignore_datatype_columns == []
|
|
455
|
+
|
|
456
|
+
|
|
368
457
|
def test_databricks_wizard_skips_primary_key_prompt_for_catalog_wide_sweep(
|
|
369
458
|
tmp_path, monkeypatch
|
|
370
459
|
):
|
|
@@ -457,6 +546,7 @@ def test_azure_sql_prompts_for_primary_key_when_table_named(tmp_path, monkeypatc
|
|
|
457
546
|
"employees", # sql_source table
|
|
458
547
|
"tgt_cat", "dbo", "employees_sample", # target table
|
|
459
548
|
"EmployeeID", # primary key
|
|
549
|
+
False, # customize validation? (declined)
|
|
460
550
|
[], # validations
|
|
461
551
|
])
|
|
462
552
|
|
|
@@ -498,6 +588,7 @@ def test_azure_blob_prompts_for_primary_key_when_blob_path_named(tmp_path, monke
|
|
|
498
588
|
"validation/customers.csv", # blob_path (explicit)
|
|
499
589
|
"tgt_cat", "bronze", "customers", # target table
|
|
500
590
|
"id", # primary key
|
|
591
|
+
False, # customize validation? (declined)
|
|
501
592
|
[], # validations
|
|
502
593
|
])
|
|
503
594
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/azure_connector.py
RENAMED
|
File without changes
|
{table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/databricks_connector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/blob_discovery.py
RENAMED
|
File without changes
|
{table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/catalog_validator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/dependency_links.txt
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|