acryl-datahub 0.15.0.5rc3__py3-none-any.whl → 0.15.0.5rc5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of acryl-datahub might be problematic. Click here for more details.
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/METADATA +2480 -2480
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/RECORD +15 -15
- datahub/_version.py +1 -1
- datahub/ingestion/source/aws/glue.py +2 -0
- datahub/ingestion/source/looker/looker_config.py +3 -1
- datahub/ingestion/source/looker/looker_dataclasses.py +8 -0
- datahub/ingestion/source/looker/looker_file_loader.py +14 -3
- datahub/ingestion/source/looker/looker_template_language.py +104 -14
- datahub/ingestion/source/looker/lookml_config.py +20 -3
- datahub/ingestion/source/looker/lookml_source.py +110 -22
- datahub/ingestion/source/snowflake/snowflake_v2.py +41 -4
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/LICENSE +0 -0
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/WHEEL +0 -0
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/entry_points.txt +0 -0
- {acryl_datahub-0.15.0.5rc3.dist-info → acryl_datahub-0.15.0.5rc5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
datahub/__init__.py,sha256=aq_i5lVREmoLfYIqcx_pEQicO855YlhD19tWc1eZZNI,59
|
|
2
2
|
datahub/__main__.py,sha256=pegIvQ9hzK7IhqVeUi1MeADSZ2QlP-D3K0OQdEg55RU,106
|
|
3
|
-
datahub/_version.py,sha256=
|
|
3
|
+
datahub/_version.py,sha256=k2KgFitDFziMKt2iil2MW_OYVP7lggtvH9A6OAJFD9c,324
|
|
4
4
|
datahub/entrypoints.py,sha256=osv2ailvuW-HHlAE0fOtyblJI1X7HInZutd9DC66jqQ,8022
|
|
5
5
|
datahub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
datahub/_codegen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -219,7 +219,7 @@ datahub/ingestion/source/abs/report.py,sha256=fzkTdTewYlWrTk4f2Cyl-e8RV4qw9wEVtm
|
|
|
219
219
|
datahub/ingestion/source/abs/source.py,sha256=cuMezUzr-Smp5tok2ceYor5I5jp52NDMjfeN8kfIbvg,24816
|
|
220
220
|
datahub/ingestion/source/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
221
221
|
datahub/ingestion/source/aws/aws_common.py,sha256=DfdQgkJ_s2isFx8WvqKTlAcBk4KE8SgfpmA5BgC3fgY,17716
|
|
222
|
-
datahub/ingestion/source/aws/glue.py,sha256=
|
|
222
|
+
datahub/ingestion/source/aws/glue.py,sha256=DwROr923M01QnvImUbMoHS6TTTT9kBz2tEmQ3Sv4EoY,58019
|
|
223
223
|
datahub/ingestion/source/aws/s3_boto_utils.py,sha256=Y54jlLV5gLcuZ4Zs57kIW5dYHD89RSFfsVNlFbRnSkQ,3901
|
|
224
224
|
datahub/ingestion/source/aws/s3_util.py,sha256=OFypcgmVC6jnZM90-gjcPpAMtTV1lbnreCaMhCzNlzs,2149
|
|
225
225
|
datahub/ingestion/source/aws/sagemaker.py,sha256=Bl2tkBYnrindgx61VHYgNovUF_Kp_fXNcivQn28vC2w,5254
|
|
@@ -333,22 +333,22 @@ datahub/ingestion/source/kafka_connect/source_connectors.py,sha256=-rFNXKD8_EFoX
|
|
|
333
333
|
datahub/ingestion/source/looker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
334
334
|
datahub/ingestion/source/looker/lkml_patched.py,sha256=XShEU7Wbz0DubDhYMjKf9wjKZrBJa2XPg9MIjp8rPhk,733
|
|
335
335
|
datahub/ingestion/source/looker/looker_common.py,sha256=squUUBHxsLeT5xbZOTO66irtOB8fL0V4Q8Tgd9EJMYU,62067
|
|
336
|
-
datahub/ingestion/source/looker/looker_config.py,sha256=
|
|
336
|
+
datahub/ingestion/source/looker/looker_config.py,sha256=eVKw1nn9D8hUFdRfNyT3MtzL8w-zWhFeokiwSnNKQuc,13607
|
|
337
337
|
datahub/ingestion/source/looker/looker_connection.py,sha256=yDmC6lDsHmL2e_Pw8ULylwOIHPWPp_6gT1iyLvD0fTw,2075
|
|
338
338
|
datahub/ingestion/source/looker/looker_constant.py,sha256=GMKYtNXlpojPxa9azridKfcGLSJwKdUCTesp7U8dIrQ,402
|
|
339
|
-
datahub/ingestion/source/looker/looker_dataclasses.py,sha256=
|
|
340
|
-
datahub/ingestion/source/looker/looker_file_loader.py,sha256=
|
|
339
|
+
datahub/ingestion/source/looker/looker_dataclasses.py,sha256=MrDeZ4Nd0wQnJbCoI1qePYlYeObnUw5dvpWcmhKuNgc,12346
|
|
340
|
+
datahub/ingestion/source/looker/looker_file_loader.py,sha256=PEyL9KWRaFcrvOkapU8wSNlFbmetmBy9tAyCgeVDOa4,4864
|
|
341
341
|
datahub/ingestion/source/looker/looker_lib_wrapper.py,sha256=0gaYjBv4wkbbLWVgvaAV6JyWAFb0utTG6TCve2d9xss,11511
|
|
342
342
|
datahub/ingestion/source/looker/looker_liquid_tag.py,sha256=mO4G4MNA4YZFvZaDBpdiJ2vP3irC82kY34RdaK4Pbfs,3100
|
|
343
343
|
datahub/ingestion/source/looker/looker_query_model.py,sha256=N0jBbFruiCIIGT6sJn6tNeppeQ78KGTkOwTLirhxFNc,2144
|
|
344
344
|
datahub/ingestion/source/looker/looker_source.py,sha256=S-g06Bm3sbyD0Qjra9hEhZmsVDb-BY_-bCPDwCjtEoQ,66427
|
|
345
|
-
datahub/ingestion/source/looker/looker_template_language.py,sha256=
|
|
345
|
+
datahub/ingestion/source/looker/looker_template_language.py,sha256=W-SMICKBfIuivrHywHRYchz9SJiXhoU8VOEKGQW_1v8,17825
|
|
346
346
|
datahub/ingestion/source/looker/looker_usage.py,sha256=qFBX7OHtIcarYIqFe0jQMrDV8MMPV_nN4PZrZRUznTw,23029
|
|
347
347
|
datahub/ingestion/source/looker/looker_view_id_cache.py,sha256=92gDy6NONhJYBp92z_IBzDVZvezmUIkaBCZY1bdk6mE,4392
|
|
348
348
|
datahub/ingestion/source/looker/lookml_concept_context.py,sha256=eDaze9S7cgO5eFP7-0azUMEJyR3EfMjmfj5pMPjpm8c,18066
|
|
349
|
-
datahub/ingestion/source/looker/lookml_config.py,sha256=
|
|
349
|
+
datahub/ingestion/source/looker/lookml_config.py,sha256=RuZkH3DDmII21gEsUvPsJi5gxWngbYkqBP06H8_n_Hs,11353
|
|
350
350
|
datahub/ingestion/source/looker/lookml_refinement.py,sha256=MkVreI0BylaCFyDHihDHaCcXyDSP84eF9p1h5d-ZHnM,9504
|
|
351
|
-
datahub/ingestion/source/looker/lookml_source.py,sha256=
|
|
351
|
+
datahub/ingestion/source/looker/lookml_source.py,sha256=PJBUJgZfZyvmasDf_LJC39SggLCA6vSfAbf1PdzviZU,43889
|
|
352
352
|
datahub/ingestion/source/looker/str_functions.py,sha256=zceEX2ka_4WaWwWgEdyknUSz7X3GrO951BkwSbF2afo,766
|
|
353
353
|
datahub/ingestion/source/looker/urn_functions.py,sha256=4VvqEfGvIMq3rNHHps0-HlPurMPnpqdxNtDAOOHIZww,528
|
|
354
354
|
datahub/ingestion/source/looker/view_upstream.py,sha256=4FCjZaU6p2G7npB2RJpP4Gv2yLjbvbsYWEbAg55IvjY,26110
|
|
@@ -446,7 +446,7 @@ datahub/ingestion/source/snowflake/snowflake_summary.py,sha256=kTmuCtRnvHqM8WBYh
|
|
|
446
446
|
datahub/ingestion/source/snowflake/snowflake_tag.py,sha256=TN_cTF4a8V_tbeR2czm_hoMYfQMuqmBbFlAqyh7PJzQ,6551
|
|
447
447
|
datahub/ingestion/source/snowflake/snowflake_usage_v2.py,sha256=ySFm7WDk8FW9KjCnX4HQfTqObIrlUS-V8WIHl3j0CTI,24848
|
|
448
448
|
datahub/ingestion/source/snowflake/snowflake_utils.py,sha256=xq58c47zmaQPkTVqjKW25iViX8VJuHdQDTFY4jxzZ2o,12778
|
|
449
|
-
datahub/ingestion/source/snowflake/snowflake_v2.py,sha256=
|
|
449
|
+
datahub/ingestion/source/snowflake/snowflake_v2.py,sha256=vyTqC_C5Bf0AMRVyoxUfl1CdlgeQouX20msP2FsMqnk,33439
|
|
450
450
|
datahub/ingestion/source/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
451
451
|
datahub/ingestion/source/sql/athena.py,sha256=Uh9wGLOqAkcphffxOPIQNyXvjeRm74XIpaLb4rjqMjM,24045
|
|
452
452
|
datahub/ingestion/source/sql/clickhouse.py,sha256=uSRy-HKAiGFTHVLoVtGoh23X0O1lwyYUaK8BaWkYhps,25555
|
|
@@ -993,9 +993,9 @@ datahub_provider/operators/datahub_assertion_operator.py,sha256=uvTQ-jk2F0sbqqxp
|
|
|
993
993
|
datahub_provider/operators/datahub_assertion_sensor.py,sha256=lCBj_3x1cf5GMNpHdfkpHuyHfVxsm6ff5x2Z5iizcAo,140
|
|
994
994
|
datahub_provider/operators/datahub_operation_operator.py,sha256=aevDp2FzX7FxGlXrR0khoHNbxbhKR2qPEX5e8O2Jyzw,174
|
|
995
995
|
datahub_provider/operators/datahub_operation_sensor.py,sha256=8fcdVBCEPgqy1etTXgLoiHoJrRt_nzFZQMdSzHqSG7M,168
|
|
996
|
-
acryl_datahub-0.15.0.
|
|
997
|
-
acryl_datahub-0.15.0.
|
|
998
|
-
acryl_datahub-0.15.0.
|
|
999
|
-
acryl_datahub-0.15.0.
|
|
1000
|
-
acryl_datahub-0.15.0.
|
|
1001
|
-
acryl_datahub-0.15.0.
|
|
996
|
+
acryl_datahub-0.15.0.5rc5.dist-info/LICENSE,sha256=9xNHpsD0uYF5ONzXsKDCuHHB-xbiCrSbueWXqrTNsxk,11365
|
|
997
|
+
acryl_datahub-0.15.0.5rc5.dist-info/METADATA,sha256=iUCOkI7iz8GUQSvFsn9nLdzi1GxoElLbxrV96MnC9BM,173382
|
|
998
|
+
acryl_datahub-0.15.0.5rc5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
999
|
+
acryl_datahub-0.15.0.5rc5.dist-info/entry_points.txt,sha256=xnPSPLK3bJGADxe4TDS4wL4u0FT_PGlahDa-ENYdYCQ,9512
|
|
1000
|
+
acryl_datahub-0.15.0.5rc5.dist-info/top_level.txt,sha256=iLjSrLK5ox1YVYcglRUkcvfZPvKlobBWx7CTUXx8_GI,25
|
|
1001
|
+
acryl_datahub-0.15.0.5rc5.dist-info/RECORD,,
|
datahub/_version.py
CHANGED
|
@@ -218,6 +218,7 @@ class GlueSourceConfig(
|
|
|
218
218
|
|
|
219
219
|
@dataclass
|
|
220
220
|
class GlueSourceReport(StaleEntityRemovalSourceReport):
|
|
221
|
+
catalog_id: Optional[str] = None
|
|
221
222
|
tables_scanned = 0
|
|
222
223
|
filtered: List[str] = dataclass_field(default_factory=list)
|
|
223
224
|
databases: EntityFilterReport = EntityFilterReport.field(type="database")
|
|
@@ -315,6 +316,7 @@ class GlueSource(StatefulIngestionSourceBase):
|
|
|
315
316
|
self.extract_owners = config.extract_owners
|
|
316
317
|
self.source_config = config
|
|
317
318
|
self.report = GlueSourceReport()
|
|
319
|
+
self.report.catalog_id = self.source_config.catalog_id
|
|
318
320
|
self.glue_client = config.glue_client
|
|
319
321
|
self.s3_client = config.s3_client
|
|
320
322
|
self.extract_transforms = config.extract_transforms
|
|
@@ -177,7 +177,9 @@ def _get_generic_definition(
|
|
|
177
177
|
class LookerConnectionDefinition(ConfigModel):
|
|
178
178
|
platform: str
|
|
179
179
|
default_db: str
|
|
180
|
-
default_schema: Optional[str]
|
|
180
|
+
default_schema: Optional[str] = (
|
|
181
|
+
None # Optional since some sources are two-level only
|
|
182
|
+
)
|
|
181
183
|
platform_instance: Optional[str] = None
|
|
182
184
|
platform_env: Optional[str] = Field(
|
|
183
185
|
default=None,
|
|
@@ -32,6 +32,12 @@ class LookerField:
|
|
|
32
32
|
sql: Optional[str]
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
@dataclass
|
|
36
|
+
class LookerConstant:
|
|
37
|
+
name: str
|
|
38
|
+
value: str
|
|
39
|
+
|
|
40
|
+
|
|
35
41
|
@dataclass
|
|
36
42
|
class LookerModel:
|
|
37
43
|
connection: str
|
|
@@ -75,6 +81,7 @@ class LookerModel:
|
|
|
75
81
|
try:
|
|
76
82
|
parsed = load_and_preprocess_file(
|
|
77
83
|
path=included_file,
|
|
84
|
+
reporter=reporter,
|
|
78
85
|
source_config=source_config,
|
|
79
86
|
)
|
|
80
87
|
included_explores = parsed.get("explores", [])
|
|
@@ -217,6 +224,7 @@ class LookerModel:
|
|
|
217
224
|
try:
|
|
218
225
|
parsed = load_and_preprocess_file(
|
|
219
226
|
path=included_file,
|
|
227
|
+
reporter=reporter,
|
|
220
228
|
source_config=source_config,
|
|
221
229
|
)
|
|
222
230
|
seen_so_far.add(included_file)
|
|
@@ -4,7 +4,10 @@ from dataclasses import replace
|
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
6
|
from datahub.ingestion.source.looker.looker_config import LookerConnectionDefinition
|
|
7
|
-
from datahub.ingestion.source.looker.looker_dataclasses import
|
|
7
|
+
from datahub.ingestion.source.looker.looker_dataclasses import (
|
|
8
|
+
LookerConstant,
|
|
9
|
+
LookerViewFile,
|
|
10
|
+
)
|
|
8
11
|
from datahub.ingestion.source.looker.looker_template_language import (
|
|
9
12
|
load_and_preprocess_file,
|
|
10
13
|
)
|
|
@@ -30,12 +33,14 @@ class LookerViewFileLoader:
|
|
|
30
33
|
base_projects_folder: Dict[str, pathlib.Path],
|
|
31
34
|
reporter: LookMLSourceReport,
|
|
32
35
|
source_config: LookMLSourceConfig,
|
|
36
|
+
manifest_constants: Dict[str, LookerConstant] = {},
|
|
33
37
|
) -> None:
|
|
34
38
|
self.viewfile_cache: Dict[str, Optional[LookerViewFile]] = {}
|
|
35
39
|
self._root_project_name = root_project_name
|
|
36
40
|
self._base_projects_folder = base_projects_folder
|
|
37
41
|
self.reporter = reporter
|
|
38
42
|
self.source_config = source_config
|
|
43
|
+
self.manifest_constants = manifest_constants
|
|
39
44
|
|
|
40
45
|
def _load_viewfile(
|
|
41
46
|
self, project_name: str, path: str, reporter: LookMLSourceReport
|
|
@@ -60,7 +65,7 @@ class LookerViewFileLoader:
|
|
|
60
65
|
with open(path) as file:
|
|
61
66
|
raw_file_content = file.read()
|
|
62
67
|
except Exception as e:
|
|
63
|
-
self.reporter.
|
|
68
|
+
self.reporter.report_warning(
|
|
64
69
|
title="LKML File Loading Error",
|
|
65
70
|
message="A lookml file is not present on local storage or GitHub",
|
|
66
71
|
context=f"file path: {path}",
|
|
@@ -71,9 +76,15 @@ class LookerViewFileLoader:
|
|
|
71
76
|
try:
|
|
72
77
|
logger.debug(f"Loading viewfile {path}")
|
|
73
78
|
|
|
79
|
+
# load_and preprocess_file is called multiple times for loading view file from multiple flows.
|
|
80
|
+
# Flag resolve_constants is a hack to avoid passing around manifest_constants from all of the flows.
|
|
81
|
+
# This is fine as rest of flows do not need resolution of constants.
|
|
74
82
|
parsed = load_and_preprocess_file(
|
|
75
83
|
path=path,
|
|
84
|
+
reporter=self.reporter,
|
|
76
85
|
source_config=self.source_config,
|
|
86
|
+
resolve_constants=True,
|
|
87
|
+
manifest_constants=self.manifest_constants,
|
|
77
88
|
)
|
|
78
89
|
|
|
79
90
|
looker_viewfile = LookerViewFile.from_looker_dict(
|
|
@@ -90,7 +101,7 @@ class LookerViewFileLoader:
|
|
|
90
101
|
self.viewfile_cache[path] = looker_viewfile
|
|
91
102
|
return looker_viewfile
|
|
92
103
|
except Exception as e:
|
|
93
|
-
self.reporter.
|
|
104
|
+
self.reporter.report_warning(
|
|
94
105
|
title="LKML File Parsing Error",
|
|
95
106
|
message="The input file is not lookml file",
|
|
96
107
|
context=f"file path: {path}",
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
import pathlib
|
|
3
3
|
import re
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
|
-
from typing import Any, ClassVar, Dict, List, Optional, Set, Union
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Set, Union
|
|
6
6
|
|
|
7
7
|
from deepmerge import always_merger
|
|
8
8
|
from liquid import Undefined
|
|
@@ -27,8 +27,12 @@ from datahub.ingestion.source.looker.looker_liquid_tag import (
|
|
|
27
27
|
from datahub.ingestion.source.looker.lookml_config import (
|
|
28
28
|
DERIVED_VIEW_PATTERN,
|
|
29
29
|
LookMLSourceConfig,
|
|
30
|
+
LookMLSourceReport,
|
|
30
31
|
)
|
|
31
32
|
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from datahub.ingestion.source.looker.looker_dataclasses import LookerConstant
|
|
35
|
+
|
|
32
36
|
logger = logging.getLogger(__name__)
|
|
33
37
|
|
|
34
38
|
|
|
@@ -82,7 +86,12 @@ class SpecialVariable:
|
|
|
82
86
|
return self._create_new_liquid_variables_with_default(variables=variables)
|
|
83
87
|
|
|
84
88
|
|
|
85
|
-
def resolve_liquid_variable(
|
|
89
|
+
def resolve_liquid_variable(
|
|
90
|
+
text: str,
|
|
91
|
+
view_name: str,
|
|
92
|
+
liquid_variable: Dict[Any, Any],
|
|
93
|
+
report: LookMLSourceReport,
|
|
94
|
+
) -> str:
|
|
86
95
|
# Set variable value to NULL if not present in liquid_variable dictionary
|
|
87
96
|
Undefined.__str__ = lambda instance: "NULL" # type: ignore
|
|
88
97
|
try:
|
|
@@ -96,6 +105,7 @@ def resolve_liquid_variable(text: str, liquid_variable: Dict[Any, Any]) -> str:
|
|
|
96
105
|
# Resolve liquid template
|
|
97
106
|
return create_template(text).render(liquid_variable)
|
|
98
107
|
except LiquidSyntaxError as e:
|
|
108
|
+
# TODO: Will add warning once we get rid of duplcate warning message for same view
|
|
99
109
|
logger.warning(f"Unsupported liquid template encountered. error [{e.message}]")
|
|
100
110
|
# TODO: There are some tag specific to looker and python-liquid library does not understand them. currently
|
|
101
111
|
# we are not parsing such liquid template.
|
|
@@ -103,6 +113,7 @@ def resolve_liquid_variable(text: str, liquid_variable: Dict[Any, Any]) -> str:
|
|
|
103
113
|
# See doc: https://cloud.google.com/looker/docs/templated-filters and look for { % condition region %}
|
|
104
114
|
# order.region { % endcondition %}
|
|
105
115
|
except CustomTagException as e:
|
|
116
|
+
# TODO: Will add warning once we get rid of duplcate warning message for same view
|
|
106
117
|
logger.warning(e)
|
|
107
118
|
logger.debug(e, exc_info=e)
|
|
108
119
|
|
|
@@ -192,15 +203,20 @@ class LookMLViewTransformer(ABC):
|
|
|
192
203
|
|
|
193
204
|
source_config: LookMLSourceConfig
|
|
194
205
|
|
|
195
|
-
def __init__(
|
|
206
|
+
def __init__(
|
|
207
|
+
self,
|
|
208
|
+
source_config: LookMLSourceConfig,
|
|
209
|
+
reporter: LookMLSourceReport,
|
|
210
|
+
):
|
|
196
211
|
self.source_config = source_config
|
|
212
|
+
self.reporter = reporter
|
|
197
213
|
|
|
198
214
|
def transform(self, view: dict) -> dict:
|
|
199
215
|
value_to_transform: Optional[str] = None
|
|
200
216
|
|
|
201
|
-
# is_attribute_supported check is required because not all
|
|
202
|
-
#
|
|
203
|
-
# however IncompleteSqlTransformer only transform the derived.sql attribute
|
|
217
|
+
# is_attribute_supported check is required because not all transformers work on all attributes in the current
|
|
218
|
+
# case, mostly all transformers work on sql_table_name and derived.sql attributes;
|
|
219
|
+
# however, IncompleteSqlTransformer only transform the derived.sql attribute
|
|
204
220
|
if SQL_TABLE_NAME in view and self.is_attribute_supported(SQL_TABLE_NAME):
|
|
205
221
|
# Give precedence to already processed transformed view.sql_table_name to apply more transformation
|
|
206
222
|
value_to_transform = view.get(
|
|
@@ -252,7 +268,9 @@ class LiquidVariableTransformer(LookMLViewTransformer):
|
|
|
252
268
|
def _apply_transformation(self, value: str, view: dict) -> str:
|
|
253
269
|
return resolve_liquid_variable(
|
|
254
270
|
text=value,
|
|
255
|
-
liquid_variable=self.source_config.
|
|
271
|
+
liquid_variable=self.source_config.liquid_variables,
|
|
272
|
+
view_name=view["name"],
|
|
273
|
+
report=self.reporter,
|
|
256
274
|
)
|
|
257
275
|
|
|
258
276
|
|
|
@@ -287,7 +305,7 @@ class IncompleteSqlTransformer(LookMLViewTransformer):
|
|
|
287
305
|
|
|
288
306
|
class DropDerivedViewPatternTransformer(LookMLViewTransformer):
|
|
289
307
|
"""
|
|
290
|
-
drop ${} from datahub_transformed_sql_table_name and
|
|
308
|
+
drop ${} from datahub_transformed_sql_table_name and view["derived_table"]["datahub_transformed_sql_table_name"] values.
|
|
291
309
|
|
|
292
310
|
Example: transform ${employee_income_source.SQL_TABLE_NAME} to employee_income_source.SQL_TABLE_NAME
|
|
293
311
|
"""
|
|
@@ -308,8 +326,8 @@ class LookMlIfCommentTransformer(LookMLViewTransformer):
|
|
|
308
326
|
evaluate_to_true_regx: str
|
|
309
327
|
remove_if_comment_line_regx: str
|
|
310
328
|
|
|
311
|
-
def __init__(self, source_config: LookMLSourceConfig):
|
|
312
|
-
super().__init__(source_config=source_config)
|
|
329
|
+
def __init__(self, source_config: LookMLSourceConfig, reporter: LookMLSourceReport):
|
|
330
|
+
super().__init__(source_config=source_config, reporter=reporter)
|
|
313
331
|
|
|
314
332
|
# This regx will keep whatever after -- if looker_environment --
|
|
315
333
|
self.evaluate_to_true_regx = r"-- if {} --".format(
|
|
@@ -335,6 +353,61 @@ class LookMlIfCommentTransformer(LookMLViewTransformer):
|
|
|
335
353
|
return self._apply_regx(value)
|
|
336
354
|
|
|
337
355
|
|
|
356
|
+
class LookmlConstantTransformer(LookMLViewTransformer):
|
|
357
|
+
"""
|
|
358
|
+
Replace LookML constants @{constant} from the manifest/configuration.
|
|
359
|
+
"""
|
|
360
|
+
|
|
361
|
+
CONSTANT_PATTERN = r"@{(\w+)}" # Matches @{constant}
|
|
362
|
+
|
|
363
|
+
def __init__(
|
|
364
|
+
self,
|
|
365
|
+
source_config: LookMLSourceConfig,
|
|
366
|
+
reporter: LookMLSourceReport,
|
|
367
|
+
manifest_constants: Dict[str, "LookerConstant"],
|
|
368
|
+
):
|
|
369
|
+
super().__init__(source_config=source_config, reporter=reporter)
|
|
370
|
+
self.manifest_constants = manifest_constants
|
|
371
|
+
|
|
372
|
+
def resolve_lookml_constant(self, text: str, view_name: Optional[str]) -> str:
|
|
373
|
+
"""
|
|
374
|
+
Resolves LookML constants (@{ }) from manifest or config.
|
|
375
|
+
Logs warnings for misplaced or missing variables.
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
def replace_constants(match):
|
|
379
|
+
key = match.group(1)
|
|
380
|
+
# Resolve constant from config
|
|
381
|
+
if key in self.source_config.lookml_constants:
|
|
382
|
+
return str(self.source_config.lookml_constants.get(key))
|
|
383
|
+
|
|
384
|
+
# Resolve constant from manifest
|
|
385
|
+
if key in self.manifest_constants:
|
|
386
|
+
return self.manifest_constants[key].value
|
|
387
|
+
|
|
388
|
+
# Check if it's a misplaced lookml constant
|
|
389
|
+
if key in self.source_config.liquid_variables:
|
|
390
|
+
self.reporter.warning(
|
|
391
|
+
title="Misplaced lookml constant",
|
|
392
|
+
message="Use 'lookml_constants' instead of 'liquid_variables'.",
|
|
393
|
+
context=f"Key {key}",
|
|
394
|
+
)
|
|
395
|
+
return f"@{{{key}}}"
|
|
396
|
+
|
|
397
|
+
self.reporter.warning(
|
|
398
|
+
title="LookML constant not found",
|
|
399
|
+
message="The constant is missing. Either add it under 'lookml_constants' in the config or define it in `manifest.lkml`.",
|
|
400
|
+
context=f"view-name: {view_name}, constant: {key}",
|
|
401
|
+
)
|
|
402
|
+
return f"@{{{key}}}"
|
|
403
|
+
|
|
404
|
+
# Resolve @{} (constant)
|
|
405
|
+
return re.sub(self.CONSTANT_PATTERN, replace_constants, text)
|
|
406
|
+
|
|
407
|
+
def _apply_transformation(self, value: str, view: dict) -> str:
|
|
408
|
+
return self.resolve_lookml_constant(text=value, view_name=view.get("name"))
|
|
409
|
+
|
|
410
|
+
|
|
338
411
|
class TransformedLookMlView:
|
|
339
412
|
"""
|
|
340
413
|
TransformedLookMlView is collecting output of LookMLViewTransformer and creating a new transformed LookML view.
|
|
@@ -390,24 +463,35 @@ class TransformedLookMlView:
|
|
|
390
463
|
def process_lookml_template_language(
|
|
391
464
|
source_config: LookMLSourceConfig,
|
|
392
465
|
view_lkml_file_dict: dict,
|
|
466
|
+
reporter: LookMLSourceReport,
|
|
467
|
+
manifest_constants: Dict[str, "LookerConstant"] = {},
|
|
468
|
+
resolve_constants: bool = False,
|
|
393
469
|
) -> None:
|
|
394
470
|
if "views" not in view_lkml_file_dict:
|
|
395
471
|
return
|
|
396
472
|
|
|
397
473
|
transformers: List[LookMLViewTransformer] = [
|
|
398
474
|
LookMlIfCommentTransformer(
|
|
399
|
-
source_config=source_config
|
|
475
|
+
source_config=source_config, reporter=reporter
|
|
400
476
|
), # First evaluate the -- if -- comments. Looker does the same
|
|
401
477
|
LiquidVariableTransformer(
|
|
402
|
-
source_config=source_config
|
|
478
|
+
source_config=source_config, reporter=reporter
|
|
403
479
|
), # Now resolve liquid variables
|
|
404
480
|
DropDerivedViewPatternTransformer(
|
|
405
|
-
source_config=source_config
|
|
481
|
+
source_config=source_config, reporter=reporter
|
|
406
482
|
), # Remove any ${} symbol
|
|
407
483
|
IncompleteSqlTransformer(
|
|
408
|
-
source_config=source_config
|
|
484
|
+
source_config=source_config, reporter=reporter
|
|
409
485
|
), # complete any incomplete sql
|
|
410
486
|
]
|
|
487
|
+
if resolve_constants:
|
|
488
|
+
transformers.append(
|
|
489
|
+
LookmlConstantTransformer(
|
|
490
|
+
source_config=source_config,
|
|
491
|
+
manifest_constants=manifest_constants,
|
|
492
|
+
reporter=reporter,
|
|
493
|
+
), # Resolve @{} constant with its corresponding value
|
|
494
|
+
)
|
|
411
495
|
|
|
412
496
|
transformed_views: List[dict] = []
|
|
413
497
|
|
|
@@ -422,12 +506,18 @@ def process_lookml_template_language(
|
|
|
422
506
|
def load_and_preprocess_file(
|
|
423
507
|
path: Union[str, pathlib.Path],
|
|
424
508
|
source_config: LookMLSourceConfig,
|
|
509
|
+
reporter: LookMLSourceReport,
|
|
510
|
+
manifest_constants: Dict[str, "LookerConstant"] = {},
|
|
511
|
+
resolve_constants: bool = False,
|
|
425
512
|
) -> dict:
|
|
426
513
|
parsed = load_lkml(path)
|
|
427
514
|
|
|
428
515
|
process_lookml_template_language(
|
|
429
516
|
view_lkml_file_dict=parsed,
|
|
517
|
+
reporter=reporter,
|
|
430
518
|
source_config=source_config,
|
|
519
|
+
manifest_constants=manifest_constants,
|
|
520
|
+
resolve_constants=resolve_constants,
|
|
431
521
|
)
|
|
432
522
|
|
|
433
523
|
return parsed
|
|
@@ -139,7 +139,10 @@ class LookMLSourceConfig(
|
|
|
139
139
|
)
|
|
140
140
|
emit_reachable_views_only: bool = Field(
|
|
141
141
|
True,
|
|
142
|
-
description=
|
|
142
|
+
description=(
|
|
143
|
+
"When enabled, only views that are reachable from explores defined in the model files are emitted. "
|
|
144
|
+
"If set to False, all views imported in model files are emitted. Views that are unreachable i.e. not explicitly defined in the model files are currently not emitted however reported as warning for debugging purposes."
|
|
145
|
+
),
|
|
143
146
|
)
|
|
144
147
|
populate_sql_logic_for_missing_descriptions: bool = Field(
|
|
145
148
|
False,
|
|
@@ -158,13 +161,27 @@ class LookMLSourceConfig(
|
|
|
158
161
|
description="When enabled, looker refinement will be processed to adapt an existing view.",
|
|
159
162
|
)
|
|
160
163
|
|
|
161
|
-
|
|
164
|
+
liquid_variables: Dict[Any, Any] = Field(
|
|
162
165
|
{},
|
|
163
|
-
description="A dictionary containing Liquid variables
|
|
166
|
+
description="A dictionary containing Liquid variables with their corresponding values, utilized in SQL-defined "
|
|
164
167
|
"derived views. The Liquid template will be resolved in view.derived_table.sql and "
|
|
165
168
|
"view.sql_table_name. Defaults to an empty dictionary.",
|
|
166
169
|
)
|
|
167
170
|
|
|
171
|
+
_liquid_variable_deprecated = pydantic_renamed_field(
|
|
172
|
+
old_name="liquid_variable", new_name="liquid_variables", print_warning=True
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
lookml_constants: Dict[str, str] = Field(
|
|
176
|
+
{},
|
|
177
|
+
description=(
|
|
178
|
+
"A dictionary containing LookML constants (`@{constant_name}`) and their values. "
|
|
179
|
+
"If a constant is defined in the `manifest.lkml` file, its value will be used. "
|
|
180
|
+
"If not found in the manifest, the value from this config will be used instead. "
|
|
181
|
+
"Defaults to an empty dictionary."
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
|
|
168
185
|
looker_environment: Literal["prod", "dev"] = Field(
|
|
169
186
|
"prod",
|
|
170
187
|
description="A looker prod or dev environment. "
|