gooddata-dbt 1.60.1.dev1__tar.gz → 1.60.1.dev2__tar.gz
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.
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/PKG-INFO +2 -2
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/pyproject.toml +11 -2
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/base.py +1 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/metrics.py +6 -7
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/profiles.py +3 -3
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/tables.py +32 -30
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt_plugin.py +4 -5
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/gooddata/config.py +3 -4
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/sdk_wrapper.py +3 -4
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/dbt_target/manifest.json +19 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/airports.yaml +3 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/test_tables.py +32 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tox.ini +1 -1
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/.env.custom.dev +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/.env.dev +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/.gitignore +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/LICENSE.txt +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/Makefile +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/README.md +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/bin/gooddata-dbt +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/gooddata_example.yml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/__init__.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/_version.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/args.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/__init__.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/cloud.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/dbt/environment.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/gooddata/__init__.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/gooddata/api_wrapper.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/logger.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/main.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/utils.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/conftest.py +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/gooddata_example.yml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/dbt_profiles/profiles.yml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/aircraft.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/aircraft_models.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/ambient_temperature.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/carriers.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/census.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/census_by_country.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/commits.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/customer.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/eshop_customers.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/flights.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/home_rentals.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/house_property_sales_time_series.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/mall_customers.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/monthlyinventory.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/order_lines.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/orders.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/product.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/pull_requests.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/repos.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/returns.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/telco_customer_churn.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/users.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/gooddata_layouts/pdm/workflow_runs.yaml +0 -0
- {gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/test_profiles.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gooddata-dbt
|
|
3
|
-
Version: 1.60.1.
|
|
3
|
+
Version: 1.60.1.dev2
|
|
4
4
|
Summary: dbt plugin for GoodData
|
|
5
5
|
Author-email: GoodData <support@gooddata.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,7 @@ Classifier: Typing :: Typed
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Requires-Dist: attrs<=24.2.0,>=21.4.0
|
|
21
21
|
Requires-Dist: cattrs<=24.1.1,>=22.1.0
|
|
22
|
-
Requires-Dist: gooddata-sdk~=1.60.1.
|
|
22
|
+
Requires-Dist: gooddata-sdk~=1.60.1.dev2
|
|
23
23
|
Requires-Dist: pyyaml>=6.0
|
|
24
24
|
Requires-Dist: requests~=2.32.0
|
|
25
25
|
Requires-Dist: tabulate~=0.8.10
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# (C) 2025 GoodData Corporation
|
|
2
2
|
[project]
|
|
3
3
|
name = "gooddata-dbt"
|
|
4
|
-
version = "1.60.1.
|
|
4
|
+
version = "1.60.1.dev2"
|
|
5
5
|
description = "dbt plugin for GoodData"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
@@ -10,7 +10,7 @@ authors = [
|
|
|
10
10
|
]
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
dependencies = [
|
|
13
|
-
"gooddata-sdk~=1.60.1.
|
|
13
|
+
"gooddata-sdk~=1.60.1.dev2",
|
|
14
14
|
"pyyaml>=6.0",
|
|
15
15
|
"attrs>=21.4.0,<=24.2.0",
|
|
16
16
|
"cattrs>=22.1.0,<=24.1.1",
|
|
@@ -47,6 +47,15 @@ allowed-unresolved-imports = ["deep_translator", "github"]
|
|
|
47
47
|
[tool.hatch.build.targets.wheel]
|
|
48
48
|
packages = ["src/gooddata_dbt"]
|
|
49
49
|
|
|
50
|
+
[tool.coverage.run]
|
|
51
|
+
source = ["gooddata_dbt"]
|
|
52
|
+
|
|
53
|
+
[tool.coverage.paths]
|
|
54
|
+
source = [
|
|
55
|
+
"src/gooddata_dbt",
|
|
56
|
+
"**/site-packages/gooddata_dbt",
|
|
57
|
+
]
|
|
58
|
+
|
|
50
59
|
[build-system]
|
|
51
60
|
requires = ["hatchling"]
|
|
52
61
|
build-backend = "hatchling.build"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# (C) 2023 GoodData Corporation
|
|
2
2
|
import json
|
|
3
3
|
import re
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
import attrs
|
|
7
6
|
from gooddata_sdk import CatalogDeclarativeMetric, CatalogDeclarativeModel
|
|
@@ -26,8 +25,8 @@ DBT_TO_GD_FILTER_OPERATORS = {
|
|
|
26
25
|
|
|
27
26
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
28
27
|
class DbtModelMetaGoodDataMetricProps(Base):
|
|
29
|
-
model_id:
|
|
30
|
-
format:
|
|
28
|
+
model_id: str | None = None
|
|
29
|
+
format: str | None = None
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
@@ -49,11 +48,11 @@ class DbtModelMetric(DbtModelBase):
|
|
|
49
48
|
model: str
|
|
50
49
|
calculation_method: str
|
|
51
50
|
expression: str
|
|
52
|
-
filters:
|
|
51
|
+
filters: list[DbtModelMetricFilter] | None = None
|
|
53
52
|
|
|
54
53
|
|
|
55
54
|
class DbtModelMetrics:
|
|
56
|
-
def __init__(self, model_ids:
|
|
55
|
+
def __init__(self, model_ids: list[str] | None, ldm: CatalogDeclarativeModel) -> None:
|
|
57
56
|
self.model_ids = model_ids
|
|
58
57
|
self.ldm = ldm
|
|
59
58
|
with open(DBT_PATH_TO_MANIFEST) as fp:
|
|
@@ -104,7 +103,7 @@ class DbtModelMetrics:
|
|
|
104
103
|
else:
|
|
105
104
|
raise Exception(f"Unsupported entity type {table_name=} {expression_entity=}")
|
|
106
105
|
|
|
107
|
-
def make_entity_id(self, table_name: str, token: str) ->
|
|
106
|
+
def make_entity_id(self, table_name: str, token: str) -> str | None:
|
|
108
107
|
entity_type = self.get_entity_type(table_name, token)
|
|
109
108
|
if not entity_type:
|
|
110
109
|
return None
|
|
@@ -125,7 +124,7 @@ class DbtModelMetrics:
|
|
|
125
124
|
result_tokens.append(entity_id or token)
|
|
126
125
|
return " ".join(result_tokens)
|
|
127
126
|
|
|
128
|
-
def make_gooddata_filter(self, table_name: str, dbt_filters:
|
|
127
|
+
def make_gooddata_filter(self, table_name: str, dbt_filters: list[DbtModelMetricFilter] | None = None) -> str:
|
|
129
128
|
# TODO - Quite naive implementation
|
|
130
129
|
# e.g. missing polishing of values (e.g. SQL vs MAQL enclosers)
|
|
131
130
|
gd_maql_filters = []
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import argparse
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Union
|
|
6
6
|
from urllib.parse import quote_plus
|
|
7
7
|
|
|
8
8
|
import attrs
|
|
@@ -97,7 +97,7 @@ class DbtOutputSnowflake(Base):
|
|
|
97
97
|
database: str
|
|
98
98
|
warehouse: str
|
|
99
99
|
schema: str
|
|
100
|
-
query_tag:
|
|
100
|
+
query_tag: str | None = None
|
|
101
101
|
|
|
102
102
|
def to_gooddata(self, data_source_id: str, schema_name: str) -> CatalogDataSourceSnowflake:
|
|
103
103
|
return CatalogDataSourceSnowflake(
|
|
@@ -222,7 +222,7 @@ class DbtProfiles:
|
|
|
222
222
|
# else do nothing, real value seems to be stored in dbt profile
|
|
223
223
|
|
|
224
224
|
@staticmethod
|
|
225
|
-
def to_data_class(output: str, output_def: dict) ->
|
|
225
|
+
def to_data_class(output: str, output_def: dict) -> DbtOutput | None:
|
|
226
226
|
db_type = output_def["type"]
|
|
227
227
|
if db_type == "postgres":
|
|
228
228
|
return DbtOutputPostgreSQL.from_dict({"name": output, **output_def})
|
|
@@ -3,7 +3,7 @@ import copy
|
|
|
3
3
|
import json
|
|
4
4
|
import re
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Union
|
|
7
7
|
|
|
8
8
|
import attrs
|
|
9
9
|
from gooddata_sdk import CatalogDeclarativeColumn, CatalogDeclarativeTable, CatalogDeclarativeTables
|
|
@@ -27,22 +27,23 @@ from gooddata_dbt.dbt.cloud import DbtConnection
|
|
|
27
27
|
|
|
28
28
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
29
29
|
class DbtModelMetaGoodDataTableProps(Base):
|
|
30
|
-
model_id:
|
|
30
|
+
model_id: str | None = None
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
34
34
|
class DbtModelMetaGoodDataColumnProps(Base):
|
|
35
|
-
id:
|
|
36
|
-
ldm_type:
|
|
37
|
-
referenced_table:
|
|
38
|
-
label_type:
|
|
39
|
-
attribute_column:
|
|
40
|
-
sort_column:
|
|
41
|
-
sort_direction:
|
|
42
|
-
default_view:
|
|
35
|
+
id: str | None = None
|
|
36
|
+
ldm_type: GoodDataLdmType | None = None
|
|
37
|
+
referenced_table: str | None = None
|
|
38
|
+
label_type: GoodDataLabelType | None = None
|
|
39
|
+
attribute_column: str | None = None
|
|
40
|
+
sort_column: str | None = None
|
|
41
|
+
sort_direction: GoodDataSortDirection | None = None
|
|
42
|
+
default_view: bool | None = None
|
|
43
|
+
geo_area_config: dict[str, dict[str, str]] | None = None
|
|
43
44
|
|
|
44
45
|
@property
|
|
45
|
-
def gooddata_ref_table_ldm_id(self) ->
|
|
46
|
+
def gooddata_ref_table_ldm_id(self) -> str | None:
|
|
46
47
|
if self.referenced_table:
|
|
47
48
|
return self.referenced_table.lower()
|
|
48
49
|
return None
|
|
@@ -73,7 +74,7 @@ class DbtModelBase(Base):
|
|
|
73
74
|
tags: list[str]
|
|
74
75
|
# If 2+ references point to the same table, the table plays multiple roles,
|
|
75
76
|
# it must be generated as multiple datasets
|
|
76
|
-
role_name:
|
|
77
|
+
role_name: str | None = None
|
|
77
78
|
|
|
78
79
|
# TODO - duplicate of backend logic.
|
|
79
80
|
# Solution: use result of generateLdm as a master template, and override based on dbt metadata only if necessary
|
|
@@ -120,7 +121,7 @@ class DbtModelBase(Base):
|
|
|
120
121
|
|
|
121
122
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
122
123
|
class DbtModelColumn(DbtModelBase):
|
|
123
|
-
data_type:
|
|
124
|
+
data_type: str | None
|
|
124
125
|
meta: DbtModelMetaGoodDataColumn = attrs.field(factory=DbtModelMetaGoodDataColumn)
|
|
125
126
|
|
|
126
127
|
# Enable to override LDM ID for LDM entities derived from columns (attributes, ...)
|
|
@@ -130,21 +131,21 @@ class DbtModelColumn(DbtModelBase):
|
|
|
130
131
|
return self.meta.gooddata.id or self.gooddata_ldm_id
|
|
131
132
|
|
|
132
133
|
@property
|
|
133
|
-
def ldm_type(self) ->
|
|
134
|
+
def ldm_type(self) -> str | None:
|
|
134
135
|
if self.meta.gooddata.ldm_type is None:
|
|
135
136
|
return None
|
|
136
137
|
else:
|
|
137
138
|
return self.meta.gooddata.ldm_type.value
|
|
138
139
|
|
|
139
140
|
@property
|
|
140
|
-
def label_type(self) ->
|
|
141
|
+
def label_type(self) -> str | None:
|
|
141
142
|
if self.meta.gooddata.label_type is None:
|
|
142
143
|
return None
|
|
143
144
|
else:
|
|
144
145
|
return self.meta.gooddata.label_type.value
|
|
145
146
|
|
|
146
147
|
@property
|
|
147
|
-
def sort_direction(self) ->
|
|
148
|
+
def sort_direction(self) -> str | None:
|
|
148
149
|
if self.meta.gooddata.sort_direction is None:
|
|
149
150
|
return None
|
|
150
151
|
else:
|
|
@@ -387,22 +388,23 @@ class DbtModelTables:
|
|
|
387
388
|
return facts
|
|
388
389
|
|
|
389
390
|
@staticmethod
|
|
390
|
-
def make_labels(table: DbtModelTable, attribute_column: DbtModelColumn) -> tuple[list[dict],
|
|
391
|
+
def make_labels(table: DbtModelTable, attribute_column: DbtModelColumn) -> tuple[list[dict], dict | None]:
|
|
391
392
|
labels = []
|
|
392
393
|
default_view = None
|
|
393
394
|
for column in table.columns.values():
|
|
394
395
|
if column.gooddata_is_label(attribute_column.name):
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
396
|
+
label_dict: dict = {
|
|
397
|
+
"id": column.ldm_id,
|
|
398
|
+
"title": column.gooddata_ldm_title,
|
|
399
|
+
"description": column.gooddata_ldm_description,
|
|
400
|
+
"source_column": column.name,
|
|
401
|
+
"source_column_data_type": column.data_type,
|
|
402
|
+
"value_type": column.label_type,
|
|
403
|
+
"tags": [table.gooddata_ldm_title] + column.tags,
|
|
404
|
+
}
|
|
405
|
+
if column.meta.gooddata.geo_area_config is not None:
|
|
406
|
+
label_dict["geo_area_config"] = column.meta.gooddata.geo_area_config
|
|
407
|
+
labels.append(label_dict)
|
|
406
408
|
if column.meta.gooddata.default_view:
|
|
407
409
|
default_view = {
|
|
408
410
|
"id": column.ldm_id,
|
|
@@ -507,7 +509,7 @@ class DbtModelTables:
|
|
|
507
509
|
result.append(table)
|
|
508
510
|
return result
|
|
509
511
|
|
|
510
|
-
def make_declarative_datasets(self, data_source_id: str, model_ids:
|
|
512
|
+
def make_declarative_datasets(self, data_source_id: str, model_ids: list[str] | None) -> dict:
|
|
511
513
|
result: dict[str, list] = {"datasets": [], "date_instances": []}
|
|
512
514
|
model_tables = [t for t in self.tables if not model_ids or t.meta.gooddata.model_id in model_ids]
|
|
513
515
|
role_playing_tables = self.find_role_playing_tables(model_tables)
|
|
@@ -517,7 +519,7 @@ class DbtModelTables:
|
|
|
517
519
|
result = self.make_dataset(data_source_id, table, role_playing_tables, result)
|
|
518
520
|
return result
|
|
519
521
|
|
|
520
|
-
def get_entity_type(self, table_name: str, column_name: str) ->
|
|
522
|
+
def get_entity_type(self, table_name: str, column_name: str) -> str | None:
|
|
521
523
|
comp_table_name = table_name
|
|
522
524
|
if self.upper_case:
|
|
523
525
|
comp_table_name = table_name.upper()
|
|
@@ -5,7 +5,6 @@ from argparse import Namespace
|
|
|
5
5
|
from asyncio import Semaphore
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from time import time
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import tabulate
|
|
11
10
|
import yaml
|
|
@@ -36,7 +35,7 @@ def generate_and_put_ldm(
|
|
|
36
35
|
data_source_id: str,
|
|
37
36
|
workspace_id: str,
|
|
38
37
|
dbt_tables: DbtModelTables,
|
|
39
|
-
model_ids:
|
|
38
|
+
model_ids: list[str] | None,
|
|
40
39
|
) -> None:
|
|
41
40
|
scan_request = CatalogScanModelRequest(scan_tables=True, scan_views=True)
|
|
42
41
|
logger.info(f"Scan data source {data_source_id=}")
|
|
@@ -68,7 +67,7 @@ def deploy_ldm(
|
|
|
68
67
|
args: Namespace,
|
|
69
68
|
all_model_ids: list[str],
|
|
70
69
|
sdk_wrapper: GoodDataSdkWrapper,
|
|
71
|
-
model_ids:
|
|
70
|
+
model_ids: list[str] | None,
|
|
72
71
|
workspace_id: str,
|
|
73
72
|
) -> None:
|
|
74
73
|
logger.info("Generate and put LDM")
|
|
@@ -186,7 +185,7 @@ async def test_visualizations(
|
|
|
186
185
|
logger: logging.Logger,
|
|
187
186
|
sdk_wrapper: GoodDataSdkWrapper,
|
|
188
187
|
workspace_id: str,
|
|
189
|
-
skip_tests:
|
|
188
|
+
skip_tests: list[str] | None,
|
|
190
189
|
test_visualizations_parallelism: int = 1,
|
|
191
190
|
) -> None:
|
|
192
191
|
start = time()
|
|
@@ -334,7 +333,7 @@ def process_organization(
|
|
|
334
333
|
logger: logging.Logger,
|
|
335
334
|
sdk_wrapper: GoodDataSdkWrapper,
|
|
336
335
|
gd_config: GoodDataConfig,
|
|
337
|
-
organization:
|
|
336
|
+
organization: GoodDataConfigOrganization | None = None,
|
|
338
337
|
) -> None:
|
|
339
338
|
if args.method == "upload_notification":
|
|
340
339
|
dbt_profiles = DbtProfiles(args)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# (C) 2023 GoodData Corporation
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
import attr
|
|
5
4
|
import attrs
|
|
@@ -37,8 +36,8 @@ class GoodDataConfigProduct(Base):
|
|
|
37
36
|
name: str
|
|
38
37
|
environment_setup_id: str
|
|
39
38
|
model_ids: list[str] = attr.field(factory=list)
|
|
40
|
-
localization:
|
|
41
|
-
skip_tests:
|
|
39
|
+
localization: GoodDataConfigLocalization | None = None
|
|
40
|
+
skip_tests: list[str] | None = None
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
@@ -49,7 +48,7 @@ class GoodDataConfigOrganization(Base):
|
|
|
49
48
|
|
|
50
49
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
51
50
|
class GoodDataGlobalConfig(Base):
|
|
52
|
-
test_visualizations_parallelism:
|
|
51
|
+
test_visualizations_parallelism: int | None = 1
|
|
53
52
|
|
|
54
53
|
|
|
55
54
|
@attrs.define(auto_attribs=True, kw_only=True)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# (C) 2023 GoodData Corporation
|
|
2
2
|
import argparse
|
|
3
3
|
from logging import Logger
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
from gooddata_sdk import GoodDataSdk
|
|
7
6
|
|
|
@@ -11,7 +10,7 @@ from gooddata_dbt.gooddata.api_wrapper import GoodDataApiWrapper
|
|
|
11
10
|
class GoodDataSdkWrapper:
|
|
12
11
|
# Timeout=600 because supporting waiting for GoodData services to start
|
|
13
12
|
def __init__(
|
|
14
|
-
self, args: argparse.Namespace, logger: Logger, profile:
|
|
13
|
+
self, args: argparse.Namespace, logger: Logger, profile: str | None = None, timeout: int = 600
|
|
15
14
|
) -> None:
|
|
16
15
|
self.args = args
|
|
17
16
|
self.logger = logger
|
|
@@ -22,7 +21,7 @@ class GoodDataSdkWrapper:
|
|
|
22
21
|
if not self.args.dry_run:
|
|
23
22
|
self.wait_for_gooddata_is_up(self.timeout)
|
|
24
23
|
|
|
25
|
-
def get_host_from_sdk(self) ->
|
|
24
|
+
def get_host_from_sdk(self) -> str | None:
|
|
26
25
|
# TODO - make _hostname public in gooddata_sdk
|
|
27
26
|
return self.sdk.client._hostname
|
|
28
27
|
|
|
@@ -54,7 +53,7 @@ class GoodDataSdkWrapper:
|
|
|
54
53
|
self.sdk.support.wait_till_available(timeout=timeout)
|
|
55
54
|
self.logger.info(f"Host {host} is up")
|
|
56
55
|
|
|
57
|
-
def pre_cache_visualizations(self, workspaces:
|
|
56
|
+
def pre_cache_visualizations(self, workspaces: list | None = None) -> None:
|
|
58
57
|
if not workspaces:
|
|
59
58
|
workspaces = [w.id for w in self.sdk.catalog_workspace.list_workspaces()]
|
|
60
59
|
for workspace_id in workspaces:
|
{gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/dbt_target/manifest.json
RENAMED
|
@@ -1860,6 +1860,25 @@
|
|
|
1860
1860
|
"data_type": null,
|
|
1861
1861
|
"quote": null,
|
|
1862
1862
|
"tags": []
|
|
1863
|
+
},
|
|
1864
|
+
"country": {
|
|
1865
|
+
"name": "country",
|
|
1866
|
+
"description": "",
|
|
1867
|
+
"meta": {
|
|
1868
|
+
"gooddata": {
|
|
1869
|
+
"ldm_type": "label",
|
|
1870
|
+
"label_type": "GEO_AREA",
|
|
1871
|
+
"attribute_column": "code",
|
|
1872
|
+
"geo_area_config": {
|
|
1873
|
+
"collection": {
|
|
1874
|
+
"id": "countries"
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
},
|
|
1879
|
+
"data_type": null,
|
|
1880
|
+
"quote": null,
|
|
1881
|
+
"tags": []
|
|
1863
1882
|
}
|
|
1864
1883
|
},
|
|
1865
1884
|
"meta": {
|
|
@@ -49,3 +49,35 @@ def test_make_ldm():
|
|
|
49
49
|
assert ldm.ldm is not None
|
|
50
50
|
assert len(ldm.ldm.datasets) == 4
|
|
51
51
|
assert len(ldm.ldm.date_instances) == 4
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
FAA_MODEL_ID = "faa"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_make_ldm_geo_area():
|
|
58
|
+
"""Test that GEO_AREA label type is parsed and included in the LDM."""
|
|
59
|
+
tables = DbtModelTables.from_local(upper_case=False, all_model_ids=[FAA_MODEL_ID], manifest_path=_MANIFEST_PATH)
|
|
60
|
+
scan_pdm = CatalogDeclarativeTables.load_from_disk(_PDM_PATH)
|
|
61
|
+
tables.set_data_types(scan_pdm)
|
|
62
|
+
data_source_id = "postgres"
|
|
63
|
+
|
|
64
|
+
declarative_datasets = tables.make_declarative_datasets(data_source_id, [FAA_MODEL_ID])
|
|
65
|
+
ldm = CatalogDeclarativeModel.from_dict({"ldm": declarative_datasets}, camel_case=False)
|
|
66
|
+
|
|
67
|
+
assert ldm.ldm is not None
|
|
68
|
+
# airports is referenced twice (origin/destination), find either one
|
|
69
|
+
airports = [ds for ds in ldm.ldm.datasets if ds.id == "airports_origin"]
|
|
70
|
+
assert len(airports) == 1
|
|
71
|
+
airports_ds = airports[0]
|
|
72
|
+
# Find the code attribute (which has geo labels)
|
|
73
|
+
code_attrs = [a for a in airports_ds.attributes if a.id == "code_origin"]
|
|
74
|
+
assert len(code_attrs) == 1
|
|
75
|
+
labels = code_attrs[0].labels
|
|
76
|
+
label_types = {label.id: label.value_type for label in labels}
|
|
77
|
+
assert label_types["latitude_origin"] == "GEO_LATITUDE"
|
|
78
|
+
assert label_types["longitude_origin"] == "GEO_LONGITUDE"
|
|
79
|
+
assert label_types["country_origin"] == "GEO_AREA"
|
|
80
|
+
# Verify geo_area_config is propagated
|
|
81
|
+
country_label = next(lbl for lbl in labels if lbl.id == "country_origin")
|
|
82
|
+
assert country_label.geo_area_config is not None
|
|
83
|
+
assert country_label.geo_area_config.collection.id == "countries"
|
|
@@ -11,4 +11,4 @@ dependency_groups =
|
|
|
11
11
|
setenv =
|
|
12
12
|
COVERAGE_CORE=sysmon
|
|
13
13
|
commands =
|
|
14
|
-
pytest -v --cov
|
|
14
|
+
pytest -v --cov --cov-report=xml tests {posargs} --json-report --json-report-file=.json-report-{envname}.json
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/src/gooddata_dbt/gooddata/api_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gooddata_dbt-1.60.1.dev1 → gooddata_dbt-1.60.1.dev2}/tests/resources/dbt_profiles/profiles.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|