diff --git a/bigquery/data_profile_scan/dataplex_get_data_profile_scan.py b/bigquery/data_profile_scan/dataplex_get_data_profile_scan.py new file mode 100644 index 0000000000..2c0b58413a --- /dev/null +++ b/bigquery/data_profile_scan/dataplex_get_data_profile_scan.py @@ -0,0 +1,70 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START dataplex_get_data_profile_scan] +import sys + +from google.api_core import exceptions +from google.cloud import dataplex_v1 + + +def get_data_profile_scan( + project_id: str, + location: str, + data_scan_id: str, +) -> None: + """Retrieves a Dataplex data profile scan and its latest profile results. + + Args: + project_id: Google Cloud project ID (for example, 'example-project'). + location: Google Cloud region where the data scan resides + (for example, 'us-central1'). + data_scan_id: Dataplex data profile scan ID + (for example, 'example-profile-scan'). + """ + client = dataplex_v1.DataScanServiceClient() + scan_name = f"projects/{project_id}/locations/{location}/dataScans/{data_scan_id}" + # Request DataScanView.FULL so the response includes data_profile_result metrics. + request = dataplex_v1.GetDataScanRequest( + name=scan_name, + view=dataplex_v1.GetDataScanRequest.DataScanView.FULL, + ) + + try: + scan = client.get_data_scan(request=request) + except exceptions.NotFound as err: + print( + f"error: data profile scan '{data_scan_id}' not found in location " + f"'{location}' for project '{project_id}': {err.message}", + file=sys.stderr, + ) + return + except exceptions.GoogleAPICallError as err: + print( + f"error: failed to retrieve data profile scan '{data_scan_id}' in location " + f"'{location}' for project '{project_id}': {err.message}", + file=sys.stderr, + ) + return + + row_count = ( + scan.data_profile_result.row_count if scan.data_profile_result else "N/A" + ) + print(f"Resource ID: {scan.name}") + print(f"Data Resource: {scan.data.resource}") + print(f"Row Count: {row_count}") + print(f"Scan State: {scan.state.name}") + + +# [END dataplex_get_data_profile_scan] diff --git a/bigquery/data_profile_scan/dataplex_get_data_profile_scan_test.py b/bigquery/data_profile_scan/dataplex_get_data_profile_scan_test.py new file mode 100644 index 0000000000..afd77805c7 --- /dev/null +++ b/bigquery/data_profile_scan/dataplex_get_data_profile_scan_test.py @@ -0,0 +1,76 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unittest import mock + +import dataplex_get_data_profile_scan +from google.api_core import exceptions +import pytest + + +def test_get_data_profile_scan_success( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], +) -> None: + mock_client = mock.MagicMock() + mock_scan = mock.MagicMock() + mock_scan.name = ( + "projects/example-project/locations/us-central1/dataScans/example-profile-scan" + ) + mock_scan.data.resource = "//bigquery.googleapis.com/projects/bigquery-public-data/datasets/samples/tables/shakespeare" + mock_scan.data_profile_result.row_count = 164656 + mock_scan.state.name = "ACTIVE" + mock_client.get_data_scan.return_value = mock_scan + monkeypatch.setattr( + dataplex_get_data_profile_scan.dataplex_v1, + "DataScanServiceClient", + lambda: mock_client, + ) + + dataplex_get_data_profile_scan.get_data_profile_scan( + project_id="example-project", + location="us-central1", + data_scan_id="example-profile-scan", + ) + + captured = capsys.readouterr() + assert ( + "Resource ID: projects/example-project/locations/us-central1/dataScans/example-profile-scan" + in captured.out + ) + assert "Row Count: 164656" in captured.out + assert "Scan State: ACTIVE" in captured.out + + +def test_get_data_profile_scan_error( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], +) -> None: + mock_client = mock.MagicMock() + mock_client.get_data_scan.side_effect = exceptions.NotFound("scan not found") + monkeypatch.setattr( + dataplex_get_data_profile_scan.dataplex_v1, + "DataScanServiceClient", + lambda: mock_client, + ) + + dataplex_get_data_profile_scan.get_data_profile_scan( + project_id="example-project", + location="us-central1", + data_scan_id="example-profile-scan", + ) + + captured = capsys.readouterr() + assert "error:" in captured.err + assert "example-profile-scan" in captured.err diff --git a/bigquery/data_profile_scan/noxfile_config.py b/bigquery/data_profile_scan/noxfile_config.py new file mode 100644 index 0000000000..63902aa8c7 --- /dev/null +++ b/bigquery/data_profile_scan/noxfile_config.py @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11"], + # Enforce type hints on new samples. + "enforce_type_hints": True, + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "pip_version_override": None, + "envs": {}, +} diff --git a/bigquery/data_profile_scan/requirements-test.txt b/bigquery/data_profile_scan/requirements-test.txt new file mode 100644 index 0000000000..c9e154ba44 --- /dev/null +++ b/bigquery/data_profile_scan/requirements-test.txt @@ -0,0 +1 @@ +pytest==9.0.3; python_version >= "3.10" diff --git a/bigquery/data_profile_scan/requirements.txt b/bigquery/data_profile_scan/requirements.txt new file mode 100644 index 0000000000..07ce35f203 --- /dev/null +++ b/bigquery/data_profile_scan/requirements.txt @@ -0,0 +1 @@ +google-cloud-dataplex==2.20.0