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.
Files changed (47) hide show
  1. {table_validator-0.1.7/table_validator.egg-info → table_validator-0.1.8}/PKG-INFO +1 -1
  2. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/wizard.py +56 -0
  3. {table_validator-0.1.7 → table_validator-0.1.8/table_validator.egg-info}/PKG-INFO +1 -1
  4. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/scm_version.json +2 -2
  5. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_wizard.py +91 -0
  6. {table_validator-0.1.7 → table_validator-0.1.8}/LICENSE +0 -0
  7. {table_validator-0.1.7 → table_validator-0.1.8}/README.md +0 -0
  8. {table_validator-0.1.7 → table_validator-0.1.8}/pyproject.toml +0 -0
  9. {table_validator-0.1.7 → table_validator-0.1.8}/setup.cfg +0 -0
  10. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/__init__.py +0 -0
  11. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/__init__.py +0 -0
  12. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/azure_auth.py +0 -0
  13. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/auth/databricks_auth.py +0 -0
  14. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/__init__.py +0 -0
  15. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/main.py +0 -0
  16. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/partition_prompt.py +0 -0
  17. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/cli/summary_table.py +0 -0
  18. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/__init__.py +0 -0
  19. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/manager.py +0 -0
  20. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/config/schema.py +0 -0
  21. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/__init__.py +0 -0
  22. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/azure_connector.py +0 -0
  23. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/connectors/databricks_connector.py +0 -0
  24. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/engine/__init__.py +0 -0
  25. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/engine/comparison_engine.py +0 -0
  26. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/models.py +0 -0
  27. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/reports/__init__.py +0 -0
  28. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/reports/excel_report.py +0 -0
  29. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/__init__.py +0 -0
  30. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/blob_discovery.py +0 -0
  31. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/catalog_validator.py +0 -0
  32. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator/validators/row_validator.py +0 -0
  33. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/SOURCES.txt +0 -0
  34. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/dependency_links.txt +0 -0
  35. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/entry_points.txt +0 -0
  36. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/requires.txt +0 -0
  37. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/scm_file_list.json +0 -0
  38. {table_validator-0.1.7 → table_validator-0.1.8}/table_validator.egg-info/top_level.txt +0 -0
  39. {table_validator-0.1.7 → table_validator-0.1.8}/tests/__init__.py +0 -0
  40. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_blob_discovery.py +0 -0
  41. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_catalog_validator.py +0 -0
  42. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_cli.py +0 -0
  43. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_databricks_connector.py +0 -0
  44. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_excel_report.py +0 -0
  45. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_partition_prompt.py +0 -0
  46. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_report_command.py +0 -0
  47. {table_validator-0.1.7 → table_validator-0.1.8}/tests/test_row_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table-validator
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: CLI tool for validating data migrations between Azure (Blob Storage / SQL Database) and Databricks Delta Lake catalogs
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table-validator
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: CLI tool for validating data migrations between Azure (Blob Storage / SQL Database) and Databricks Delta Lake catalogs
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.1.7",
2
+ "tag": "0.1.8",
3
3
  "distance": 0,
4
- "node": "g989192ab5b13d03c174b2c33883a8569f5437e2a",
4
+ "node": "g5004811d73585508b803dc003e03bd1da62ede4a",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-09-02"
@@ -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