databricks-schema 0.7.0__tar.gz → 0.10.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.
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/.gitignore +0 -1
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/CLAUDE.md +19 -9
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/PKG-INFO +219 -91
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/README.md +214 -88
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/__init__.py +18 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/cli.py +353 -86
- databricks_schema-0.10.0/databricks_schema/dbml_io.py +433 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/diff.py +92 -43
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/extractor.py +58 -3
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/models.py +2 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/sql_gen.py +45 -1
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/yaml_io.py +42 -1
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/pyproject.toml +9 -3
- databricks_schema-0.10.0/skills/databricks-schema-cli/SKILL.md +218 -0
- databricks_schema-0.10.0/tests/test_cli.py +527 -0
- databricks_schema-0.10.0/tests/test_dbml_io.py +316 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_diff.py +122 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_extractor.py +116 -2
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_sql_gen.py +50 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_yaml_io.py +23 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/uv.lock +41 -9
- databricks_schema-0.7.0/.claude/skills/databricks-schema-cli/SKILL.md +0 -203
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/.github/workflows/ci.yml +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/.github/workflows/release.yml +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/.python-version +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/LICENSE +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/databricks_schema/validate.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/examples/01_extract_schema.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/examples/02_save_load_yaml.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/examples/03_diff_schemas.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/examples/04_generate_sql.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/__init__.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_models.py +0 -0
- {databricks_schema-0.7.0 → databricks_schema-0.10.0}/tests/test_validate.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Project
|
|
4
4
|
|
|
5
|
-
`databricks-schema` — CLI + Python library that extracts, diffs, and generates SQL for Databricks Unity Catalog schemas stored as YAML or JSON files (one file per schema). Pydantic v2 models serve as the intermediate representation for future bidirectional sync.
|
|
5
|
+
`databricks-schema` — CLI + Python library that extracts, diffs, and generates SQL for Databricks Unity Catalog schemas stored as YAML or JSON files (one file per schema) or DBML (one file per catalog). Pydantic v2 models serve as the intermediate representation for future bidirectional sync.
|
|
6
6
|
|
|
7
7
|
## Key commands
|
|
8
8
|
|
|
@@ -18,9 +18,10 @@ uv run databricks-schema --help
|
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
databricks_schema/
|
|
21
|
-
models.py # Pydantic v2 models: Catalog, Schema, Table, Column, PrimaryKey, ForeignKey
|
|
21
|
+
models.py # Pydantic v2 models: Catalog, Schema, Table, Column, PrimaryKey, ForeignKey (Schema/Table carry grants)
|
|
22
22
|
extractor.py # CatalogExtractor — wraps databricks-sdk
|
|
23
|
-
yaml_io.py # schema/catalog to/from YAML and JSON; _strip_empty removes None + empty collections
|
|
23
|
+
yaml_io.py # schema/catalog to/from YAML and JSON; _strip_empty removes None + empty collections; load_schema_dir (all formats)
|
|
24
|
+
dbml_io.py # schema/catalog to/from DBML; own writer, PyDBML grammar for parsing
|
|
24
25
|
diff.py # diff_schemas / diff_catalogs / diff_catalog_with_dir / diff_schema_dirs; FieldChange, ColumnDiff, TableDiff, SchemaDiff, CatalogDiff
|
|
25
26
|
sql_gen.py # schema_diff_to_sql — pure SQL generation from SchemaDiff; no SDK/IO
|
|
26
27
|
cli.py # argparse CLI: extract, diff, generate-sql, validate, diff-files, list-catalogs, list-schemas
|
|
@@ -29,15 +30,17 @@ tests/
|
|
|
29
30
|
test_models.py
|
|
30
31
|
test_extractor.py # all SDK calls mocked with MagicMock
|
|
31
32
|
test_yaml_io.py
|
|
33
|
+
test_dbml_io.py
|
|
32
34
|
test_diff.py # pure model comparison, no SDK calls
|
|
33
35
|
test_sql_gen.py # pure SQL generation tests, no SDK calls
|
|
34
36
|
test_validate.py
|
|
35
|
-
|
|
37
|
+
skills/databricks-schema-cli/SKILL.md # Agent Skill: teaches an AI agent to drive the CLI
|
|
36
38
|
```
|
|
37
39
|
|
|
38
40
|
## Conventions
|
|
39
41
|
|
|
40
42
|
- Package manager: `uv`; do not use `pip` directly
|
|
43
|
+
- Version bumps: use `uv version --bump <major|minor|patch>` (updates `pyproject.toml` and `uv.lock` together) — do not hand-edit the version string
|
|
41
44
|
- Ruff: select E, W, F, I, UP; line-length 100; target py311
|
|
42
45
|
- Use `X | None` not `Optional[X]`; use `datetime.UTC` not `timezone.utc`
|
|
43
46
|
- `from __future__ import annotations` in every module
|
|
@@ -48,20 +51,27 @@ tests/
|
|
|
48
51
|
- Column order in YAML = SDK position (None → 9999)
|
|
49
52
|
- `_strip_empty`: removes `None` and empty `dict`/`list`; preserves `False`, `0`, empty strings
|
|
50
53
|
- `yaml_io.py` has parallel YAML and JSON functions (`schema_to_yaml`/`schema_to_json`, etc.)
|
|
51
|
-
- `diff_catalog_with_dir`
|
|
54
|
+
- `diff_catalog_with_dir` / `diff_schema_dirs` / `load_schema_dir` take `fmt: SchemaFormat` (`"yaml" | "json" | "dbml"`, default `"yaml"`)
|
|
55
|
+
- DBML is one document per catalog (`extract -f dbml -o DIR` writes `DIR/<catalog>.dbml`): Catalog → `Project`, Schema → `TableGroup` (always emitted), PK → `indexes { (...) [pk] }`, FK → `Ref`
|
|
56
|
+
- DBML has no key/value metadata: tags/grants/owner/table_type/storage_location are trailing `@key: value` lines in notes (`@tags`/`@grants` = JSON objects); writer output must round-trip exactly and stay parseable by `@dbml/core`
|
|
57
|
+
- PyDBML is optional (`databricks-schema[dbml]` extra; also in the `dev` group): `dbml_io` imports it in a top-level `try/except ImportError` setting `PYDBML_AVAILABLE`; writing DBML must never need it, readers raise `DbmlDependencyError` (CLI exits 2)
|
|
58
|
+
- `dbml_io` parses via PyDBML's grammar (`pydbml.definitions`) but resolves refs itself, so refs to tables outside the file are kept; never build a PyDBML `Database` (it rejects such refs and reflows note text) and never use PyDBML's renderer (it leaves complex types unquoted)
|
|
59
|
+
- For DBML directories, `--schema` filters match schema names (YAML/JSON match file stems)
|
|
52
60
|
- CLI: catalog is a required positional argument (not a flag)
|
|
53
|
-
- `extract` `--format`/`-f` selects output format (`yaml` default, `json` opt-in); dest is `fmt`
|
|
54
|
-
- `diff` auto-detects format from files present in the directory; exits 2 on mixed
|
|
61
|
+
- `extract` `--format`/`-f` selects output format (`yaml` default, `json`/`dbml` opt-in); dest is `fmt`
|
|
62
|
+
- `diff` auto-detects format from files present in the directory; exits 2 on mixed formats
|
|
55
63
|
- `diff`'s second positional arg is a directory if one exists at that path, else a second catalog name (`diff_catalogs`); first `catalog` arg is always the live side
|
|
56
64
|
- `TableType` is re-exported from `databricks.sdk.service.catalog` — do not redefine it
|
|
57
65
|
- `--include-metadata` flag (on `extract`, `diff`, `generate-sql`, `diff-files`) adds `owner` to output/comparison; `extract` additionally includes `storage_location` in its output (not compared by `diff`/`generate-sql`/`diff-files`); excluded by default
|
|
58
66
|
- `--include-tags` flag (on `extract`, `diff`, `generate-sql`) enables Unity Catalog tag lookups; excluded by default
|
|
67
|
+
- `--include-grants` flag (on `extract`, `diff`, `generate-sql`, `diff-files`) adds `grants: dict[str, list[str]]` (principal → sorted privileges) on `Schema`/`Table` via `grants.list()` — direct grants only, never inherited/effective ones; diff functions take `include_grants` and ignore grants otherwise; a grants `FieldChange` holds only differing principals
|
|
68
|
+
- `generate-sql` emits `GRANT` for stored-not-live privileges and `REVOKE` for live-not-stored; `REVOKE` is destructive and follows `--allow-drop`
|
|
59
69
|
- `--quiet`/`-q` flag (on `extract`, `diff`, `generate-sql`, `diff-files`) raises the log level to suppress progress messages; errors always print
|
|
60
70
|
- `diff` command exits 0 (no changes) or 1 (differences found) — useful in CI
|
|
61
71
|
- Diff result types are dataclasses (not Pydantic); comparison functions are pure (no SDK calls)
|
|
62
|
-
- `generate-sql` auto-detects format from files; exits 2 on mixed
|
|
72
|
+
- `generate-sql` auto-detects format from files; exits 2 on mixed formats or empty directory; invalid DBML exits 2
|
|
63
73
|
- `generate-sql` destructive statements commented out by default; `--allow-drop` emits real DROPs
|
|
64
74
|
- `sql_gen.py` is pure (no SDK, no I/O); diff direction: `FieldChange.old` = stored (target), `.new` = live
|
|
65
75
|
- FK refs in SQL use same catalog as the source table (`ref_schema` + `ref_table` from model)
|
|
66
76
|
- Unsupported field changes (`table_type`) emit `-- TODO: unsupported change: …` comments
|
|
67
|
-
- When CLI commands, flags, or output shape change, update
|
|
77
|
+
- When CLI commands, flags, or output shape change, update `skills/databricks-schema-cli/SKILL.md` to match
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: databricks-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Databricks Unity Catalog schema extractor
|
|
5
5
|
Project-URL: Homepage, https://github.com/frizzleqq/databricks-schema
|
|
6
6
|
Project-URL: Repository, https://github.com/frizzleqq/databricks-schema
|
|
@@ -18,14 +18,16 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
|
-
Requires-Dist: databricks-sdk>=0.
|
|
21
|
+
Requires-Dist: databricks-sdk>=0.121.0
|
|
22
22
|
Requires-Dist: pydantic>=2.0
|
|
23
23
|
Requires-Dist: pyyaml>=6.0
|
|
24
|
+
Provides-Extra: dbml
|
|
25
|
+
Requires-Dist: pydbml<2,>=1.2.1; extra == 'dbml'
|
|
24
26
|
Description-Content-Type: text/markdown
|
|
25
27
|
|
|
26
28
|
# databricks-schema
|
|
27
29
|
|
|
28
|
-
A CLI tool and Python library that uses the Databricks SDK to extract and diff Unity Catalog schemas as YAML files. It can also generate Databricks Spark SQL to apply schema changes across catalogs.
|
|
30
|
+
A CLI tool and Python library that uses the Databricks SDK to extract and diff Unity Catalog schemas as YAML, JSON or [DBML](https://dbml.dbdiagram.io/docs/) files. It can also generate Databricks Spark SQL to apply schema changes across catalogs.
|
|
29
31
|
|
|
30
32
|
## Getting Started
|
|
31
33
|
|
|
@@ -53,23 +55,94 @@ databricks-schema diff test_catalog ./schemas/
|
|
|
53
55
|
databricks-schema generate-sql test_catalog ./schemas/ --output-dir ./migrations/
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
## Databricks Authentication
|
|
59
|
+
|
|
60
|
+
The tool uses the [Databricks SDK](https://github.com/databricks/databricks-sdk-py) for auth. Configure it via environment variables:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
export DATABRICKS_HOST=https://<databricks-url>
|
|
64
|
+
export DATABRICKS_TOKEN=<your-personal-access-token>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or use a [Databricks CLI profile](https://docs.databricks.com/dev-tools/cli/profiles.html) (`~/.databrickscfg`) — the SDK will pick it up automatically.
|
|
68
|
+
|
|
69
|
+
You can also pass credentials directly as flags using `--host` / `--token` below.
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
Requires Python 3.11+ and [uv](https://github.com/astral-sh/uv).
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/frizzleqq/databricks-schema
|
|
77
|
+
cd databricks-schema
|
|
78
|
+
uv sync --all-groups # includes pytest and ruff
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Run tests
|
|
83
|
+
uv run pytest
|
|
84
|
+
|
|
85
|
+
# Lint
|
|
86
|
+
uv run ruff check databricks_schema/ tests/
|
|
87
|
+
|
|
88
|
+
# Format
|
|
89
|
+
uv run ruff format databricks_schema/ tests/
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Agent Skill
|
|
93
|
+
|
|
94
|
+
This repo ships an [Agent Skill](https://code.claude.com/docs/en/skills) at
|
|
95
|
+
[`skills/databricks-schema-cli/SKILL.md`](skills/databricks-schema-cli/SKILL.md)
|
|
96
|
+
that teaches an AI coding agent (e.g. Claude Code) how to use the `databricks-schema` CLI to
|
|
97
|
+
explore, snapshot, diff, and generate migration SQL for a live Unity Catalog. Copy the skill into
|
|
98
|
+
your own project and it can use the CLI directly instead of writing ad-hoc Databricks SDK calls
|
|
99
|
+
or queries.
|
|
100
|
+
|
|
101
|
+
The skill assumes the `databricks-schema` command is on `PATH`. Install it as a standalone tool
|
|
102
|
+
with [uv](https://github.com/astral-sh/uv):
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv tool install databricks-schema
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
To use the skill in your own project without cloning this repo, download it directly into your
|
|
109
|
+
project's `.claude/skills/`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
mkdir -p .claude/skills/databricks-schema-cli
|
|
113
|
+
curl -o .claude/skills/databricks-schema-cli/SKILL.md \
|
|
114
|
+
https://raw.githubusercontent.com/frizzleqq/databricks-schema/main/skills/databricks-schema-cli/SKILL.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For agentic harnesses other than Claude Code that look under `.agents/skills/` instead:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
mkdir -p .agents/skills/databricks-schema-cli
|
|
121
|
+
curl -o .agents/skills/databricks-schema-cli/SKILL.md \
|
|
122
|
+
https://raw.githubusercontent.com/frizzleqq/databricks-schema/main/skills/databricks-schema-cli/SKILL.md
|
|
123
|
+
```
|
|
57
124
|
|
|
58
125
|
## Output Format
|
|
59
126
|
|
|
60
|
-
Each schema is written to `{output-dir}/{schema-name}.yaml
|
|
127
|
+
Each schema is written to `{output-dir}/{schema-name}.yaml` if `--output-dir` is specified. Fields with no value (null comments, empty tag dicts, empty FK lists) are omitted. Use `--format json` to write `.json` files with the same structure.
|
|
61
128
|
|
|
62
129
|
```yaml
|
|
63
130
|
name: main
|
|
64
131
|
comment: Main production schema
|
|
65
132
|
tags:
|
|
66
133
|
env: prod
|
|
134
|
+
grants:
|
|
135
|
+
analysts:
|
|
136
|
+
- USE_SCHEMA
|
|
67
137
|
tables:
|
|
68
138
|
- name: users
|
|
69
139
|
table_type: MANAGED
|
|
70
140
|
comment: User accounts
|
|
71
141
|
tags:
|
|
72
142
|
domain: identity
|
|
143
|
+
grants:
|
|
144
|
+
analysts:
|
|
145
|
+
- SELECT
|
|
73
146
|
columns:
|
|
74
147
|
- name: id
|
|
75
148
|
data_type: bigint
|
|
@@ -93,74 +166,74 @@ tables:
|
|
|
93
166
|
- id
|
|
94
167
|
```
|
|
95
168
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```yaml
|
|
99
|
-
name: prod_catalog
|
|
100
|
-
schemas:
|
|
101
|
-
- name: main
|
|
102
|
-
comment: Main production schema
|
|
103
|
-
tags:
|
|
104
|
-
env: prod
|
|
105
|
-
tables: [...]
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Authentication
|
|
169
|
+
### DBML
|
|
109
170
|
|
|
110
|
-
|
|
171
|
+
Writing DBML works out of the box; reading it back (`diff`, `generate-sql`, `validate`, `diff-files`, `catalog_from_dbml`) needs the optional `dbml` extra, which installs [PyDBML](https://github.com/Vanderhoof/PyDBML):
|
|
111
172
|
|
|
112
173
|
```bash
|
|
113
|
-
|
|
114
|
-
|
|
174
|
+
pip install 'databricks-schema[dbml]'
|
|
175
|
+
uv tool install 'databricks-schema[dbml]'
|
|
115
176
|
```
|
|
116
177
|
|
|
117
|
-
|
|
178
|
+
Without it, those commands exit `2` with a message saying how to install it.
|
|
118
179
|
|
|
119
|
-
|
|
180
|
+
Use `--format dbml` to write the catalog as a single [DBML](https://dbml.dbdiagram.io/docs/) document — `{output-dir}/{catalog}.dbml` with `--output-dir`, or stdout without. Unlike YAML/JSON, DBML is one file per catalog, so that foreign keys between schemas resolve within the file. Paste it into [dbdiagram.io](https://dbdiagram.io) for an ER diagram, or point `diff`, `generate-sql`, `validate` and `diff-files` at the directory just like a YAML/JSON one.
|
|
120
181
|
|
|
121
|
-
|
|
182
|
+
```dbml
|
|
183
|
+
Project "prod_catalog" {
|
|
184
|
+
database_type: 'Databricks'
|
|
185
|
+
}
|
|
122
186
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
explore, snapshot, diff, and generate migration SQL for a live Unity Catalog. Point an agent at
|
|
127
|
-
this repo (or copy the skill into your own project) and it can use the CLI directly instead of
|
|
128
|
-
writing ad-hoc Databricks SDK calls.
|
|
187
|
+
TableGroup "main" [note: 'Main production schema'] {
|
|
188
|
+
"main"."users"
|
|
189
|
+
}
|
|
129
190
|
|
|
130
|
-
|
|
131
|
-
|
|
191
|
+
Table "main"."users" {
|
|
192
|
+
"id" bigint [not null, note: 'Primary key']
|
|
193
|
+
"email" string
|
|
194
|
+
"org_id" bigint
|
|
195
|
+
"settings" "struct<theme:string,beta:boolean>"
|
|
132
196
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
197
|
+
indexes {
|
|
198
|
+
("id") [pk, name: 'pk_users']
|
|
199
|
+
}
|
|
136
200
|
|
|
137
|
-
|
|
201
|
+
Note: '''User accounts
|
|
138
202
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
203
|
+
@table_type: MANAGED
|
|
204
|
+
@tags: {"domain": "identity"}'''
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
Ref "fk_org": "main"."users"."org_id" > "orgs"."organizations"."id"
|
|
143
208
|
```
|
|
144
209
|
|
|
145
|
-
|
|
210
|
+
How the model maps to DBML:
|
|
146
211
|
|
|
147
|
-
|
|
212
|
+
| Model | DBML |
|
|
213
|
+
|---|---|
|
|
214
|
+
| Catalog | `Project` (comment in its `Note`) |
|
|
215
|
+
| Schema | `TableGroup` named after the schema (comment in its `note`); written for every schema, so empty schemas survive |
|
|
216
|
+
| Table / column comment | `Note` / `note:` |
|
|
217
|
+
| `nullable: false` | `not null` |
|
|
218
|
+
| Primary key | `indexes { (...) [pk, name: '...'] }` |
|
|
219
|
+
| Foreign key | `Ref "<name>": ... > ...` |
|
|
220
|
+
| Complex types (`struct<...>`, `map<...>`) | double-quoted type |
|
|
221
|
+
| `tags`, `grants`, `owner`, `table_type`, `storage_location` | trailing `@key: value` lines in the note (`@tags` and `@grants` are JSON objects) |
|
|
148
222
|
|
|
149
|
-
|
|
150
|
-
git clone https://github.com/frizzleqq/databricks-schema
|
|
151
|
-
cd databricks-schema
|
|
152
|
-
uv sync --all-groups # includes pytest and ruff
|
|
153
|
-
```
|
|
223
|
+
Everything round-trips: reading a written file gives back exactly the extracted model. Hand-written DBML (e.g. exported from dbdiagram) is accepted too — tables without a schema land in `public`, column `pk` and inline `ref:` settings are understood, and constructs with no Unity Catalog equivalent (enums, sticky notes, other indexes, defaults, many-to-many refs, TableGroups that don't match a schema) are ignored. A directory may hold several `.dbml` files, but each schema may be defined in only one of them.
|
|
154
224
|
|
|
155
|
-
|
|
156
|
-
# Run tests
|
|
157
|
-
uv run pytest
|
|
225
|
+
### Catalog document
|
|
158
226
|
|
|
159
|
-
|
|
160
|
-
uv run ruff check databricks_schema/ tests/
|
|
227
|
+
Without `--output-dir`, `extract` prints a single `Catalog` document to stdout instead — the same schema shape nested under a `schemas` list, with the catalog name as a top-level field:
|
|
161
228
|
|
|
162
|
-
|
|
163
|
-
|
|
229
|
+
```yaml
|
|
230
|
+
name: prod_catalog
|
|
231
|
+
schemas:
|
|
232
|
+
- name: main
|
|
233
|
+
comment: Main production schema
|
|
234
|
+
tags:
|
|
235
|
+
env: prod
|
|
236
|
+
tables: [...]
|
|
164
237
|
```
|
|
165
238
|
|
|
166
239
|
## CLI Usage
|
|
@@ -169,9 +242,27 @@ uv run ruff format databricks_schema/ tests/
|
|
|
169
242
|
databricks-schema [OPTIONS] COMMAND [ARGS]...
|
|
170
243
|
```
|
|
171
244
|
|
|
172
|
-
`extract`, `diff`, `generate-sql`, and `diff-files` print progress messages (e.g. `Extracting
|
|
173
|
-
|
|
174
|
-
|
|
245
|
+
`extract`, `diff`, `generate-sql`, and `diff-files` print progress messages (e.g. `Extracting catalog 'X'...`) to stderr as they run. Pass `--quiet` / `-q` to suppress them;
|
|
246
|
+
results and errors are unaffected.
|
|
247
|
+
|
|
248
|
+
### `list-catalogs`
|
|
249
|
+
|
|
250
|
+
List all accessible catalogs:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
databricks-schema list-catalogs
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### `list-schemas`
|
|
257
|
+
|
|
258
|
+
List schemas in a catalog:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
databricks-schema list-schemas <catalog>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Both print one name per line by default. Pass `--format json` / `-f json` (or `--format yaml`) to
|
|
265
|
+
get the names as a JSON array or YAML list instead.
|
|
175
266
|
|
|
176
267
|
### `extract`
|
|
177
268
|
|
|
@@ -181,7 +272,11 @@ Extract all schemas from a catalog to YAML files:
|
|
|
181
272
|
databricks-schema extract <catalog> --output-dir ./schemas/
|
|
182
273
|
```
|
|
183
274
|
|
|
184
|
-
|
|
275
|
+
Print to stdout instead of writing files (no `--output-dir`) — the catalog and its schemas are printed as a single `Catalog` document (`name` + `schemas: [...]`):
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
databricks-schema extract <catalog>
|
|
279
|
+
```
|
|
185
280
|
|
|
186
281
|
Extract specific schemas only:
|
|
187
282
|
|
|
@@ -196,16 +291,16 @@ databricks-schema extract <catalog>.<schema>
|
|
|
196
291
|
databricks-schema extract <catalog>.<schema>.<table>
|
|
197
292
|
```
|
|
198
293
|
|
|
199
|
-
|
|
294
|
+
Include Unity Catalog tags in the output (extra API calls per entity; excluded by default):
|
|
200
295
|
|
|
201
296
|
```bash
|
|
202
|
-
databricks-schema extract <catalog> --
|
|
297
|
+
databricks-schema extract <catalog> --output-dir ./schemas/ --include-tags
|
|
203
298
|
```
|
|
204
299
|
|
|
205
|
-
Include
|
|
300
|
+
Include grants (principal → privileges) on schemas and tables. Only grants made directly on each object are extracted — privileges inherited from a parent catalog or schema are left out, so they don't show up repeatedly on every child (one extra API call per schema/table; excluded by default):
|
|
206
301
|
|
|
207
302
|
```bash
|
|
208
|
-
databricks-schema extract <catalog> --output-dir ./schemas/ --include-
|
|
303
|
+
databricks-schema extract <catalog> --output-dir ./schemas/ --include-grants
|
|
209
304
|
```
|
|
210
305
|
|
|
211
306
|
Include additional metadata (`owner`, `storage_location`) in the output:
|
|
@@ -214,7 +309,13 @@ Include additional metadata (`owner`, `storage_location`) in the output:
|
|
|
214
309
|
databricks-schema extract <catalog> --output-dir ./schemas/ --include-metadata
|
|
215
310
|
```
|
|
216
311
|
|
|
217
|
-
|
|
312
|
+
Write a single DBML file (`./schemas/<catalog>.dbml`) instead — see [DBML](#dbml):
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
databricks-schema extract <catalog> --output-dir ./schemas/ --format dbml
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Control the number of parallel workers (default: 4), useful for large schemas with many tags:
|
|
218
319
|
|
|
219
320
|
```bash
|
|
220
321
|
databricks-schema extract <catalog> --output-dir ./schemas/ --workers 8
|
|
@@ -222,13 +323,27 @@ databricks-schema extract <catalog> --output-dir ./schemas/ --workers 8
|
|
|
222
323
|
|
|
223
324
|
### `diff`
|
|
224
325
|
|
|
225
|
-
Compare the live catalog against previously extracted schema files (format auto-detected from the directory — YAML or
|
|
326
|
+
Compare the live catalog against previously extracted schema files (format auto-detected from the directory — YAML, JSON or DBML, not mixed):
|
|
226
327
|
|
|
227
328
|
```bash
|
|
228
329
|
databricks-schema diff <catalog> ./schemas/
|
|
229
330
|
```
|
|
230
331
|
|
|
231
|
-
|
|
332
|
+
Exits with code `0` if no differences are found, `1` if there are — making it suitable for CI pipelines. Output example:
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
~ Schema: main [MODIFIED]
|
|
336
|
+
~ Table: users [MODIFIED]
|
|
337
|
+
~ Column: score [MODIFIED]
|
|
338
|
+
data_type: 'int' -> 'double'
|
|
339
|
+
+ Column: phone [ADDED]
|
|
340
|
+
+ Table: events [ADDED]
|
|
341
|
+
- Schema: legacy [REMOVED]
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Markers: `+` added in catalog, `-` removed from catalog, `~` modified.
|
|
345
|
+
|
|
346
|
+
Or compare two live catalogs directly, e.g. dev against prod. The second argument is treated as a directory if one exists at that path, otherwise as a catalog name:
|
|
232
347
|
|
|
233
348
|
```bash
|
|
234
349
|
databricks-schema diff dev_catalog prod_catalog
|
|
@@ -252,23 +367,22 @@ Include `owner` in the comparison (excluded by default):
|
|
|
252
367
|
databricks-schema diff <catalog> ./schemas/ --include-metadata
|
|
253
368
|
```
|
|
254
369
|
|
|
255
|
-
|
|
370
|
+
Include direct grants in the comparison (excluded by default; without it, grants in the files are ignored):
|
|
256
371
|
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
~ Table: users [MODIFIED]
|
|
260
|
-
~ Column: score [MODIFIED]
|
|
261
|
-
data_type: 'int' -> 'double'
|
|
262
|
-
+ Column: phone [ADDED]
|
|
263
|
-
+ Table: events [ADDED]
|
|
264
|
-
- Schema: legacy [REMOVED]
|
|
372
|
+
```bash
|
|
373
|
+
databricks-schema diff <catalog> ./schemas/ --include-grants
|
|
265
374
|
```
|
|
266
375
|
|
|
267
|
-
|
|
376
|
+
Get the same comparison as structured JSON or YAML instead of the `+`/`-`/`~` tree (exit codes unchanged) — useful for scripts or agents:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
databricks-schema diff <catalog> ./schemas/ --format json
|
|
380
|
+
databricks-schema diff <catalog> ./schemas/ --format yaml
|
|
381
|
+
```
|
|
268
382
|
|
|
269
383
|
### `generate-sql`
|
|
270
384
|
|
|
271
|
-
Generate Databricks Spark SQL statements to bring the live catalog in line with local schema files (format auto-detected
|
|
385
|
+
Generate Databricks Spark SQL statements to bring the live catalog in line with local schema files (format auto-detected — YAML, JSON or DBML, not mixed). Statements are printed to stdout by default:
|
|
272
386
|
|
|
273
387
|
```bash
|
|
274
388
|
databricks-schema generate-sql <catalog> ./schemas/
|
|
@@ -280,7 +394,7 @@ Write one `.sql` file per schema to a directory instead:
|
|
|
280
394
|
databricks-schema generate-sql <catalog> ./schemas/ --output-dir ./migrations/
|
|
281
395
|
```
|
|
282
396
|
|
|
283
|
-
Destructive statements (`DROP SCHEMA`, `DROP TABLE`, `DROP COLUMN`) are emitted as SQL comments by default. Pass `--allow-drop` to emit them as executable statements:
|
|
397
|
+
Destructive statements (`DROP SCHEMA`, `DROP TABLE`, `DROP COLUMN`, `REVOKE`) are emitted as SQL comments by default. Pass `--allow-drop` to emit them as executable statements:
|
|
284
398
|
|
|
285
399
|
```bash
|
|
286
400
|
databricks-schema generate-sql <catalog> ./schemas/ --allow-drop
|
|
@@ -304,6 +418,12 @@ Include `owner` in the comparison (excluded by default):
|
|
|
304
418
|
databricks-schema generate-sql <catalog> ./schemas/ --include-metadata
|
|
305
419
|
```
|
|
306
420
|
|
|
421
|
+
Include direct grants in the comparison, emitting `GRANT` for privileges in the files but not live and (commented-out unless `--allow-drop`) `REVOKE` for privileges live but not in the files:
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
databricks-schema generate-sql <catalog> ./schemas/ --include-grants
|
|
425
|
+
```
|
|
426
|
+
|
|
307
427
|
### `validate`
|
|
308
428
|
|
|
309
429
|
Validate local schema files for structural integrity (no Databricks connection needed):
|
|
@@ -312,29 +432,28 @@ Validate local schema files for structural integrity (no Databricks connection n
|
|
|
312
432
|
databricks-schema validate ./schemas/
|
|
313
433
|
```
|
|
314
434
|
|
|
435
|
+
Pass `--format json` or `--format yaml` for an `{"issues": [...]}` document instead of `OK`/`ERROR:` text.
|
|
436
|
+
|
|
315
437
|
### `diff-files`
|
|
316
438
|
|
|
317
439
|
Compare two local directories of schema files (no Databricks connection needed). Same output,
|
|
318
|
-
exit codes, and `--schema` / `--include-metadata` flags as `diff`:
|
|
440
|
+
exit codes, `--format json`/`yaml`, and `--schema` / `--include-metadata` / `--include-grants` flags as `diff`:
|
|
319
441
|
|
|
320
442
|
```bash
|
|
321
443
|
databricks-schema diff-files ./schemas-prod/ ./schemas-test/
|
|
322
444
|
```
|
|
323
445
|
|
|
324
|
-
### `
|
|
325
|
-
|
|
326
|
-
List all accessible catalogs:
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
databricks-schema list-catalogs
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### `list-schemas`
|
|
446
|
+
### `json-schema`
|
|
333
447
|
|
|
334
|
-
|
|
448
|
+
Print the JSON Schema for one of the CLI's structured output shapes — no Databricks connection
|
|
449
|
+
needed. Useful before parsing `--format json`/`yaml` output (or `extract`'s output)
|
|
450
|
+
programmatically. Add `--format yaml` to render the schema itself as YAML:
|
|
335
451
|
|
|
336
452
|
```bash
|
|
337
|
-
databricks-schema
|
|
453
|
+
databricks-schema json-schema catalog # extract's stdout Catalog document
|
|
454
|
+
databricks-schema json-schema schema # one per-schema extract file
|
|
455
|
+
databricks-schema json-schema diff # diff / diff-files --format json/yaml
|
|
456
|
+
databricks-schema json-schema validate # validate --format json/yaml
|
|
338
457
|
```
|
|
339
458
|
|
|
340
459
|
## Python Library Usage
|
|
@@ -353,6 +472,10 @@ catalog = extractor.extract_catalog("my_catalog", schema_filter=["main", "raw"])
|
|
|
353
472
|
# Include Unity Catalog tags (extra API calls per entity; excluded by default)
|
|
354
473
|
catalog = extractor.extract_catalog("my_catalog", include_tags=True)
|
|
355
474
|
|
|
475
|
+
# Include direct (non-inherited) grants on schemas and tables; compare them with
|
|
476
|
+
# diff_schemas(..., include_grants=True) and friends
|
|
477
|
+
catalog = extractor.extract_catalog("my_catalog", include_grants=True)
|
|
478
|
+
|
|
356
479
|
# Include additional metadata (owner, storage_location)
|
|
357
480
|
catalog = extractor.extract_catalog("my_catalog", include_metadata=True)
|
|
358
481
|
|
|
@@ -363,7 +486,12 @@ yaml_text = catalog_to_yaml(catalog)
|
|
|
363
486
|
schema = schema_from_yaml(open("schemas/main.yaml").read())
|
|
364
487
|
print(schema.tables[0].columns)
|
|
365
488
|
|
|
366
|
-
#
|
|
489
|
+
# DBML: one document per catalog
|
|
490
|
+
from databricks_schema import catalog_from_dbml, catalog_to_dbml
|
|
491
|
+
Path("schemas/my_catalog.dbml").write_text(catalog_to_dbml(catalog))
|
|
492
|
+
catalog = catalog_from_dbml(Path("schemas/my_catalog.dbml").read_text())
|
|
493
|
+
|
|
494
|
+
# Compare live catalog against local YAML files (fmt="json" / fmt="dbml" for other formats)
|
|
367
495
|
result = diff_catalog_with_dir(catalog, Path("./schemas/"))
|
|
368
496
|
if result.has_changes:
|
|
369
497
|
for schema_diff in result.schemas:
|