tablevalidator-databricks 0.1.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.
Files changed (21) hide show
  1. tablevalidator_databricks-0.1.2/PKG-INFO +116 -0
  2. tablevalidator_databricks-0.1.2/README.md +102 -0
  3. tablevalidator_databricks-0.1.2/pyproject.toml +50 -0
  4. tablevalidator_databricks-0.1.2/setup.cfg +4 -0
  5. tablevalidator_databricks-0.1.2/tablevalidator_databricks/__init__.py +15 -0
  6. tablevalidator_databricks-0.1.2/tablevalidator_databricks/cli/__init__.py +0 -0
  7. tablevalidator_databricks-0.1.2/tablevalidator_databricks/cli/main.py +101 -0
  8. tablevalidator_databricks-0.1.2/tablevalidator_databricks/generator/__init__.py +0 -0
  9. tablevalidator_databricks-0.1.2/tablevalidator_databricks/generator/generator.py +39 -0
  10. tablevalidator_databricks-0.1.2/tablevalidator_databricks/templates/widget_notebook.py.tmpl +327 -0
  11. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/PKG-INFO +116 -0
  12. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/SOURCES.txt +19 -0
  13. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/dependency_links.txt +1 -0
  14. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/entry_points.txt +2 -0
  15. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/requires.txt +7 -0
  16. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/scm_file_list.json +15 -0
  17. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/scm_version.json +8 -0
  18. tablevalidator_databricks-0.1.2/tablevalidator_databricks.egg-info/top_level.txt +1 -0
  19. tablevalidator_databricks-0.1.2/tests/test_cli.py +56 -0
  20. tablevalidator_databricks-0.1.2/tests/test_generated_notebook_execution.py +375 -0
  21. tablevalidator_databricks-0.1.2/tests/test_generator.py +91 -0
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: tablevalidator-databricks
3
+ Version: 0.1.2
4
+ Summary: Generates a widget-driven Databricks notebook UI on top of the table-validator package - no code required to run a comparison.
5
+ License: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: typer>=0.12
9
+ Requires-Dist: table-validator>=0.1.19
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=7.0; extra == "dev"
12
+ Requires-Dist: ruff>=0.4; extra == "dev"
13
+ Requires-Dist: black>=24.0; extra == "dev"
14
+
15
+ # tablevalidator-databricks
16
+
17
+ A widget-driven Databricks notebook UI for [`table-validator`](https://pypi.org/project/table-validator/)
18
+ - generates a notebook with `dbutils.widgets` for picking source/target
19
+ tables and validation checks, so you can run a comparison without writing
20
+ any Python.
21
+
22
+ This package contains **no validation logic of its own**. It only writes a
23
+ notebook file whose cells call directly into `table-validator`'s own
24
+ `validate_tables()` API - the exact same engine the CLI (`tablevalidator`)
25
+ and the notebook-native Python API already use.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install tablevalidator-databricks
31
+ ```
32
+
33
+ Installing this package also installs `table-validator` (a dependency), so
34
+ there's nothing else to install separately.
35
+
36
+ ## Usage
37
+
38
+ ```bash
39
+ tablevalidator-databricks init
40
+ ```
41
+
42
+ Writes `./TableValidator.py` - a ready-to-use Databricks notebook. Options:
43
+
44
+ ```bash
45
+ tablevalidator-databricks init --output MyValidation.py --mode full
46
+ ```
47
+
48
+ - `--mode basic` - only the check-group multiselect and table pickers.
49
+ - `--mode full` (default) - also shows optional filter widgets (only/
50
+ ignore columns, row filter, primary key).
51
+ - `--mode schema` - same widgets as `basic`; intended for a lightweight
52
+ schema-shape-only comparison (just deselect Column/Row in the checks
53
+ multiselect after opening the notebook).
54
+
55
+ Then, in your Databricks workspace: **Workspace -> Import**, format
56
+ "Source", and select the generated file. Databricks recognizes the
57
+ `# Databricks notebook source` header and `# COMMAND ----------` cell
58
+ markers and opens it as a real notebook.
59
+
60
+ ## What the generated notebook does
61
+
62
+ 1. Installs `table-validator` (`%pip install table-validator`).
63
+ 2. Queries Unity Catalog (`SHOW CATALOGS` / `SHOW SCHEMAS IN ...` /
64
+ `SHOW TABLES IN ...` via the notebook's own ambient Spark session) to
65
+ populate Source/Target Catalog, Schema, and Table dropdowns.
66
+ 3. Shows a "Validation Checks" multiselect (Catalog & Schema / Column /
67
+ Row - the three independently-selectable check groups the engine
68
+ actually supports) plus, in `full` mode, optional text widgets for
69
+ column filtering, a row filter, and a primary key.
70
+ 4. On run, reads every widget and calls
71
+ `validate_tables(source, target, enabled_validations=..., ...)`,
72
+ then prints a summary and displays the Table Validation sheet.
73
+
74
+ **Cascading dropdowns**: Databricks widgets don't auto-refresh when an
75
+ upstream selection changes. After changing Source/Target Catalog or
76
+ Schema, re-run the notebook's "Create / refresh widgets" cell once to
77
+ repopulate the dropdowns below it before running the rest of the notebook.
78
+ This is a Databricks widget limitation, not a bug in the generated
79
+ notebook. If you skip this and run validation anyway with a stale Schema/
80
+ Table selection, the notebook fails with a clear error telling you which
81
+ cell to re-run, rather than silently comparing the wrong table.
82
+
83
+ **Can't find a name in a dropdown?** Every Catalog/Schema/Table dropdown
84
+ has a matching "(manual override)" text widget next to it. Type the exact
85
+ name there and it's used instead of the dropdown - useful if something
86
+ isn't showing up (a permissions lag, sort order, anything). It's used
87
+ as-is, not checked against the live catalog listing. Leave every override
88
+ blank to just use the dropdowns as normal.
89
+
90
+ **Validate every table in a schema, not just one**: pick
91
+ "(all tables in schema)" as the Table dropdown (Source and/or Target
92
+ independently) to compare every identically-named table in that schema in
93
+ one run - the same schema-wide sweep `validate_tables()` itself supports.
94
+ A primary key can't be set in this mode (leave the Primary Key widget
95
+ blank). Comparing every schema in a catalog isn't supported yet - Schema
96
+ must be a specific choice, even when Table is left as "(all ... in ...)".
97
+
98
+ ## Why a separate package
99
+
100
+ `table-validator` stays focused on the actual comparison engine (CLI +
101
+ notebook API + report generation). This package is purely a Databricks-
102
+ specific UI layer on top of it - keeping the two independently versioned
103
+ and installable means CLI-only or code-only users never need Databricks-
104
+ specific tooling pulled in, and this package can add more Databricks UX
105
+ (e.g. richer widgets) without touching the core engine at all.
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ pip install -e ".[dev]"
111
+ pytest
112
+ ```
113
+
114
+ ## License
115
+
116
+ MIT - see the `table-validator` repository's [LICENSE](../table_validator/LICENSE).
@@ -0,0 +1,102 @@
1
+ # tablevalidator-databricks
2
+
3
+ A widget-driven Databricks notebook UI for [`table-validator`](https://pypi.org/project/table-validator/)
4
+ - generates a notebook with `dbutils.widgets` for picking source/target
5
+ tables and validation checks, so you can run a comparison without writing
6
+ any Python.
7
+
8
+ This package contains **no validation logic of its own**. It only writes a
9
+ notebook file whose cells call directly into `table-validator`'s own
10
+ `validate_tables()` API - the exact same engine the CLI (`tablevalidator`)
11
+ and the notebook-native Python API already use.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install tablevalidator-databricks
17
+ ```
18
+
19
+ Installing this package also installs `table-validator` (a dependency), so
20
+ there's nothing else to install separately.
21
+
22
+ ## Usage
23
+
24
+ ```bash
25
+ tablevalidator-databricks init
26
+ ```
27
+
28
+ Writes `./TableValidator.py` - a ready-to-use Databricks notebook. Options:
29
+
30
+ ```bash
31
+ tablevalidator-databricks init --output MyValidation.py --mode full
32
+ ```
33
+
34
+ - `--mode basic` - only the check-group multiselect and table pickers.
35
+ - `--mode full` (default) - also shows optional filter widgets (only/
36
+ ignore columns, row filter, primary key).
37
+ - `--mode schema` - same widgets as `basic`; intended for a lightweight
38
+ schema-shape-only comparison (just deselect Column/Row in the checks
39
+ multiselect after opening the notebook).
40
+
41
+ Then, in your Databricks workspace: **Workspace -> Import**, format
42
+ "Source", and select the generated file. Databricks recognizes the
43
+ `# Databricks notebook source` header and `# COMMAND ----------` cell
44
+ markers and opens it as a real notebook.
45
+
46
+ ## What the generated notebook does
47
+
48
+ 1. Installs `table-validator` (`%pip install table-validator`).
49
+ 2. Queries Unity Catalog (`SHOW CATALOGS` / `SHOW SCHEMAS IN ...` /
50
+ `SHOW TABLES IN ...` via the notebook's own ambient Spark session) to
51
+ populate Source/Target Catalog, Schema, and Table dropdowns.
52
+ 3. Shows a "Validation Checks" multiselect (Catalog & Schema / Column /
53
+ Row - the three independently-selectable check groups the engine
54
+ actually supports) plus, in `full` mode, optional text widgets for
55
+ column filtering, a row filter, and a primary key.
56
+ 4. On run, reads every widget and calls
57
+ `validate_tables(source, target, enabled_validations=..., ...)`,
58
+ then prints a summary and displays the Table Validation sheet.
59
+
60
+ **Cascading dropdowns**: Databricks widgets don't auto-refresh when an
61
+ upstream selection changes. After changing Source/Target Catalog or
62
+ Schema, re-run the notebook's "Create / refresh widgets" cell once to
63
+ repopulate the dropdowns below it before running the rest of the notebook.
64
+ This is a Databricks widget limitation, not a bug in the generated
65
+ notebook. If you skip this and run validation anyway with a stale Schema/
66
+ Table selection, the notebook fails with a clear error telling you which
67
+ cell to re-run, rather than silently comparing the wrong table.
68
+
69
+ **Can't find a name in a dropdown?** Every Catalog/Schema/Table dropdown
70
+ has a matching "(manual override)" text widget next to it. Type the exact
71
+ name there and it's used instead of the dropdown - useful if something
72
+ isn't showing up (a permissions lag, sort order, anything). It's used
73
+ as-is, not checked against the live catalog listing. Leave every override
74
+ blank to just use the dropdowns as normal.
75
+
76
+ **Validate every table in a schema, not just one**: pick
77
+ "(all tables in schema)" as the Table dropdown (Source and/or Target
78
+ independently) to compare every identically-named table in that schema in
79
+ one run - the same schema-wide sweep `validate_tables()` itself supports.
80
+ A primary key can't be set in this mode (leave the Primary Key widget
81
+ blank). Comparing every schema in a catalog isn't supported yet - Schema
82
+ must be a specific choice, even when Table is left as "(all ... in ...)".
83
+
84
+ ## Why a separate package
85
+
86
+ `table-validator` stays focused on the actual comparison engine (CLI +
87
+ notebook API + report generation). This package is purely a Databricks-
88
+ specific UI layer on top of it - keeping the two independently versioned
89
+ and installable means CLI-only or code-only users never need Databricks-
90
+ specific tooling pulled in, and this package can add more Databricks UX
91
+ (e.g. richer widgets) without touching the core engine at all.
92
+
93
+ ## Development
94
+
95
+ ```bash
96
+ pip install -e ".[dev]"
97
+ pytest
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT - see the `table-validator` repository's [LICENSE](../table_validator/LICENSE).
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "setuptools_scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tablevalidator-databricks"
7
+ dynamic = ["version"]
8
+ description = "Generates a widget-driven Databricks notebook UI on top of the table-validator package - no code required to run a comparison."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ dependencies = [
13
+ "typer>=0.12",
14
+ "table-validator>=0.1.19",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ dev = [
19
+ "pytest>=7.0",
20
+ "ruff>=0.4",
21
+ "black>=24.0",
22
+ ]
23
+
24
+ [project.scripts]
25
+ tablevalidator-databricks = "tablevalidator_databricks.cli.main:app"
26
+
27
+ [tool.setuptools.packages.find]
28
+ include = ["tablevalidator_databricks", "tablevalidator_databricks.*"]
29
+
30
+ [tool.setuptools.package-data]
31
+ tablevalidator_databricks = ["templates/*.tmpl"]
32
+
33
+ [tool.setuptools_scm]
34
+ root = ".."
35
+ # Distinct tag prefix ("databricks-vX.Y.Z") from table-validator's own
36
+ # "vX.Y.Z" tags (table_validator/pyproject.toml's tag_regex) - the two
37
+ # packages are versioned and released completely independently, and this
38
+ # package's own publish workflow only triggers on this tag pattern (see
39
+ # .github/workflows/publish-databricks.yml). Do not reuse table-validator's
40
+ # tag_regex here - a shared pattern would make both packages' publish
41
+ # workflows fire off the same tag.
42
+ #
43
+ # git_describe_command scopes `git describe` itself to only this package's
44
+ # tag pattern (via --match) - without this, `git describe` finds the
45
+ # repo's overall nearest tag (e.g. table-validator's own "v0.1.19") and
46
+ # setuptools_scm >=8 raises ValueError rather than silently falling back
47
+ # to fallback_version when that tag doesn't match tag_regex.
48
+ git_describe_command = "git describe --dirty --tags --long --match 'databricks-v*.*.*'"
49
+ tag_regex = "^databricks-v(?P<version>\\d+\\.\\d+\\.\\d+)$"
50
+ fallback_version = "0.0.0"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ """tablevalidator_databricks: generates a widget-driven Databricks notebook
2
+ UI on top of the table-validator package's validate_tables() API.
3
+
4
+ This package contains no validation logic of its own - it only writes a
5
+ notebook file whose cells call into table_validator's existing engine
6
+ (see tablevalidator_databricks/templates/widget_notebook.py.tmpl)."""
7
+
8
+ from importlib.metadata import PackageNotFoundError, version
9
+
10
+ try:
11
+ __version__ = version("tablevalidator-databricks")
12
+ except PackageNotFoundError:
13
+ __version__ = "0.0.0"
14
+
15
+ __all__ = ["__version__"]
@@ -0,0 +1,101 @@
1
+ """CLI entry point: `tablevalidator-databricks` console script."""
2
+
3
+ from pathlib import Path
4
+
5
+ import typer
6
+
7
+ from tablevalidator_databricks.generator.generator import VALID_MODES, generate_notebook
8
+
9
+ app = typer.Typer(
10
+ name="tablevalidator-databricks",
11
+ help="Generate a widget-driven Databricks notebook UI for table-validator.",
12
+ no_args_is_help=True,
13
+ )
14
+
15
+ DEFAULT_OUTPUT_PATH = Path("TableValidator.py")
16
+
17
+
18
+ @app.command()
19
+ def init(
20
+ output: Path = typer.Option(
21
+ DEFAULT_OUTPUT_PATH,
22
+ "--output",
23
+ help="Path to write the generated notebook to (default: ./TableValidator.py).",
24
+ ),
25
+ mode: str = typer.Option(
26
+ "full",
27
+ "--mode",
28
+ help=(
29
+ "basic: only the check-group multiselect and table pickers. "
30
+ "full (default): also shows optional filter widgets (only/ "
31
+ "ignore columns, row filter, primary key). "
32
+ "schema: pre-selects only the Catalog & Schema check group."
33
+ ),
34
+ ),
35
+ ) -> None:
36
+ """Generate a Databricks notebook with dbutils widgets for source/
37
+ target catalog.schema.table selection and validation checks - fill in
38
+ the widgets and run the notebook, no code to write.
39
+
40
+ Import the generated file into a Databricks workspace via
41
+ Workspace -> Import, with format set to "Source" (or "File" -> upload
42
+ directly, depending on your workspace UI version) - Databricks
43
+ recognizes the "# Databricks notebook source" header and cell
44
+ (# COMMAND ----------) markers and opens it as a real notebook, not a
45
+ plain text file.
46
+ """
47
+ if mode not in VALID_MODES:
48
+ typer.secho(
49
+ f"Invalid --mode {mode!r} - must be one of {', '.join(VALID_MODES)}.",
50
+ fg=typer.colors.RED,
51
+ )
52
+ raise typer.Exit(code=1)
53
+
54
+ generate_notebook(output, mode)
55
+
56
+ typer.echo(f"Generated notebook: {output.resolve()}")
57
+ typer.echo(
58
+ "Import it into Databricks (Workspace -> Import, format 'Source'), "
59
+ "fill in the widgets, and Run All."
60
+ )
61
+
62
+
63
+ @app.command()
64
+ def info() -> None:
65
+ """Show what this tool does and how to use the generated notebook."""
66
+ typer.echo(
67
+ "\n"
68
+ "tablevalidator-databricks - Databricks notebook UI for table-validator\n"
69
+ "------------------------------------------------------------------------\n"
70
+ "Generates a Databricks notebook with dbutils widgets (dynamic "
71
+ "catalog/schema/table dropdowns sourced from Unity Catalog, plus a "
72
+ "validation-checks multiselect) as a wrapper around the "
73
+ "table-validator package's validate_tables() API - no Python code "
74
+ "to write, no separate credentials to configure (the notebook "
75
+ "reuses its own ambient Spark session, same as validate_tables() "
76
+ "itself).\n"
77
+ "\n"
78
+ "Workflow:\n"
79
+ "\n"
80
+ " 1. tablevalidator-databricks init\n"
81
+ " Writes a ready-to-use notebook (./TableValidator.py by "
82
+ "default). Use --output to write elsewhere, --mode to pick basic/"
83
+ "full/schema (see 'tablevalidator-databricks init --help').\n"
84
+ "\n"
85
+ " 2. Import the generated file into Databricks\n"
86
+ " Workspace -> Import, format 'Source'.\n"
87
+ "\n"
88
+ " 3. Fill in the widgets and Run All\n"
89
+ " Pick Source/Target Catalog, Schema, Table, and which checks "
90
+ "to run, then run the notebook top to bottom. Re-run the "
91
+ "'Create / refresh widgets' cell after changing a Catalog/Schema "
92
+ "selection, to repopulate the dropdowns below it (a Databricks "
93
+ "widget limitation, not a bug). Can't find a name in a dropdown? "
94
+ "Each dropdown has a '(manual override)' text widget next to it - "
95
+ "type the exact name there instead.\n"
96
+ "\n"
97
+ "This package contains no validation logic of its own - every "
98
+ "generated notebook calls directly into table-validator's own "
99
+ "validate_tables() engine, so results are identical to calling it "
100
+ "yourself in a code cell.\n"
101
+ )
@@ -0,0 +1,39 @@
1
+ """
2
+ Renders the bundled widget_notebook.py.tmpl into a real Databricks
3
+ notebook file. No Jinja2 - the template has exactly two placeholders,
4
+ substituted via plain str.replace(), so a templating dependency isn't
5
+ worth adding for this.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import importlib.resources
11
+ from pathlib import Path
12
+
13
+ VALID_MODES = ("basic", "full", "schema")
14
+
15
+
16
+ def generate_notebook(output: Path, mode: str) -> None:
17
+ """Write a widget-driven Databricks notebook to `output`.
18
+
19
+ mode controls which optional widgets/pre-selected checks the notebook
20
+ starts with - see tablevalidator_databricks/cli/main.py's `init`
21
+ command docstring for what each mode means. The underlying comparison
22
+ logic is identical regardless of mode; only the widgets shown differ,
23
+ so all three modes render from the same template file rather than
24
+ three separate ones.
25
+ """
26
+ if mode not in VALID_MODES:
27
+ raise ValueError(f"mode must be one of {VALID_MODES}, got {mode!r}")
28
+
29
+ template = (
30
+ importlib.resources.files("tablevalidator_databricks.templates")
31
+ .joinpath("widget_notebook.py.tmpl")
32
+ .read_text(encoding="utf-8")
33
+ )
34
+ rendered = template.replace("{{MODE}}", mode).replace(
35
+ "{{SHOW_OPTIONAL_WIDGETS}}", "True" if mode == "full" else "False",
36
+ )
37
+
38
+ output.parent.mkdir(parents=True, exist_ok=True)
39
+ output.write_text(rendered, encoding="utf-8")