From 3dc16217e520c718e30ccb87f23713cb63c0d777 Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Tue, 10 Mar 2026 09:28:28 -0500 Subject: [PATCH 1/4] feat: add anomaly detection section to data profiling docs Add tested SDK example for enabling schema-level anomaly detection using w.data_quality.create_monitor with AnomalyDetectionConfig. Co-Authored-By: Claude Opus 4.6 --- .../7-data-profiling.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/databricks-skills/databricks-unity-catalog/7-data-profiling.md b/databricks-skills/databricks-unity-catalog/7-data-profiling.md index 36eceff4..1ca4b351 100644 --- a/databricks-skills/databricks-unity-catalog/7-data-profiling.md +++ b/databricks-skills/databricks-unity-catalog/7-data-profiling.md @@ -237,6 +237,30 @@ w.data_quality.delete_monitor( --- +## Anomaly Detection + +Anomaly detection is enabled at the **schema level**, not per table. Once enabled, Databricks automatically scans all tables in the schema at the same frequency they are updated. + +```python +from databricks.sdk.service.dataquality import Monitor, AnomalyDetectionConfig + +schema_info = w.schemas.get("catalog.schema") + +monitor = w.data_quality.create_monitor( + monitor=Monitor( + object_type="schema", + object_id=schema_info.schema_id, + anomaly_detection_config=AnomalyDetectionConfig(), + ), +) +``` + +> **Note:** Anomaly detection requires `MANAGE SCHEMA` or `MANAGE CATALOG` privileges and serverless compute enabled on the workspace. + +For more details, see [Anomaly Detection Documentation](https://docs.databricks.com/aws/en/data-quality-monitoring/anomaly-detection/). + +--- + ## Output Tables When a monitor is created, two metric tables are generated in the specified output schema: From 8f499ce6983fc57eabaebb2077e7ec8069602f8a Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Tue, 10 Mar 2026 09:32:26 -0500 Subject: [PATCH 2/4] style: fix ruff formatting for auth.py and test_sql.py Co-Authored-By: Claude Opus 4.6 --- .../databricks_tools_core/auth.py | 13 +- databricks-tools-core/tests/unit/test_sql.py | 118 ++++++++++++------ 2 files changed, 89 insertions(+), 42 deletions(-) diff --git a/databricks-tools-core/databricks_tools_core/auth.py b/databricks-tools-core/databricks_tools_core/auth.py index 21913983..e021ad3d 100644 --- a/databricks-tools-core/databricks_tools_core/auth.py +++ b/databricks-tools-core/databricks_tools_core/auth.py @@ -48,7 +48,9 @@ def my_function(): _active_host: Optional[str] = None -def set_active_workspace(profile: Optional[str] = None, host: Optional[str] = None) -> None: +def set_active_workspace( + profile: Optional[str] = None, host: Optional[str] = None +) -> None: """Set the active workspace for all subsequent tool calls. Adds a step 0 to get_workspace_client() that overrides the default SDK @@ -83,7 +85,10 @@ def get_active_workspace() -> dict: def _has_oauth_credentials() -> bool: """Check if OAuth credentials (SP) are configured in environment.""" - return bool(os.environ.get("DATABRICKS_CLIENT_ID") and os.environ.get("DATABRICKS_CLIENT_SECRET")) + return bool( + os.environ.get("DATABRICKS_CLIENT_ID") + and os.environ.get("DATABRICKS_CLIENT_SECRET") + ) # Context variables for per-request authentication @@ -153,7 +158,9 @@ def get_workspace_client() -> WorkspaceClient: # or when OAuth M2M credentials are present (Databricks Apps runtime). if not force and not _has_oauth_credentials(): if _active_profile: - return tag_client(WorkspaceClient(profile=_active_profile, **product_kwargs)) + return tag_client( + WorkspaceClient(profile=_active_profile, **product_kwargs) + ) if _active_host: return tag_client(WorkspaceClient(host=_active_host, **product_kwargs)) diff --git a/databricks-tools-core/tests/unit/test_sql.py b/databricks-tools-core/tests/unit/test_sql.py index d1b661c6..cb16e048 100644 --- a/databricks-tools-core/tests/unit/test_sql.py +++ b/databricks-tools-core/tests/unit/test_sql.py @@ -13,9 +13,13 @@ class TestExecuteSQLQueryTags: """Tests for query_tags parameter passthrough.""" - @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") + @mock.patch( + "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" + ) @mock.patch("databricks_tools_core.sql.sql.SQLExecutor") - def test_execute_sql_passes_query_tags_to_executor(self, mock_executor_cls, mock_warehouse): + def test_execute_sql_passes_query_tags_to_executor( + self, mock_executor_cls, mock_warehouse + ): """query_tags should be passed through to SQLExecutor.execute().""" mock_executor = mock.Mock() mock_executor.execute.return_value = [{"num": 1}] @@ -31,7 +35,9 @@ def test_execute_sql_passes_query_tags_to_executor(self, mock_executor_cls, mock call_kwargs = mock_executor.execute.call_args.kwargs assert call_kwargs["query_tags"] == "team:eng,cost_center:701" - @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") + @mock.patch( + "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" + ) @mock.patch("databricks_tools_core.sql.sql.SQLExecutor") def test_execute_sql_without_query_tags(self, mock_executor_cls, mock_warehouse): """When query_tags not provided, executor should not receive it (or receive None).""" @@ -45,9 +51,13 @@ def test_execute_sql_without_query_tags(self, mock_executor_cls, mock_warehouse) call_kwargs = mock_executor.execute.call_args.kwargs assert call_kwargs.get("query_tags") is None - @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") + @mock.patch( + "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" + ) @mock.patch("databricks_tools_core.sql.sql.SQLParallelExecutor") - def test_execute_sql_multi_passes_query_tags(self, mock_parallel_cls, mock_warehouse): + def test_execute_sql_multi_passes_query_tags( + self, mock_parallel_cls, mock_warehouse + ): """query_tags should be passed through to SQLParallelExecutor.execute().""" mock_executor = mock.Mock() mock_executor.execute.return_value = { @@ -121,8 +131,9 @@ def test_executor_without_query_tags_omits_from_api(self, mock_get_client): assert "query_tags" not in call_kwargs -def _make_warehouse(id, name, state, creator_name="other@example.com", - enable_serverless_compute=False): +def _make_warehouse( + id, name, state, creator_name="other@example.com", enable_serverless_compute=False +): """Helper to create a mock warehouse object.""" w = mock.Mock() w.id = id @@ -141,33 +152,49 @@ class TestSortWithinTier: def test_serverless_first(self): """Serverless warehouses should come before classic ones.""" classic = _make_warehouse("c1", "Classic WH", State.RUNNING) - serverless = _make_warehouse("s1", "Serverless WH", State.RUNNING, - enable_serverless_compute=True) + serverless = _make_warehouse( + "s1", "Serverless WH", State.RUNNING, enable_serverless_compute=True + ) result = _sort_within_tier([classic, serverless], current_user=None) assert result[0].id == "s1" assert result[1].id == "c1" def test_serverless_before_user_owned(self): """Serverless should be preferred over user-owned classic.""" - classic_owned = _make_warehouse("c1", "My WH", State.RUNNING, - creator_name="me@example.com") - serverless_other = _make_warehouse("s1", "Other WH", State.RUNNING, - creator_name="other@example.com", - enable_serverless_compute=True) - result = _sort_within_tier([classic_owned, serverless_other], - current_user="me@example.com") + classic_owned = _make_warehouse( + "c1", "My WH", State.RUNNING, creator_name="me@example.com" + ) + serverless_other = _make_warehouse( + "s1", + "Other WH", + State.RUNNING, + creator_name="other@example.com", + enable_serverless_compute=True, + ) + result = _sort_within_tier( + [classic_owned, serverless_other], current_user="me@example.com" + ) assert result[0].id == "s1" def test_serverless_user_owned_first(self): """Among serverless, user-owned should come first.""" - serverless_other = _make_warehouse("s1", "Other Serverless", State.RUNNING, - creator_name="other@example.com", - enable_serverless_compute=True) - serverless_owned = _make_warehouse("s2", "My Serverless", State.RUNNING, - creator_name="me@example.com", - enable_serverless_compute=True) - result = _sort_within_tier([serverless_other, serverless_owned], - current_user="me@example.com") + serverless_other = _make_warehouse( + "s1", + "Other Serverless", + State.RUNNING, + creator_name="other@example.com", + enable_serverless_compute=True, + ) + serverless_owned = _make_warehouse( + "s2", + "My Serverless", + State.RUNNING, + creator_name="me@example.com", + enable_serverless_compute=True, + ) + result = _sort_within_tier( + [serverless_other, serverless_owned], current_user="me@example.com" + ) assert result[0].id == "s2" assert result[1].id == "s1" @@ -177,8 +204,9 @@ def test_empty_list(self): def test_no_current_user(self): """Without a current user, only serverless preference applies.""" classic = _make_warehouse("c1", "Classic", State.RUNNING) - serverless = _make_warehouse("s1", "Serverless", State.RUNNING, - enable_serverless_compute=True) + serverless = _make_warehouse( + "s1", "Serverless", State.RUNNING, enable_serverless_compute=True + ) result = _sort_within_tier([classic, serverless], current_user=None) assert result[0].id == "s1" @@ -186,14 +214,17 @@ def test_no_current_user(self): class TestGetBestWarehouseServerless: """Tests for serverless preference in get_best_warehouse.""" - @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com") + @mock.patch( + "databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com", + ) @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_prefers_serverless_within_running_shared(self, mock_client_fn, mock_user): """Among running shared warehouses, serverless should be picked.""" classic_shared = _make_warehouse("c1", "Shared WH", State.RUNNING) - serverless_shared = _make_warehouse("s1", "Shared Serverless", State.RUNNING, - enable_serverless_compute=True) + serverless_shared = _make_warehouse( + "s1", "Shared Serverless", State.RUNNING, enable_serverless_compute=True + ) mock_client = mock.Mock() mock_client.warehouses.list.return_value = [classic_shared, serverless_shared] mock_client_fn.return_value = mock_client @@ -201,14 +232,17 @@ def test_prefers_serverless_within_running_shared(self, mock_client_fn, mock_use result = get_best_warehouse() assert result == "s1" - @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com") + @mock.patch( + "databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com", + ) @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_prefers_serverless_within_running_other(self, mock_client_fn, mock_user): """Among running non-shared warehouses, serverless should be picked.""" classic = _make_warehouse("c1", "My WH", State.RUNNING) - serverless = _make_warehouse("s1", "Fast WH", State.RUNNING, - enable_serverless_compute=True) + serverless = _make_warehouse( + "s1", "Fast WH", State.RUNNING, enable_serverless_compute=True + ) mock_client = mock.Mock() mock_client.warehouses.list.return_value = [classic, serverless] mock_client_fn.return_value = mock_client @@ -216,16 +250,22 @@ def test_prefers_serverless_within_running_other(self, mock_client_fn, mock_user result = get_best_warehouse() assert result == "s1" - @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com") + @mock.patch( + "databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com", + ) @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_tier_order_preserved_over_serverless(self, mock_client_fn, mock_user): """A running shared classic should still beat a stopped serverless.""" running_shared_classic = _make_warehouse("c1", "Shared WH", State.RUNNING) - stopped_serverless = _make_warehouse("s1", "Fast WH", State.STOPPED, - enable_serverless_compute=True) + stopped_serverless = _make_warehouse( + "s1", "Fast WH", State.STOPPED, enable_serverless_compute=True + ) mock_client = mock.Mock() - mock_client.warehouses.list.return_value = [stopped_serverless, running_shared_classic] + mock_client.warehouses.list.return_value = [ + stopped_serverless, + running_shared_classic, + ] mock_client_fn.return_value = mock_client result = get_best_warehouse() From e9982123cb16a82a1a53c33dedecaf9a7c022454 Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Tue, 10 Mar 2026 09:34:11 -0500 Subject: [PATCH 3/4] Revert "style: fix ruff formatting for auth.py and test_sql.py" This reverts commit 8f499ce6983fc57eabaebb2077e7ec8069602f8a. --- .../databricks_tools_core/auth.py | 13 +- databricks-tools-core/tests/unit/test_sql.py | 118 ++++++------------ 2 files changed, 42 insertions(+), 89 deletions(-) diff --git a/databricks-tools-core/databricks_tools_core/auth.py b/databricks-tools-core/databricks_tools_core/auth.py index e021ad3d..21913983 100644 --- a/databricks-tools-core/databricks_tools_core/auth.py +++ b/databricks-tools-core/databricks_tools_core/auth.py @@ -48,9 +48,7 @@ def my_function(): _active_host: Optional[str] = None -def set_active_workspace( - profile: Optional[str] = None, host: Optional[str] = None -) -> None: +def set_active_workspace(profile: Optional[str] = None, host: Optional[str] = None) -> None: """Set the active workspace for all subsequent tool calls. Adds a step 0 to get_workspace_client() that overrides the default SDK @@ -85,10 +83,7 @@ def get_active_workspace() -> dict: def _has_oauth_credentials() -> bool: """Check if OAuth credentials (SP) are configured in environment.""" - return bool( - os.environ.get("DATABRICKS_CLIENT_ID") - and os.environ.get("DATABRICKS_CLIENT_SECRET") - ) + return bool(os.environ.get("DATABRICKS_CLIENT_ID") and os.environ.get("DATABRICKS_CLIENT_SECRET")) # Context variables for per-request authentication @@ -158,9 +153,7 @@ def get_workspace_client() -> WorkspaceClient: # or when OAuth M2M credentials are present (Databricks Apps runtime). if not force and not _has_oauth_credentials(): if _active_profile: - return tag_client( - WorkspaceClient(profile=_active_profile, **product_kwargs) - ) + return tag_client(WorkspaceClient(profile=_active_profile, **product_kwargs)) if _active_host: return tag_client(WorkspaceClient(host=_active_host, **product_kwargs)) diff --git a/databricks-tools-core/tests/unit/test_sql.py b/databricks-tools-core/tests/unit/test_sql.py index cb16e048..d1b661c6 100644 --- a/databricks-tools-core/tests/unit/test_sql.py +++ b/databricks-tools-core/tests/unit/test_sql.py @@ -13,13 +13,9 @@ class TestExecuteSQLQueryTags: """Tests for query_tags parameter passthrough.""" - @mock.patch( - "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" - ) + @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") @mock.patch("databricks_tools_core.sql.sql.SQLExecutor") - def test_execute_sql_passes_query_tags_to_executor( - self, mock_executor_cls, mock_warehouse - ): + def test_execute_sql_passes_query_tags_to_executor(self, mock_executor_cls, mock_warehouse): """query_tags should be passed through to SQLExecutor.execute().""" mock_executor = mock.Mock() mock_executor.execute.return_value = [{"num": 1}] @@ -35,9 +31,7 @@ def test_execute_sql_passes_query_tags_to_executor( call_kwargs = mock_executor.execute.call_args.kwargs assert call_kwargs["query_tags"] == "team:eng,cost_center:701" - @mock.patch( - "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" - ) + @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") @mock.patch("databricks_tools_core.sql.sql.SQLExecutor") def test_execute_sql_without_query_tags(self, mock_executor_cls, mock_warehouse): """When query_tags not provided, executor should not receive it (or receive None).""" @@ -51,13 +45,9 @@ def test_execute_sql_without_query_tags(self, mock_executor_cls, mock_warehouse) call_kwargs = mock_executor.execute.call_args.kwargs assert call_kwargs.get("query_tags") is None - @mock.patch( - "databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123" - ) + @mock.patch("databricks_tools_core.sql.sql.get_best_warehouse", return_value="wh-123") @mock.patch("databricks_tools_core.sql.sql.SQLParallelExecutor") - def test_execute_sql_multi_passes_query_tags( - self, mock_parallel_cls, mock_warehouse - ): + def test_execute_sql_multi_passes_query_tags(self, mock_parallel_cls, mock_warehouse): """query_tags should be passed through to SQLParallelExecutor.execute().""" mock_executor = mock.Mock() mock_executor.execute.return_value = { @@ -131,9 +121,8 @@ def test_executor_without_query_tags_omits_from_api(self, mock_get_client): assert "query_tags" not in call_kwargs -def _make_warehouse( - id, name, state, creator_name="other@example.com", enable_serverless_compute=False -): +def _make_warehouse(id, name, state, creator_name="other@example.com", + enable_serverless_compute=False): """Helper to create a mock warehouse object.""" w = mock.Mock() w.id = id @@ -152,49 +141,33 @@ class TestSortWithinTier: def test_serverless_first(self): """Serverless warehouses should come before classic ones.""" classic = _make_warehouse("c1", "Classic WH", State.RUNNING) - serverless = _make_warehouse( - "s1", "Serverless WH", State.RUNNING, enable_serverless_compute=True - ) + serverless = _make_warehouse("s1", "Serverless WH", State.RUNNING, + enable_serverless_compute=True) result = _sort_within_tier([classic, serverless], current_user=None) assert result[0].id == "s1" assert result[1].id == "c1" def test_serverless_before_user_owned(self): """Serverless should be preferred over user-owned classic.""" - classic_owned = _make_warehouse( - "c1", "My WH", State.RUNNING, creator_name="me@example.com" - ) - serverless_other = _make_warehouse( - "s1", - "Other WH", - State.RUNNING, - creator_name="other@example.com", - enable_serverless_compute=True, - ) - result = _sort_within_tier( - [classic_owned, serverless_other], current_user="me@example.com" - ) + classic_owned = _make_warehouse("c1", "My WH", State.RUNNING, + creator_name="me@example.com") + serverless_other = _make_warehouse("s1", "Other WH", State.RUNNING, + creator_name="other@example.com", + enable_serverless_compute=True) + result = _sort_within_tier([classic_owned, serverless_other], + current_user="me@example.com") assert result[0].id == "s1" def test_serverless_user_owned_first(self): """Among serverless, user-owned should come first.""" - serverless_other = _make_warehouse( - "s1", - "Other Serverless", - State.RUNNING, - creator_name="other@example.com", - enable_serverless_compute=True, - ) - serverless_owned = _make_warehouse( - "s2", - "My Serverless", - State.RUNNING, - creator_name="me@example.com", - enable_serverless_compute=True, - ) - result = _sort_within_tier( - [serverless_other, serverless_owned], current_user="me@example.com" - ) + serverless_other = _make_warehouse("s1", "Other Serverless", State.RUNNING, + creator_name="other@example.com", + enable_serverless_compute=True) + serverless_owned = _make_warehouse("s2", "My Serverless", State.RUNNING, + creator_name="me@example.com", + enable_serverless_compute=True) + result = _sort_within_tier([serverless_other, serverless_owned], + current_user="me@example.com") assert result[0].id == "s2" assert result[1].id == "s1" @@ -204,9 +177,8 @@ def test_empty_list(self): def test_no_current_user(self): """Without a current user, only serverless preference applies.""" classic = _make_warehouse("c1", "Classic", State.RUNNING) - serverless = _make_warehouse( - "s1", "Serverless", State.RUNNING, enable_serverless_compute=True - ) + serverless = _make_warehouse("s1", "Serverless", State.RUNNING, + enable_serverless_compute=True) result = _sort_within_tier([classic, serverless], current_user=None) assert result[0].id == "s1" @@ -214,17 +186,14 @@ def test_no_current_user(self): class TestGetBestWarehouseServerless: """Tests for serverless preference in get_best_warehouse.""" - @mock.patch( - "databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com", - ) + @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com") @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_prefers_serverless_within_running_shared(self, mock_client_fn, mock_user): """Among running shared warehouses, serverless should be picked.""" classic_shared = _make_warehouse("c1", "Shared WH", State.RUNNING) - serverless_shared = _make_warehouse( - "s1", "Shared Serverless", State.RUNNING, enable_serverless_compute=True - ) + serverless_shared = _make_warehouse("s1", "Shared Serverless", State.RUNNING, + enable_serverless_compute=True) mock_client = mock.Mock() mock_client.warehouses.list.return_value = [classic_shared, serverless_shared] mock_client_fn.return_value = mock_client @@ -232,17 +201,14 @@ def test_prefers_serverless_within_running_shared(self, mock_client_fn, mock_use result = get_best_warehouse() assert result == "s1" - @mock.patch( - "databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com", - ) + @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com") @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_prefers_serverless_within_running_other(self, mock_client_fn, mock_user): """Among running non-shared warehouses, serverless should be picked.""" classic = _make_warehouse("c1", "My WH", State.RUNNING) - serverless = _make_warehouse( - "s1", "Fast WH", State.RUNNING, enable_serverless_compute=True - ) + serverless = _make_warehouse("s1", "Fast WH", State.RUNNING, + enable_serverless_compute=True) mock_client = mock.Mock() mock_client.warehouses.list.return_value = [classic, serverless] mock_client_fn.return_value = mock_client @@ -250,22 +216,16 @@ def test_prefers_serverless_within_running_other(self, mock_client_fn, mock_user result = get_best_warehouse() assert result == "s1" - @mock.patch( - "databricks_tools_core.sql.warehouse.get_current_username", - return_value="me@example.com", - ) + @mock.patch("databricks_tools_core.sql.warehouse.get_current_username", + return_value="me@example.com") @mock.patch("databricks_tools_core.sql.warehouse.get_workspace_client") def test_tier_order_preserved_over_serverless(self, mock_client_fn, mock_user): """A running shared classic should still beat a stopped serverless.""" running_shared_classic = _make_warehouse("c1", "Shared WH", State.RUNNING) - stopped_serverless = _make_warehouse( - "s1", "Fast WH", State.STOPPED, enable_serverless_compute=True - ) + stopped_serverless = _make_warehouse("s1", "Fast WH", State.STOPPED, + enable_serverless_compute=True) mock_client = mock.Mock() - mock_client.warehouses.list.return_value = [ - stopped_serverless, - running_shared_classic, - ] + mock_client.warehouses.list.return_value = [stopped_serverless, running_shared_classic] mock_client_fn.return_value = mock_client result = get_best_warehouse() From 6ae5ac5f85ebe2a8590721439c6ce29199384c03 Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Tue, 10 Mar 2026 09:38:30 -0500 Subject: [PATCH 4/4] docs: remove redundant anomaly detection link Co-Authored-By: Claude Opus 4.6 --- databricks-skills/databricks-unity-catalog/7-data-profiling.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/databricks-skills/databricks-unity-catalog/7-data-profiling.md b/databricks-skills/databricks-unity-catalog/7-data-profiling.md index 1ca4b351..23a2b62f 100644 --- a/databricks-skills/databricks-unity-catalog/7-data-profiling.md +++ b/databricks-skills/databricks-unity-catalog/7-data-profiling.md @@ -257,8 +257,6 @@ monitor = w.data_quality.create_monitor( > **Note:** Anomaly detection requires `MANAGE SCHEMA` or `MANAGE CATALOG` privileges and serverless compute enabled on the workspace. -For more details, see [Anomaly Detection Documentation](https://docs.databricks.com/aws/en/data-quality-monitoring/anomaly-detection/). - --- ## Output Tables