Skip to content

Commit f09963b

Browse files
committed
Vibe code schema support
1 parent 7e07911 commit f09963b

File tree

10 files changed

+148
-0
lines changed

10 files changed

+148
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
bundle:
2+
name: my_project
3+
4+
sync: {paths: []} # don't need to copy files
5+
6+
experimental:
7+
python:
8+
resources:
9+
- "resources:load_resources"
10+
mutators:
11+
- "mutators:update_schema"
12+
13+
resources:
14+
schemas:
15+
my_schema_1:
16+
name: "My Schema"
17+
catalog_name: "my_catalog"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from dataclasses import replace
2+
3+
from databricks.bundles.core import schema_mutator
4+
from databricks.bundles.catalog import Schema
5+
6+
7+
@schema_mutator
8+
def update_schema(schema: Schema) -> Schema:
9+
assert isinstance(schema.name, str)
10+
11+
return replace(schema, name=f"{schema.name} (updated)")
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from databricks.bundles.core import Resources
2+
3+
4+
def load_resources() -> Resources:
5+
resources = Resources()
6+
7+
resources.add_schema(
8+
"my_schema_2",
9+
{
10+
"name": "My Schema (2)",
11+
"catalog_name": "my_catalog_2",
12+
},
13+
)
14+
15+
return resources
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uv run --with-requirements requirements-latest.txt --no-cache -q [CLI] bundle validate --output json
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Local = true
2+
Cloud = false # tests don't interact with APIs
3+
4+
[EnvMatrix]
5+
UV_ARGS = [
6+
# pipelines are only supported in the latest version of the wheel
7+
"--with-requirements requirements-latest.txt --no-cache",
8+
]

experimental/python/databricks/bundles/core/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"VariableOrOptional",
1515
"job_mutator",
1616
"pipeline_mutator",
17+
"schema_mutator",
1718
"load_resources_from_current_package_module",
1819
"load_resources_from_module",
1920
"load_resources_from_modules",
@@ -39,6 +40,7 @@
3940
ResourceMutator,
4041
job_mutator,
4142
pipeline_mutator,
43+
schema_mutator,
4244
)
4345
from databricks.bundles.core._resources import Resources
4446
from databricks.bundles.core._variable import (

experimental/python/databricks/bundles/core/_resource_mutator.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from databricks.bundles.core._resource import Resource
77

88
if TYPE_CHECKING:
9+
from databricks.bundles.catalog._models.schema import Schema
910
from databricks.bundles.jobs._models.job import Job
1011
from databricks.bundles.pipelines._models.pipeline import Pipeline
1112

@@ -127,3 +128,35 @@ def my_pipeline_mutator(bundle: Bundle, pipeline: Pipeline) -> Pipeline:
127128
from databricks.bundles.pipelines._models.pipeline import Pipeline
128129

129130
return ResourceMutator(resource_type=Pipeline, function=function)
131+
132+
133+
@overload
134+
def schema_mutator(
135+
function: Callable[[Bundle, "Schema"], "Schema"],
136+
) -> ResourceMutator["Schema"]: ...
137+
138+
139+
@overload
140+
def schema_mutator(
141+
function: Callable[["Schema"], "Schema"],
142+
) -> ResourceMutator["Schema"]: ...
143+
144+
145+
def schema_mutator(function: Callable) -> ResourceMutator["Schema"]:
146+
"""
147+
Decorator for defining a schema mutator. Function should return a new instance of the schema with the desired changes,
148+
instead of mutating the input schema.
149+
150+
Example:
151+
152+
.. code-block:: python
153+
154+
@schema_mutator
155+
def my_schema_mutator(bundle: Bundle, schema: Schema) -> Schema:
156+
return replace(schema, name="my_schema")
157+
158+
:param function: Function that mutates a schema.
159+
"""
160+
from databricks.bundles.catalog._models.schema import Schema
161+
162+
return ResourceMutator(resource_type=Schema, function=function)

experimental/python/databricks/bundles/core/_resource_type.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def all(cls) -> tuple["_ResourceType", ...]:
3131
# intentionally lazily load all resource types to avoid imports from databricks.bundles.core to
3232
# be imported in databricks.bundles.<resource_type>
3333

34+
from databricks.bundles.catalog._models.schema import Schema
3435
from databricks.bundles.jobs._models.job import Job
3536
from databricks.bundles.pipelines._models.pipeline import Pipeline
3637

@@ -45,4 +46,9 @@ def all(cls) -> tuple["_ResourceType", ...]:
4546
plural_name="pipelines",
4647
singular_name="pipeline",
4748
),
49+
_ResourceType(
50+
resource_type=Schema,
51+
plural_name="schemas",
52+
singular_name="schema",
53+
),
4854
)

experimental/python/databricks/bundles/core/_resources.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from databricks.bundles.core._transform import _transform
77

88
if TYPE_CHECKING:
9+
from databricks.bundles.catalog._models.schema import Schema, SchemaParam
910
from databricks.bundles.jobs._models.job import Job, JobParam
1011
from databricks.bundles.pipelines._models.pipeline import Pipeline, PipelineParam
1112

@@ -57,6 +58,7 @@ def load_resources(bundle: Bundle) -> Resources:
5758
def __init__(self):
5859
self._jobs = dict[str, "Job"]()
5960
self._pipelines = dict[str, "Pipeline"]()
61+
self._schemas = dict[str, "Schema"]()
6062
self._locations = dict[tuple[str, ...], Location]()
6163
self._diagnostics = Diagnostics()
6264

@@ -68,6 +70,10 @@ def jobs(self) -> dict[str, "Job"]:
6870
def pipelines(self) -> dict[str, "Pipeline"]:
6971
return self._pipelines
7072

73+
@property
74+
def schemas(self) -> dict[str, "Schema"]:
75+
return self._schemas
76+
7177
@property
7278
def diagnostics(self) -> Diagnostics:
7379
"""
@@ -91,6 +97,7 @@ def add_resource(
9197
:param location: optional location of the resource in the source code
9298
"""
9399

100+
from databricks.bundles.catalog import Schema
94101
from databricks.bundles.jobs import Job
95102
from databricks.bundles.pipelines import Pipeline
96103

@@ -101,6 +108,8 @@ def add_resource(
101108
self.add_job(resource_name, resource, location=location)
102109
case Pipeline():
103110
self.add_pipeline(resource_name, resource, location=location)
111+
case Schema():
112+
self.add_schema(resource_name, resource, location=location)
104113
case _:
105114
raise ValueError(f"Unsupported resource type: {type(resource)}")
106115

@@ -168,6 +177,38 @@ def add_pipeline(
168177

169178
self._pipelines[resource_name] = pipeline
170179

180+
def add_schema(
181+
self,
182+
resource_name: str,
183+
schema: "SchemaParam",
184+
*,
185+
location: Optional[Location] = None,
186+
) -> None:
187+
"""
188+
Adds a schema to the collection of resources. Resource name must be unique across all schemas.
189+
190+
:param resource_name: unique identifier for the schema
191+
:param schema: the schema to add, can be Schema or dict
192+
:param location: optional location of the schema in the source code
193+
"""
194+
from databricks.bundles.catalog import Schema
195+
196+
schema = _transform(Schema, schema)
197+
path = ("resources", "schemas", resource_name)
198+
location = location or Location.from_stack_frame(depth=1)
199+
200+
if self._schemas.get(resource_name):
201+
self.add_diagnostic_error(
202+
msg=f"Duplicate resource name '{resource_name}' for a schema. Resource names must be unique.",
203+
location=location,
204+
path=path,
205+
)
206+
else:
207+
if location:
208+
self.add_location(path, location)
209+
210+
self._schemas[resource_name] = schema
211+
171212
def add_location(self, path: tuple[str, ...], location: Location) -> None:
172213
"""
173214
Associate source code location with a path in the bundle configuration.
@@ -244,6 +285,9 @@ def add_resources(self, other: "Resources") -> None:
244285
for name, pipeline in other.pipelines.items():
245286
self.add_pipeline(name, pipeline)
246287

288+
for name, schema in other.schemas.items():
289+
self.add_schema(name, schema)
290+
247291
for path, location in other._locations.items():
248292
self.add_location(path, location)
249293

experimental/python/databricks_tests/core/test_resources.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
ResourceMutator,
1010
job_mutator,
1111
pipeline_mutator,
12+
schema_mutator,
1213
)
1314
from databricks.bundles.core._resource_type import _ResourceType
15+
from databricks.bundles.catalog._models.schema import Schema
1416
from databricks.bundles.jobs._models.job import Job
1517
from databricks.bundles.pipelines._models.pipeline import Pipeline
1618

@@ -43,6 +45,15 @@ class TestCase:
4345
),
4446
resource_types[Pipeline],
4547
),
48+
(
49+
TestCase(
50+
add_resource=Resources.add_schema,
51+
dict_example={"catalog_name": "my_catalog", "name": "my_schema"},
52+
dataclass_example=Schema(catalog_name="my_catalog", name="my_schema"),
53+
mutator=schema_mutator,
54+
),
55+
resource_types[Schema],
56+
),
4657
]
4758
test_case_ids = [tpe.plural_name for _, tpe in test_cases]
4859

0 commit comments

Comments
 (0)