Repository navigation
[FS2524] Add Feature Spec as a Bundle Resource #7364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
6bd9422
TEMP: bump Go SDK to v0.194.0 for local development
Daniel114510 0cc9f17
Add the feature_specs bundle resource with UC grants
Daniel114510 8ea0673
TEMP: stand-in for feature_specs.generated.yml until cli.json carries…
Daniel114510 262ce8f
Add feature_spec.yml.tmpl to the invariant matrices
Daniel114510 0f8ffce
List feature_specs in the workspace open output
Daniel114510 ec9990e
Cover feature spec dependency capture with an acceptance case
Daniel114510 8090e03
Refresh the grants plan golden for the re-keyed grants action
Daniel114510 62045b7
Run the feature spec acceptance cases against a real workspace
Daniel114510 6ada4aa
Link the feature_specs changelog entry to its PR
Daniel114510 41e5e09
Reword the feature spec adapter's doc comments
Daniel114510 1698695
Merge main into fs2524-feature-specs
Daniel114510 e81b486
Generate the feature_specs schema, Python models and reference output
Daniel114510 0b50552
Write the feature spec test literals with promoted fields
Daniel114510 37c5813
Use bash 3.2 redirects in the feature spec acceptance cleanup
Daniel114510 864d126
Add feature_spec_mutator and add_feature_spec to the public API snapshot
Daniel114510 700f5e0
Skip the lowercased read-back of a feature spec name
Daniel114510 93f97ac
Merge remote-tracking branch 'origin/main' into fs2524-feature-specs
Daniel114510 a34162d
Regenerate the feature spec DependsOn model after merging main
Daniel114510 9423626
Match the feature spec bind test's summary URL on Azure and GCP
Daniel114510 f34d1a8
Merge remote-tracking branch 'origin/main' into fs2524-feature-specs
janniklasrose File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| * Add support for the `feature_specs` resource type, including UC grants on a feature spec. ([#7364](https://github.com/databricks/cli/pull/7364)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Creates the feature tables and Python UDFs that the feature_specs acceptance tests look up, in an | ||
| existing schema. Creating a feature spec resolves each of them in Unity Catalog. | ||
|
|
||
| Usage: create_feature_spec_fixtures.py CATALOG.SCHEMA | ||
| """ | ||
|
|
||
| import json | ||
| import os | ||
| import subprocess | ||
| import sys | ||
| import time | ||
|
|
||
| schema_full_name = sys.argv[1] | ||
| cli = os.environ.get("CLI", "databricks") | ||
| warehouse_id = os.environ["TEST_DEFAULT_WAREHOUSE_ID"] | ||
|
|
||
| statements = [ | ||
| f"CREATE TABLE {schema_full_name}.user_features " | ||
| "(user_id INT NOT NULL, age INT, country STRING, CONSTRAINT user_features_pk PRIMARY KEY (user_id))", | ||
| f"CREATE TABLE {schema_full_name}.tenant_user_features " | ||
| "(tenant_id INT NOT NULL, user_id INT NOT NULL, age INT, country STRING, " | ||
| "CONSTRAINT tenant_user_features_pk PRIMARY KEY (tenant_id, user_id))", | ||
| f"CREATE FUNCTION {schema_full_name}.score(x INT) RETURNS DOUBLE LANGUAGE PYTHON AS $$ return float(x) $$", | ||
| f"CREATE FUNCTION {schema_full_name}.country_score(x INT, y STRING) RETURNS DOUBLE LANGUAGE PYTHON " | ||
| "AS $$ return float(x) + len(y) $$", | ||
| ] | ||
|
|
||
|
|
||
| def call_api(*args): | ||
| result = subprocess.run([cli, "api", *args], capture_output=True, text=True) | ||
| if result.returncode != 0: | ||
| print(f"databricks api {' '.join(args)} failed: {result.stderr}", file=sys.stderr) | ||
| sys.exit(1) | ||
| return json.loads(result.stdout) | ||
|
|
||
|
|
||
| for statement in statements: | ||
| payload = json.dumps({"warehouse_id": warehouse_id, "statement": statement, "wait_timeout": "50s"}) | ||
| response = call_api("post", "/api/2.0/sql/statements/", "--json", payload) | ||
| # A warehouse that is still starting outlasts wait_timeout. | ||
| deadline = time.monotonic() + 600 | ||
| while response["status"]["state"] in ("PENDING", "RUNNING") and time.monotonic() < deadline: | ||
| time.sleep(5) | ||
| response = call_api("get", f"/api/2.0/sql/statements/{response['statement_id']}") | ||
| if response["status"]["state"] != "SUCCEEDED": | ||
| print(f"Statement {statement!r} ended in {response['status']}", file=sys.stderr) | ||
| sys.exit(1) | ||
12 changes: 12 additions & 0 deletions
12
acceptance/bundle/deployment/bind/feature_spec/databricks.yml.tmpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| bundle: | ||
| name: test-bind-feature-spec-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| feature_specs: | ||
| spec1: | ||
| name: $SCHEMA_FULL_NAME.boundspec | ||
| features: | ||
| - feature_lookup: | ||
| table: $SCHEMA_FULL_NAME.user_features | ||
| lookup_keys: [user_id] | ||
| feature_names: [age] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Cloud = true | ||
| EnvMatrix.DMS = ["", "true"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
|
|
||
| >>> [CLI] schemas create fspec_[UNIQUE_NAME] main -o json | ||
| { | ||
| "full_name": "main.fspec_[UNIQUE_NAME]" | ||
| } | ||
|
|
||
| >>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME] | ||
|
|
||
| === Create the feature spec outside the bundle | ||
| >>> [CLI] api post /api/2.0/feature-engineering/feature-specs --json { | ||
| "name": "main.fspec_[UNIQUE_NAME].boundspec", | ||
| "features": [{"feature_lookup": {"table": "main.fspec_[UNIQUE_NAME].user_features", "lookup_keys": ["user_id"], "feature_names": ["age"]}}] | ||
| } | ||
| { | ||
| "name": "main.fspec_[UNIQUE_NAME].boundspec" | ||
| } | ||
|
|
||
| >>> [CLI] bundle deployment bind spec1 main.fspec_[UNIQUE_NAME].boundspec --auto-approve | ||
| Successfully bound feature_spec with an id 'main.fspec_[UNIQUE_NAME].boundspec' | ||
| Run 'bundle deploy' to deploy changes to your workspace | ||
|
|
||
| >>> [CLI] bundle summary | ||
| Name: test-bind-feature-spec-[UNIQUE_NAME] | ||
| Target: default | ||
| Workspace: | ||
| User: [USERNAME] | ||
| Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default | ||
| Resources: | ||
| Feature Specs: | ||
| spec1: | ||
| Name: main.fspec_[UNIQUE_NAME].boundspec | ||
| URL: [DATABRICKS_URL]/explore/data/functions/main/fspec_[UNIQUE_NAME]/boundspec | ||
|
|
||
| === The bound feature spec matches the config, so there is nothing to change | ||
| >>> [CLI] bundle plan | ||
| Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged | ||
|
|
||
| >>> [CLI] bundle deployment unbind spec1 | ||
|
|
||
| >>> [CLI] bundle summary | ||
| Name: test-bind-feature-spec-[UNIQUE_NAME] | ||
| Target: default | ||
| Workspace: | ||
| User: [USERNAME] | ||
| Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default | ||
| Resources: | ||
| Feature Specs: | ||
| spec1: | ||
| Name: main.fspec_[UNIQUE_NAME].boundspec | ||
| URL: (not deployed) | ||
|
|
||
| >>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].boundspec | ||
| {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Creating a feature spec resolves its lookup tables in Unity Catalog, so the test creates them in | ||
| # a schema of its own. Dropping the schema also drops the feature spec. | ||
| export SCHEMA_FULL_NAME="main.fspec_$UNIQUE_NAME" | ||
| trace $CLI schemas create "fspec_$UNIQUE_NAME" main -o json | jq '{full_name}' | ||
| trace create_feature_spec_fixtures.py "$SCHEMA_FULL_NAME" | ||
|
|
||
| cleanup() { | ||
| $CLI schemas delete "$SCHEMA_FULL_NAME" --force >> LOG.cleanup 2>&1 || true | ||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| envsubst < databricks.yml.tmpl > databricks.yml | ||
|
|
||
| title "Create the feature spec outside the bundle" | ||
| MSYS_NO_PATHCONV=1 trace $CLI api post /api/2.0/feature-engineering/feature-specs --json "{ | ||
| \"name\": \"$SCHEMA_FULL_NAME.boundspec\", | ||
| \"features\": [{\"feature_lookup\": {\"table\": \"$SCHEMA_FULL_NAME.user_features\", \"lookup_keys\": [\"user_id\"], \"feature_names\": [\"age\"]}}] | ||
| }" | jq '{name}' | ||
|
|
||
| trace $CLI bundle deployment bind spec1 $SCHEMA_FULL_NAME.boundspec --auto-approve | ||
| trace $CLI bundle summary | ||
|
|
||
| title "The bound feature spec matches the config, so there is nothing to change" | ||
| trace $CLI bundle plan | ||
|
|
||
| trace $CLI bundle deployment unbind spec1 | ||
| trace $CLI bundle summary | ||
|
|
||
| MSYS_NO_PATHCONV=1 trace $CLI api delete /api/2.0/feature-engineering/feature-specs/$SCHEMA_FULL_NAME.boundspec |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| Ignore = [ | ||
| ".databricks", | ||
| ] | ||
|
|
||
| # Fake SQL endpoint so create_feature_spec_fixtures.py works against the local test server too. | ||
| [[Server]] | ||
| Pattern = "POST /api/2.0/sql/statements/" | ||
| Response.Body = '{"status": {"state": "SUCCEEDED"}, "manifest": {"schema": {"columns": []}}}' | ||
|
|
||
| # Azure and GCP hosts carry the workspace ID, so their summary URLs have no ?w=<id>. | ||
| [[Repls]] | ||
| Old = '\?[ow]=\[WORKSPACE_ID\]' | ||
|
Daniel114510 marked this conversation as resolved.
Resolved
|
||
| New = '' | ||
| Order = 1000 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| bundle: | ||
| name: test-bundle-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| feature_specs: | ||
| foo: | ||
| name: main.fspec_inv_$UNIQUE_NAME.test_feature_spec | ||
| features: | ||
| - feature_lookup: | ||
| table: main.fspec_inv_$UNIQUE_NAME.user_features | ||
| lookup_keys: [user_id] | ||
| feature_names: [age] | ||
| grants: | ||
| - principal: account users | ||
| privileges: | ||
| - EXECUTE |
4 changes: 4 additions & 0 deletions
4
acceptance/bundle/invariant/configs/feature_spec.yml.tmpl-cleanup.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #!/bin/bash | ||
|
|
||
| echo "Cleaning up temporary schema" | ||
| $CLI schemas delete main.fspec_inv_$UNIQUE_NAME --force || true |
8 changes: 8 additions & 0 deletions
8
acceptance/bundle/invariant/configs/feature_spec.yml.tmpl-init.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Creating a feature spec resolves its lookup table in Unity Catalog, and the invariant harness | ||
| # provisions no tables of its own. | ||
| echo "Creating temporary schema and feature table: main.fspec_inv_$UNIQUE_NAME" | ||
|
|
||
| $CLI schemas create fspec_inv_$UNIQUE_NAME main -o json | jq '{full_name}' | ||
| create_feature_spec_fixtures.py main.fspec_inv_$UNIQUE_NAME |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
acceptance/bundle/python/feature_specs-support/databricks.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| bundle: | ||
| name: my_project | ||
|
|
||
| sync: {paths: []} # don't need to copy files | ||
|
|
||
| python: | ||
| resources: | ||
| - "resources:load_resources" | ||
| mutators: | ||
| - "mutators:update_feature_spec" | ||
|
|
||
| resources: | ||
| feature_specs: | ||
| my_feature_spec_1: | ||
| name: main.default.my_feature_spec_1 | ||
| features: | ||
| - feature_lookup: | ||
| table: main.default.user_features | ||
| lookup_keys: [user_id] | ||
| feature_names: [age] | ||
| grants: | ||
| - principal: account users | ||
| privileges: [EXECUTE] |
11 changes: 11 additions & 0 deletions
11
acceptance/bundle/python/feature_specs-support/mutators.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| from dataclasses import replace | ||
|
|
||
| from databricks.bundles.core import feature_spec_mutator | ||
| from databricks.bundles.feature_specs import FeatureSpec | ||
|
|
||
|
|
||
| @feature_spec_mutator | ||
| def update_feature_spec(feature_spec: FeatureSpec) -> FeatureSpec: | ||
| assert isinstance(feature_spec.name, str) | ||
|
|
||
| return replace(feature_spec, name=f"{feature_spec.name}_updated") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Cloud = true | ||
| EnvMatrix.DMS = ["", "true"] | ||
| EnvMatrix.PYDAB_VERSION = ["current"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
|
|
||
| >>> uv run [UV_ARGS] -q [CLI] bundle validate --output json | ||
| { | ||
| "experimental": { | ||
| "python": { | ||
| "mutators": [ | ||
| "mutators:update_feature_spec" | ||
| ], | ||
| "resources": [ | ||
| "resources:load_resources" | ||
| ] | ||
| } | ||
| }, | ||
| "resources": { | ||
| "feature_specs": { | ||
| "my_feature_spec_1": { | ||
| "features": [ | ||
| { | ||
| "feature_lookup": { | ||
| "feature_names": [ | ||
| "age" | ||
| ], | ||
| "lookup_keys": [ | ||
| "user_id" | ||
| ], | ||
| "table": "main.default.user_features" | ||
| } | ||
| } | ||
| ], | ||
| "grants": [ | ||
| { | ||
| "principal": "account users", | ||
| "privileges": [ | ||
| "EXECUTE" | ||
| ] | ||
| } | ||
| ], | ||
| "name": "main.default.my_feature_spec_1_updated" | ||
| }, | ||
| "my_feature_spec_2": { | ||
| "extra_pip_requirements": { | ||
| "requirements": [ | ||
| "numpy==2.1.0" | ||
| ] | ||
| }, | ||
| "features": [ | ||
| { | ||
| "declarative_feature": { | ||
| "feature": "main.default.my_feature" | ||
| } | ||
| } | ||
| ], | ||
| "name": "main.default.my_feature_spec_2_updated" | ||
| } | ||
| } | ||
| } | ||
| } |
18 changes: 18 additions & 0 deletions
18
acceptance/bundle/python/feature_specs-support/resources.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| from databricks.bundles.core import Resources | ||
|
|
||
|
|
||
| def load_resources() -> Resources: | ||
| resources = Resources() | ||
|
|
||
| resources.add_feature_spec( | ||
| "my_feature_spec_2", | ||
| { | ||
| "name": "main.default.my_feature_spec_2", | ||
| "features": [ | ||
| {"declarative_feature": {"feature": "main.default.my_feature"}}, | ||
| ], | ||
| "extra_pip_requirements": {"requirements": ["numpy==2.1.0"]}, | ||
| }, | ||
| ) | ||
|
|
||
| return resources |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| trace uv run $UV_ARGS -q $CLI bundle validate --output json | \ | ||
| jq "pick(.experimental.python, .resources)" | ||
|
|
||
| rm -fr .databricks __pycache__ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Cloud = true | ||
|
|
||
| # feature specs are only supported in the current version of the wheel | ||
| EnvMatrix.PYDAB_VERSION = ["current"] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.