semantic-link-labs 0.4.2__py3-none-any.whl → 0.6.0__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 semantic-link-labs might be problematic. Click here for more details.
- {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/METADATA +2 -2
- semantic_link_labs-0.6.0.dist-info/RECORD +54 -0
- {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +44 -14
- sempy_labs/_ai.py +31 -32
- sempy_labs/_clear_cache.py +5 -8
- sempy_labs/_connections.py +80 -72
- sempy_labs/_dax.py +7 -9
- sempy_labs/_generate_semantic_model.py +60 -54
- sempy_labs/_helper_functions.py +8 -10
- sempy_labs/_icons.py +15 -0
- sempy_labs/_list_functions.py +1139 -428
- sempy_labs/_model_auto_build.py +5 -6
- sempy_labs/_model_bpa.py +134 -1125
- sempy_labs/_model_bpa_rules.py +831 -0
- sempy_labs/_model_dependencies.py +21 -25
- sempy_labs/_one_lake_integration.py +10 -7
- sempy_labs/_query_scale_out.py +83 -93
- sempy_labs/_refresh_semantic_model.py +12 -16
- sempy_labs/_translations.py +214 -288
- sempy_labs/_vertipaq.py +51 -42
- sempy_labs/directlake/__init__.py +2 -0
- sempy_labs/directlake/_directlake_schema_compare.py +12 -11
- sempy_labs/directlake/_directlake_schema_sync.py +13 -23
- sempy_labs/directlake/_fallback.py +5 -7
- sempy_labs/directlake/_get_directlake_lakehouse.py +1 -1
- sempy_labs/directlake/_get_shared_expression.py +4 -8
- sempy_labs/directlake/_guardrails.py +6 -8
- sempy_labs/directlake/_list_directlake_model_calc_tables.py +18 -12
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +4 -4
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +9 -8
- sempy_labs/directlake/_update_directlake_partition_entity.py +129 -12
- sempy_labs/directlake/_warm_cache.py +5 -5
- sempy_labs/lakehouse/_get_lakehouse_columns.py +2 -2
- sempy_labs/lakehouse/_get_lakehouse_tables.py +4 -4
- sempy_labs/lakehouse/_lakehouse.py +3 -4
- sempy_labs/lakehouse/_shortcuts.py +17 -13
- sempy_labs/migration/__init__.py +1 -1
- sempy_labs/migration/_create_pqt_file.py +21 -24
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +16 -13
- sempy_labs/migration/_migrate_calctables_to_semantic_model.py +17 -18
- sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +45 -46
- sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +14 -14
- sempy_labs/migration/_migration_validation.py +6 -2
- sempy_labs/migration/_refresh_calc_tables.py +10 -5
- sempy_labs/report/__init__.py +2 -2
- sempy_labs/report/_generate_report.py +8 -7
- sempy_labs/report/_report_functions.py +47 -52
- sempy_labs/report/_report_rebind.py +38 -37
- sempy_labs/tom/__init__.py +1 -4
- sempy_labs/tom/_model.py +541 -180
- semantic_link_labs-0.4.2.dist-info/RECORD +0 -53
- {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import sempy
|
|
2
1
|
import sempy.fabric as fabric
|
|
3
2
|
import pandas as pd
|
|
4
|
-
import json
|
|
5
|
-
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
5
|
+
import time
|
|
6
|
+
import os
|
|
7
|
+
from typing import Optional
|
|
6
8
|
from sempy_labs._helper_functions import (
|
|
7
9
|
resolve_lakehouse_name,
|
|
8
10
|
resolve_workspace_name_and_id,
|
|
9
11
|
)
|
|
10
12
|
from sempy_labs.lakehouse._lakehouse import lakehouse_attached
|
|
11
13
|
import sempy_labs._icons as icons
|
|
14
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
def create_blank_semantic_model(
|
|
@@ -32,12 +35,14 @@ def create_blank_semantic_model(
|
|
|
32
35
|
"""
|
|
33
36
|
|
|
34
37
|
if workspace is None:
|
|
35
|
-
|
|
36
|
-
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
38
|
+
workspace = fabric.resolve_workspace_name()
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
min_compat = 1500
|
|
41
|
+
|
|
42
|
+
if compatibility_level < min_compat:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"{icons.red_dot} Compatiblity level must be at least {min_compat}."
|
|
45
|
+
)
|
|
41
46
|
|
|
42
47
|
tmsl = f"""
|
|
43
48
|
{{
|
|
@@ -90,10 +95,9 @@ def create_semantic_model_from_bim(
|
|
|
90
95
|
dfI_filt = dfI[(dfI["Display Name"] == dataset)]
|
|
91
96
|
|
|
92
97
|
if len(dfI_filt) > 0:
|
|
93
|
-
|
|
94
|
-
f"
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"{icons.red_dot} '{dataset}' already exists as a semantic model in the '{workspace}' workspace."
|
|
95
100
|
)
|
|
96
|
-
return
|
|
97
101
|
|
|
98
102
|
client = fabric.FabricRestClient()
|
|
99
103
|
defPBIDataset = {"version": "1.0", "settings": {}}
|
|
@@ -131,7 +135,7 @@ def create_semantic_model_from_bim(
|
|
|
131
135
|
|
|
132
136
|
if response.status_code == 201:
|
|
133
137
|
print(
|
|
134
|
-
f"The '{dataset}' semantic model has been created within the '{workspace}' workspace."
|
|
138
|
+
f"{icons.green_dot} The '{dataset}' semantic model has been created within the '{workspace}' workspace."
|
|
135
139
|
)
|
|
136
140
|
print(response.json())
|
|
137
141
|
elif response.status_code == 202:
|
|
@@ -144,67 +148,75 @@ def create_semantic_model_from_bim(
|
|
|
144
148
|
response_body = json.loads(response.content)
|
|
145
149
|
response = client.get(f"/v1/operations/{operationId}/result")
|
|
146
150
|
print(
|
|
147
|
-
f"The '{dataset}' semantic model has been created within the '{workspace}' workspace."
|
|
151
|
+
f"{icons.green_dot} The '{dataset}' semantic model has been created within the '{workspace}' workspace."
|
|
148
152
|
)
|
|
149
153
|
print(response.json())
|
|
150
154
|
|
|
151
155
|
|
|
152
156
|
def deploy_semantic_model(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
source_dataset: str,
|
|
158
|
+
source_workspace: Optional[str] = None,
|
|
159
|
+
target_dataset: Optional[str] = None,
|
|
160
|
+
target_workspace: Optional[str] = None,
|
|
161
|
+
refresh_target_dataset: Optional[bool] = True,
|
|
157
162
|
):
|
|
158
163
|
"""
|
|
159
164
|
Deploys a semantic model based on an existing semantic model.
|
|
160
165
|
|
|
161
166
|
Parameters
|
|
162
167
|
----------
|
|
163
|
-
|
|
168
|
+
source_dataset : str
|
|
164
169
|
Name of the semantic model to deploy.
|
|
165
|
-
|
|
166
|
-
Name of the new semantic model to be created.
|
|
167
|
-
workspace : str, default=None
|
|
170
|
+
source_workspace : str, default=None
|
|
168
171
|
The Fabric workspace name.
|
|
169
172
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
170
173
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
171
|
-
|
|
174
|
+
target_dataset: str
|
|
175
|
+
Name of the new semantic model to be created.
|
|
176
|
+
target_workspace : str, default=None
|
|
172
177
|
The Fabric workspace name in which the new semantic model will be deployed.
|
|
173
178
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
174
179
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
180
|
+
refresh_target_dataset : bool, default=True
|
|
181
|
+
If set to True, this will initiate a full refresh of the target semantic model in the target workspace.
|
|
175
182
|
|
|
176
183
|
Returns
|
|
177
184
|
-------
|
|
178
185
|
|
|
179
186
|
"""
|
|
180
187
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
from sempy_labs import refresh_semantic_model
|
|
189
|
+
|
|
190
|
+
source_workspace = fabric.resolve_workspace_name(source_workspace)
|
|
184
191
|
|
|
185
|
-
if
|
|
186
|
-
|
|
192
|
+
if target_workspace is None:
|
|
193
|
+
target_workspace = source_workspace
|
|
187
194
|
|
|
188
|
-
if
|
|
189
|
-
|
|
195
|
+
if target_dataset is None:
|
|
196
|
+
target_dataset = source_dataset
|
|
190
197
|
|
|
191
|
-
if
|
|
198
|
+
if target_dataset == source_dataset and target_workspace == source_workspace:
|
|
192
199
|
print(
|
|
193
|
-
f"The 'dataset' and 'new_dataset' parameters have the same value. And, the 'workspace' and 'new_dataset_workspace'
|
|
200
|
+
f"{icons.red_dot} The 'dataset' and 'new_dataset' parameters have the same value. And, the 'workspace' and 'new_dataset_workspace' "
|
|
201
|
+
f"parameters have the same value. At least one of these must be different. Please update the parameters."
|
|
194
202
|
)
|
|
195
203
|
return
|
|
196
204
|
|
|
197
|
-
bim = get_semantic_model_bim(dataset=
|
|
205
|
+
bim = get_semantic_model_bim(dataset=source_dataset, workspace=source_workspace)
|
|
198
206
|
|
|
199
207
|
create_semantic_model_from_bim(
|
|
200
|
-
dataset=
|
|
208
|
+
dataset=target_dataset, bim_file=bim, workspace=target_workspace
|
|
201
209
|
)
|
|
202
210
|
|
|
211
|
+
if refresh_target_dataset:
|
|
212
|
+
refresh_semantic_model(dataset=target_dataset, workspace=target_workspace)
|
|
213
|
+
|
|
203
214
|
|
|
204
215
|
def get_semantic_model_bim(
|
|
205
216
|
dataset: str,
|
|
206
217
|
workspace: Optional[str] = None,
|
|
207
218
|
save_to_file_name: Optional[str] = None,
|
|
219
|
+
lakehouse_workspace: Optional[str] = None,
|
|
208
220
|
):
|
|
209
221
|
"""
|
|
210
222
|
Extracts the Model.bim file for a given semantic model.
|
|
@@ -214,11 +226,15 @@ def get_semantic_model_bim(
|
|
|
214
226
|
dataset : str
|
|
215
227
|
Name of the semantic model.
|
|
216
228
|
workspace : str, default=None
|
|
217
|
-
The Fabric workspace name.
|
|
229
|
+
The Fabric workspace name in which the semantic model resides.
|
|
218
230
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
219
231
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
220
232
|
save_to_file_name : str, default=None
|
|
221
233
|
If specified, saves the Model.bim as a file in the lakehouse attached to the notebook.
|
|
234
|
+
lakehouse_workspace : str, default=None
|
|
235
|
+
The Fabric workspace name in which the lakehouse attached to the workspace resides.
|
|
236
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
237
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
222
238
|
|
|
223
239
|
Returns
|
|
224
240
|
-------
|
|
@@ -227,29 +243,20 @@ def get_semantic_model_bim(
|
|
|
227
243
|
"""
|
|
228
244
|
|
|
229
245
|
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
246
|
+
if lakehouse_workspace is None:
|
|
247
|
+
lakehouse_workspace = workspace
|
|
230
248
|
|
|
231
|
-
|
|
249
|
+
fmt = "TMSL"
|
|
232
250
|
client = fabric.FabricRestClient()
|
|
233
|
-
itemList = fabric.list_items(workspace=workspace, type=
|
|
251
|
+
itemList = fabric.list_items(workspace=workspace, type="SemanticModel")
|
|
234
252
|
itemListFilt = itemList[(itemList["Display Name"] == dataset)]
|
|
235
253
|
itemId = itemListFilt["Id"].iloc[0]
|
|
236
254
|
response = client.post(
|
|
237
|
-
f"/v1/workspaces/{workspace_id}/items/{itemId}/getDefinition"
|
|
255
|
+
f"/v1/workspaces/{workspace_id}/items/{itemId}/getDefinition?format={fmt}",
|
|
256
|
+
lro_wait=True,
|
|
238
257
|
)
|
|
239
258
|
|
|
240
|
-
|
|
241
|
-
res = response.json()
|
|
242
|
-
elif response.status_code == 202:
|
|
243
|
-
operationId = response.headers["x-ms-operation-id"]
|
|
244
|
-
response = client.get(f"/v1/operations/{operationId}")
|
|
245
|
-
response_body = json.loads(response.content)
|
|
246
|
-
while response_body["status"] != "Succeeded":
|
|
247
|
-
time.sleep(3)
|
|
248
|
-
response = client.get(f"/v1/operations/{operationId}")
|
|
249
|
-
response_body = json.loads(response.content)
|
|
250
|
-
response = client.get(f"/v1/operations/{operationId}/result")
|
|
251
|
-
res = response.json()
|
|
252
|
-
df_items = pd.json_normalize(res["definition"]["parts"])
|
|
259
|
+
df_items = pd.json_normalize(response.json()["definition"]["parts"])
|
|
253
260
|
df_items_filt = df_items[df_items["path"] == "model.bim"]
|
|
254
261
|
payload = df_items_filt["payload"].iloc[0]
|
|
255
262
|
bimFile = base64.b64decode(payload).decode("utf-8")
|
|
@@ -258,13 +265,12 @@ def get_semantic_model_bim(
|
|
|
258
265
|
if save_to_file_name is not None:
|
|
259
266
|
lakeAttach = lakehouse_attached()
|
|
260
267
|
if lakeAttach is False:
|
|
261
|
-
|
|
262
|
-
f"In order to save the model.bim file, a lakehouse must be attached to the notebook. Please attach a lakehouse to this notebook."
|
|
268
|
+
raise ValueError(
|
|
269
|
+
f"{icons.red_dot} In order to save the model.bim file, a lakehouse must be attached to the notebook. Please attach a lakehouse to this notebook."
|
|
263
270
|
)
|
|
264
|
-
return
|
|
265
271
|
|
|
266
272
|
lakehouse_id = fabric.get_lakehouse_id()
|
|
267
|
-
lakehouse = resolve_lakehouse_name(lakehouse_id,
|
|
273
|
+
lakehouse = resolve_lakehouse_name(lakehouse_id, lakehouse_workspace)
|
|
268
274
|
folderPath = "/lakehouse/default/Files"
|
|
269
275
|
fileExt = ".bim"
|
|
270
276
|
if not save_to_file_name.endswith(fileExt):
|
sempy_labs/_helper_functions.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import sempy
|
|
2
1
|
import sempy.fabric as fabric
|
|
3
2
|
import re
|
|
4
3
|
import pandas as pd
|
|
@@ -200,7 +199,9 @@ def resolve_dataset_name(dataset_id: UUID, workspace: Optional[str] = None):
|
|
|
200
199
|
return obj
|
|
201
200
|
|
|
202
201
|
|
|
203
|
-
def resolve_lakehouse_name(
|
|
202
|
+
def resolve_lakehouse_name(
|
|
203
|
+
lakehouse_id: Optional[UUID] = None, workspace: Optional[str] = None
|
|
204
|
+
):
|
|
204
205
|
"""
|
|
205
206
|
Obtains the name of the Fabric lakehouse.
|
|
206
207
|
|
|
@@ -223,7 +224,7 @@ def resolve_lakehouse_name(lakehouse_id: Optional[UUID] = None, workspace: Optio
|
|
|
223
224
|
if workspace is None:
|
|
224
225
|
workspace_id = fabric.get_workspace_id()
|
|
225
226
|
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
226
|
-
|
|
227
|
+
|
|
227
228
|
if lakehouse_id is None:
|
|
228
229
|
lakehouse_id = fabric.get_lakehouse_id()
|
|
229
230
|
|
|
@@ -420,16 +421,14 @@ def save_as_delta_table(
|
|
|
420
421
|
write_mode = write_mode.lower()
|
|
421
422
|
|
|
422
423
|
if write_mode not in writeModes:
|
|
423
|
-
|
|
424
|
+
raise ValueError(
|
|
424
425
|
f"{icons.red_dot} Invalid 'write_type' parameter. Choose from one of the following values: {writeModes}."
|
|
425
426
|
)
|
|
426
|
-
return
|
|
427
427
|
|
|
428
428
|
if " " in delta_table_name:
|
|
429
|
-
|
|
429
|
+
raise ValueError(
|
|
430
430
|
f"{icons.red_dot} Invalid 'delta_table_name'. Delta tables in the lakehouse cannot have spaces in their names."
|
|
431
431
|
)
|
|
432
|
-
return
|
|
433
432
|
|
|
434
433
|
dataframe.columns = dataframe.columns.str.replace(" ", "_")
|
|
435
434
|
|
|
@@ -476,10 +475,9 @@ def language_validate(language: str):
|
|
|
476
475
|
elif len(df_filt2) == 1:
|
|
477
476
|
lang = df_filt2["Language"].iloc[0]
|
|
478
477
|
else:
|
|
479
|
-
|
|
480
|
-
f"The '{language}' language is not a valid language code. Please refer to this link for a list of valid language codes: {url}."
|
|
478
|
+
raise ValueError(
|
|
479
|
+
f"{icons.red_dot} The '{language}' language is not a valid language code. Please refer to this link for a list of valid language codes: {url}."
|
|
481
480
|
)
|
|
482
|
-
return
|
|
483
481
|
|
|
484
482
|
return lang
|
|
485
483
|
|
sempy_labs/_icons.py
CHANGED
|
@@ -7,3 +7,18 @@ unchecked = "\u2610"
|
|
|
7
7
|
start_bold = "\033[1m"
|
|
8
8
|
end_bold = "\033[0m"
|
|
9
9
|
bullet = "\u2022"
|
|
10
|
+
warning = "⚠️"
|
|
11
|
+
data_type_mapping = {
|
|
12
|
+
"string": "String",
|
|
13
|
+
"bigint": "Int64",
|
|
14
|
+
"int": "Int64",
|
|
15
|
+
"smallint": "Int64",
|
|
16
|
+
"boolean": "Boolean",
|
|
17
|
+
"timestamp": "DateTime",
|
|
18
|
+
"date": "DateTime",
|
|
19
|
+
"decimal(38,18)": "Decimal",
|
|
20
|
+
"double": "Double",
|
|
21
|
+
}
|
|
22
|
+
measure_icon = "\u2211"
|
|
23
|
+
table_icon = "\u229E"
|
|
24
|
+
column_icon = "\u229F"
|