Skip to content

Commit e704876

Browse files
Merge branch 'main' into meetup-connector
2 parents 6ea2b74 + d4387aa commit e704876

130 files changed

Lines changed: 5735 additions & 1678 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bootstrap/sql/migrations/native/1.13.0/mysql/schemaChanges.sql

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,42 @@ WHERE pipelineType = 'profiler'
216216
OR JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.profileSampleType')
217217
OR JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.samplingMethodType'));
218218

219+
-- ingestion_pipeline_entity (testSuite pipelines): build profileSampleConfig (skip if already migrated)
220+
UPDATE ingestion_pipeline_entity
221+
SET json = JSON_SET(
222+
json,
223+
'$.sourceConfig.config.profileSampleConfig',
224+
JSON_OBJECT(
225+
'sampleConfigType', 'STATIC',
226+
'config', JSON_OBJECT(
227+
'profileSample', JSON_EXTRACT(json, '$.sourceConfig.config.profileSample'),
228+
'profileSampleType', COALESCE(
229+
JSON_EXTRACT(json, '$.sourceConfig.config.profileSampleType'),
230+
CAST('"PERCENTAGE"' AS JSON)
231+
),
232+
'samplingMethodType', JSON_EXTRACT(json, '$.sourceConfig.config.samplingMethodType')
233+
)
234+
)
235+
)
236+
WHERE pipelineType = 'testSuite'
237+
AND JSON_EXTRACT(json, '$.sourceConfig.config.profileSample') IS NOT NULL
238+
AND JSON_TYPE(JSON_EXTRACT(json, '$.sourceConfig.config.profileSample')) != 'NULL'
239+
AND NOT JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.profileSampleConfig');
240+
241+
-- ingestion_pipeline_entity (testSuite pipelines): remove old flat fields
242+
UPDATE ingestion_pipeline_entity
243+
SET json = JSON_REMOVE(
244+
JSON_REMOVE(
245+
JSON_REMOVE(json, '$.sourceConfig.config.samplingMethodType'),
246+
'$.sourceConfig.config.profileSampleType'
247+
),
248+
'$.sourceConfig.config.profileSample'
249+
)
250+
WHERE pipelineType = 'testSuite'
251+
AND (JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.profileSample')
252+
OR JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.profileSampleType')
253+
OR JSON_CONTAINS_PATH(json, 'one', '$.sourceConfig.config.samplingMethodType'));
254+
219255
-- RDF distributed indexing state tables
220256
CREATE TABLE IF NOT EXISTS rdf_index_job (
221257
id VARCHAR(36) NOT NULL,

bootstrap/sql/migrations/native/1.13.0/postgres/schemaChanges.sql

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,37 @@ WHERE json #>> '{pipelineType}' = 'profiler'
235235
OR json::jsonb #>> '{sourceConfig,config,profileSampleType}' IS NOT NULL
236236
OR json::jsonb #>> '{sourceConfig,config,samplingMethodType}' IS NOT NULL);
237237

238+
-- ingestion_pipeline_entity (testSuite pipelines): build profileSampleConfig (skip if already migrated)
239+
UPDATE ingestion_pipeline_entity
240+
SET json = jsonb_set(
241+
json::jsonb,
242+
'{sourceConfig,config,profileSampleConfig}',
243+
jsonb_build_object(
244+
'sampleConfigType', 'STATIC',
245+
'config', jsonb_build_object(
246+
'profileSample', json::jsonb #> '{sourceConfig,config,profileSample}',
247+
'profileSampleType', COALESCE(
248+
json::jsonb #> '{sourceConfig,config,profileSampleType}',
249+
'"PERCENTAGE"'::jsonb
250+
),
251+
'samplingMethodType', json::jsonb #> '{sourceConfig,config,samplingMethodType}'
252+
)
253+
)
254+
)::json
255+
WHERE json #>> '{pipelineType}' = 'testSuite'
256+
AND json::jsonb #>> '{sourceConfig,config,profileSample}' IS NOT NULL
257+
AND json::jsonb #> '{sourceConfig,config,profileSampleConfig}' IS NULL;
258+
259+
-- ingestion_pipeline_entity (testSuite pipelines): remove old flat fields
260+
UPDATE ingestion_pipeline_entity
261+
SET json = (json::jsonb #- '{sourceConfig,config,profileSample}'
262+
#- '{sourceConfig,config,profileSampleType}'
263+
#- '{sourceConfig,config,samplingMethodType}')::json
264+
WHERE json #>> '{pipelineType}' = 'testSuite'
265+
AND (json::jsonb #>> '{sourceConfig,config,profileSample}' IS NOT NULL
266+
OR json::jsonb #>> '{sourceConfig,config,profileSampleType}' IS NOT NULL
267+
OR json::jsonb #>> '{sourceConfig,config,samplingMethodType}' IS NOT NULL);
268+
238269
-- RDF distributed indexing state tables
239270
CREATE TABLE IF NOT EXISTS rdf_index_job (
240271
id VARCHAR(36) NOT NULL,

ingestion/setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@
423423
# TODO: Remove once no unit test requires testcontainers
424424
"testcontainers",
425425
VERSIONS["factory-boy"],
426+
*plugins["exasol"],
427+
*plugins["teradata"],
426428
}
427429

428430
test = {
@@ -491,6 +493,8 @@
491493
VERSIONS["kafka-connect"],
492494
VERSIONS["factory-boy"],
493495
"locust~=2.32.0",
496+
*plugins["exasol"],
497+
*plugins["teradata"],
494498
}
495499

496500
docs = {

ingestion/src/metadata/data_quality/runner/base_test_suite_source.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@
3434
from metadata.generated.schema.type.entityReference import EntityReference
3535
from metadata.ingestion.ometa.ometa_api import OpenMetadata
3636
from metadata.sampler.models import (
37-
ProfileSampleConfig,
38-
ProfileSampleConfigType,
3937
SampleConfig,
40-
StaticSamplingConfig,
4138
)
4239
from metadata.sampler.sampler_interface import SamplerInterface # noqa: TC001
4340
from metadata.utils.bigquery_utils import copy_service_config
@@ -126,15 +123,8 @@ def create_data_quality_interface(self) -> TestSuiteInterface:
126123
schema_entity=schema_entity,
127124
database_entity=database_entity,
128125
default_sample_config=SampleConfig(
129-
profileSampleConfig=ProfileSampleConfig(
130-
sampleConfigType=ProfileSampleConfigType.STATIC,
131-
config=StaticSamplingConfig(
132-
profileSample=self.source_config.profileSample,
133-
profileSampleType=self.source_config.profileSampleType,
134-
samplingMethodType=self.source_config.samplingMethodType,
135-
),
136-
)
137-
if self.source_config.profileSample
126+
profileSampleConfig=self.source_config.profileSampleConfig
127+
if self.source_config.profileSampleConfig
138128
else None,
139129
),
140130
)

ingestion/src/metadata/data_quality/validations/column/sqlalchemy/columnValuesToBeUnique.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def _run_results(self, metric: Metrics, column: Column) -> Optional[int]: # noq
7575
"""
7676
count = Metrics.valuesCount.value(column).fn()
7777
grouped_cte = (
78-
select(count.label(column.name)).select_from(self.runner.dataset).group_by(column).cte("grouped_cte")
78+
select(count.label(column.name)).select_from(self.runner.dataset).group_by(column).cte("grouped_cte") # type: ignore
7979
)
8080
unique_count = Metrics.uniqueCount.value(column).query(
8181
sample=self.runner.dataset,

ingestion/src/metadata/data_quality/validations/table/sqlalchemy/tableDiff.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
from metadata.profiler.orm.functions.md5 import MD5
5757
from metadata.profiler.orm.functions.substr import Substr
5858
from metadata.profiler.orm.registry import Dialects, PythonDialects
59+
from metadata.sampler.config import resolve_static_sampling_config
5960
from metadata.utils.collections import CaseInsensitiveList
6061
from metadata.utils.credentials import normalize_pem_string
6162
from metadata.utils.logger import test_suite_logger
@@ -443,9 +444,12 @@ def sample_where_clause(self) -> Tuple[Optional[str], Optional[str]]: # noqa: U
443444
return None, None
444445
profile_sample_config = config.profileSampleConfig if config else None
445446
sample_config = profile_sample_config.root if profile_sample_config else None
446-
static = sample_config.config if sample_config else None
447-
profile_sample = getattr(static, "profileSample", None) if static else None
448-
profile_sample_type = getattr(static, "profileSampleType", None) if static else None
447+
static = resolve_static_sampling_config(
448+
sample_config=sample_config,
449+
row_count=self.get_total_row_count(),
450+
)
451+
profile_sample = static.profileSample if static else None
452+
profile_sample_type = static.profileSampleType if static else None
449453
if profile_sample is None or (profile_sample_type == ProfileSampleType.PERCENTAGE and profile_sample == 100):
450454
return None, None
451455
if DatabaseServiceType.Mssql in [
@@ -490,16 +494,19 @@ def calculate_nounce(self, max_nounce=2**32 - 1) -> int:
490494
config = self.runtime_params.table_profile_config
491495
profile_sample_config = config.profileSampleConfig if config else None
492496
sample_config = profile_sample_config.root if profile_sample_config else None
493-
static = sample_config.config if sample_config else None
494-
profile_sample = getattr(static, "profileSample", 100)
495-
profile_sample_type = getattr(static, "profileSampleType", None)
497+
row_count = self.get_total_row_count()
498+
static = resolve_static_sampling_config(
499+
sample_config=sample_config,
500+
row_count=row_count,
501+
)
502+
profile_sample = static.profileSample if static else None
503+
profile_sample_type = static.profileSampleType if static else None
496504
if profile_sample_type == ProfileSampleType.PERCENTAGE:
497-
return int(max_nounce * profile_sample / 100)
505+
return int(max_nounce * ((profile_sample or 100) / 100))
498506
if profile_sample_type == ProfileSampleType.ROWS:
499-
row_count = self.get_total_row_count()
500507
if row_count is None:
501508
raise ValueError("Row count is required for ROWS profile sample type")
502-
return int(max_nounce * (profile_sample / row_count))
509+
return int(max_nounce * ((profile_sample or row_count) / row_count))
503510
raise ValueError("Invalid profile sample type")
504511

505512
def get_row_diff_test_case_result(

ingestion/src/metadata/great_expectations/action.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from typing import Dict, List, Optional, Union, cast # noqa: UP035
2323

2424
from great_expectations.checkpoint.actions import ValidationAction
25-
from great_expectations.core import ExpectationConfiguration
25+
from great_expectations.core import ExpectationConfiguration # type: ignore
2626
from great_expectations.core.batch import Batch
2727
from great_expectations.core.batch_spec import (
2828
RuntimeDataBatchSpec,
@@ -32,8 +32,8 @@
3232
from great_expectations.core.expectation_validation_result import (
3333
ExpectationSuiteValidationResult,
3434
)
35-
from great_expectations.data_asset.data_asset import DataAsset
36-
from great_expectations.data_context.data_context import DataContext
35+
from great_expectations.data_asset.data_asset import DataAsset # type: ignore
36+
from great_expectations.data_context.data_context import DataContext # type: ignore
3737

3838
from metadata.generated.schema.type.basic import Timestamp
3939

@@ -115,7 +115,7 @@ def __init__(
115115
table_name: Optional[str] = None, # noqa: UP045
116116
expectation_suite_table_config_map: Optional[Dict[str, Dict[str, str]]] = None, # noqa: UP006, UP045
117117
):
118-
super().__init__(data_context, name=name)
118+
super().__init__(data_context, name=name) # type: ignore
119119
self.database_service_name = database_service_name
120120
self.database_name = database_name
121121
self.table_name = table_name
@@ -153,7 +153,7 @@ def _run( # pylint: disable=unused-argument
153153
expectation_suite_name = None
154154

155155
if expectation_suite_identifier:
156-
expectation_suite_name = expectation_suite_identifier.expectation_suite_name
156+
expectation_suite_name = expectation_suite_identifier.expectation_suite_name # type: ignore
157157
self.expectation_suite = self.data_context.get_expectation_suite(expectation_suite_name)
158158

159159
check_point_spec = self._get_checkpoint_batch_spec(data_asset)
@@ -182,7 +182,7 @@ def _run( # pylint: disable=unused-argument
182182

183183
if table_entity:
184184
for result in validation_result_suite.results:
185-
self._handle_test_case(result, table_entity)
185+
self._handle_test_case(result, table_entity) # type: ignore
186186

187187
@staticmethod
188188
def _get_checkpoint_batch_spec(

ingestion/src/metadata/great_expectations/action1xx.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@
2222
from typing import Dict, List, Literal, Optional, Union, cast # noqa: UP035
2323

2424
from great_expectations.checkpoint import (
25-
ActionContext,
26-
CheckpointResult,
27-
ValidationAction,
25+
ActionContext, # type: ignore
26+
CheckpointResult, # type: ignore
27+
ValidationAction, # type: ignore
2828
)
2929
from great_expectations.core.batch import Batch
3030
from great_expectations.core.expectation_validation_result import (
3131
ExpectationSuiteValidationResultMeta,
3232
)
33-
from great_expectations.datasource.fluent import DataAsset
33+
from great_expectations.datasource.fluent import DataAsset # type: ignore
3434
from great_expectations.validator.validator import Validator
3535
from sqlalchemy.engine.base import Connection, Engine
3636
from sqlalchemy.engine.url import URL
@@ -83,7 +83,7 @@ class OpenMetadataValidationAction1xx(ValidationAction):
8383
Format: {"suite_name": {"database_name": "db", "schema_name": "schema", "table_name": "table"}}
8484
"""
8585

86-
type: Literal["open_metadata_validation_action"] = "open_metadata_validation_action"
86+
type: Literal["open_metadata_validation_action"] = "open_metadata_validation_action" # type: ignore
8787
name: str = "OpenMetadataValidationAction"
8888
config_file_path: Optional[str] = None # noqa: UP045
8989
database_service_name: Optional[str] = None # noqa: UP045
@@ -153,7 +153,7 @@ def run(
153153

154154
if table_entity:
155155
for result in v.results:
156-
self._handle_test_case(result, table_entity)
156+
self._handle_test_case(result, table_entity) # type: ignore
157157

158158
@staticmethod
159159
def _get_checkpoint_batch_spec(meta: Union[ExpectationSuiteValidationResultMeta, dict]): # noqa: UP007

ingestion/src/metadata/ingestion/source/dashboard/looker/metadata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def __read_manifest(
314314
# For remote repositories, clone the dependency as before
315315
url_parsed = giturlparse.parse(remote_git_url)
316316
_clone_repo(
317-
f"{url_parsed.owner}/{url_parsed.repo}", # pylint: disable=E1101
317+
f"{url_parsed.owner}/{url_parsed.repo}", # type: ignore
318318
f"{repo.path}/{IMPORTED_PROJECTS_DIR}/{remote_name}",
319319
credentials,
320320
)

ingestion/src/metadata/ingestion/source/dashboard/powerbi/metadata.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ def create_report_dashboard_lineage(
675675
) -> Iterable[Either[CreateDashboardRequest]]:
676676
"""Create lineage between report and dashboard"""
677677
try:
678+
logger.debug(f"Processing to create report and dashboard lineage for dashboard: {dashboard_details.id}")
678679
charts = dashboard_details.tiles
679680
dashboard_fqn = fqn.build(
680681
self.metadata,
@@ -686,9 +687,22 @@ def create_report_dashboard_lineage(
686687
entity=Dashboard,
687688
fqn=dashboard_fqn,
688689
)
690+
if not dashboard_entity:
691+
logger.debug(
692+
f"Dashboard entity not found to create lineage between report and dashboard for dashboard: {dashboard_details.id}"
693+
)
694+
return
689695
for chart in charts or []:
696+
if chart.reportId:
697+
logger.debug(f"Dashboard's chart {chart.id} is linked with report id: {str(chart.reportId)}") # noqa: RUF010
698+
else:
699+
logger.debug(f"Dashboard's chart {chart.id} is not linked with any report")
700+
continue
690701
report = self._fetch_report_from_workspace(chart.reportId)
691702
if report:
703+
logger.debug(
704+
f"Fetched report details for report id: {str(chart.reportId)} from workspace data to create lineage with dashboard: {dashboard_details.id}" # noqa: RUF010
705+
)
692706
report_fqn = fqn.build(
693707
self.metadata,
694708
entity_type=Dashboard,
@@ -699,9 +713,19 @@ def create_report_dashboard_lineage(
699713
entity=Dashboard,
700714
fqn=report_fqn,
701715
)
702-
716+
if not report_entity:
717+
logger.debug(
718+
f"Report entity not found to create lineage between report={report.id} and dashboard={dashboard_details.id}"
719+
)
703720
if report_entity and dashboard_entity:
721+
logger.debug(
722+
f"Creating lineage between report={report.id} and dashboard={dashboard_details.id}"
723+
)
704724
yield self._get_add_lineage_request(to_entity=dashboard_entity, from_entity=report_entity)
725+
else:
726+
logger.debug(
727+
f"Could not fetch report with report id: {str(chart.reportId)} from workspace data to create lineage with dashboard: {dashboard_details.id}" # noqa: RUF010
728+
)
705729
except Exception as exc: # pylint: disable=broad-except
706730
yield Either(
707731
left=StackTraceError(
@@ -729,6 +753,8 @@ def _get_dataset_ids_from_report_datasources(self, report_id: str) -> List[str]:
729753
)
730754
if match:
731755
dataset_ids.append(match.group(1))
756+
if dataset_ids:
757+
logger.debug(f"Extracted dataset IDs from report datasources API call for report_id={report_id}")
732758
return dataset_ids
733759

734760
def create_datamodel_report_lineage(
@@ -740,6 +766,7 @@ def create_datamodel_report_lineage(
740766
create the lineage between datamodel and report
741767
"""
742768
try:
769+
logger.debug(f"Processing to create datamodel and report lineage for report: {dashboard_details.id}")
743770
report_fqn = fqn.build(
744771
self.metadata,
745772
entity_type=Dashboard,
@@ -750,10 +777,19 @@ def create_datamodel_report_lineage(
750777
entity=Dashboard,
751778
fqn=report_fqn,
752779
)
780+
if not report_entity:
781+
logger.debug(
782+
f"Report entity not found to create lineage between datamodel and report for report: {dashboard_details.id}"
783+
)
784+
return
753785
dataset_ids = []
754786
if dashboard_details.datasetId:
787+
logger.debug(f"Report linked datasetId is present in api response for report: {dashboard_details.id}")
755788
dataset_ids = [dashboard_details.datasetId]
756789
else:
790+
logger.debug(
791+
f"Processing to get report datasources from API to extract datasetIds for report: {dashboard_details.id} as datasetId is not present in api response"
792+
)
757793
dataset_ids = self._get_dataset_ids_from_report_datasources(report_id=dashboard_details.id)
758794

759795
if dataset_ids:
@@ -768,6 +804,10 @@ def create_datamodel_report_lineage(
768804
entity=DashboardDataModel,
769805
fqn=datamodel_fqn,
770806
)
807+
if not datamodel_entity:
808+
logger.debug(
809+
f"Data model entity not found for dataset_id={str(dataset_id)} while creating lineage with report={str(dashboard_details.id)}" # noqa: RUF010
810+
)
771811
if datamodel_entity and report_entity:
772812
logger.debug(
773813
f"Creating lineage between datamodel={str(dataset_id)} and report={str(dashboard_details.id)}" # noqa: RUF010
@@ -778,7 +818,7 @@ def create_datamodel_report_lineage(
778818
)
779819
else:
780820
logger.debug(
781-
f"Skipping datamodel and report lineage for {dashboard_details.id} as datasetId is not found"
821+
f"Skipping datamodel and report lineage for report: {dashboard_details.id} as datasetId is not found on api response and also could not be extracted from report datasources API call"
782822
)
783823

784824
except Exception as exc: # pylint: disable=broad-except
@@ -2062,7 +2102,7 @@ def _fetch_dataset_from_workspace(self, dataset_id: Optional[str]) -> Optional[D
20622102
return dataset_data
20632103
return None
20642104

2065-
def _fetch_report_from_workspace(self, report_id: Optional[str]) -> Optional[Dataset]: # noqa: UP045
2105+
def _fetch_report_from_workspace(self, report_id: Optional[str]) -> Optional[PowerBIReport]: # noqa: UP045
20662106
"""
20672107
Method to search the report using id in the workspace dict
20682108
"""

0 commit comments

Comments
 (0)