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.

Files changed (54) hide show
  1. {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/METADATA +2 -2
  2. semantic_link_labs-0.6.0.dist-info/RECORD +54 -0
  3. {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +44 -14
  5. sempy_labs/_ai.py +31 -32
  6. sempy_labs/_clear_cache.py +5 -8
  7. sempy_labs/_connections.py +80 -72
  8. sempy_labs/_dax.py +7 -9
  9. sempy_labs/_generate_semantic_model.py +60 -54
  10. sempy_labs/_helper_functions.py +8 -10
  11. sempy_labs/_icons.py +15 -0
  12. sempy_labs/_list_functions.py +1139 -428
  13. sempy_labs/_model_auto_build.py +5 -6
  14. sempy_labs/_model_bpa.py +134 -1125
  15. sempy_labs/_model_bpa_rules.py +831 -0
  16. sempy_labs/_model_dependencies.py +21 -25
  17. sempy_labs/_one_lake_integration.py +10 -7
  18. sempy_labs/_query_scale_out.py +83 -93
  19. sempy_labs/_refresh_semantic_model.py +12 -16
  20. sempy_labs/_translations.py +214 -288
  21. sempy_labs/_vertipaq.py +51 -42
  22. sempy_labs/directlake/__init__.py +2 -0
  23. sempy_labs/directlake/_directlake_schema_compare.py +12 -11
  24. sempy_labs/directlake/_directlake_schema_sync.py +13 -23
  25. sempy_labs/directlake/_fallback.py +5 -7
  26. sempy_labs/directlake/_get_directlake_lakehouse.py +1 -1
  27. sempy_labs/directlake/_get_shared_expression.py +4 -8
  28. sempy_labs/directlake/_guardrails.py +6 -8
  29. sempy_labs/directlake/_list_directlake_model_calc_tables.py +18 -12
  30. sempy_labs/directlake/_show_unsupported_directlake_objects.py +4 -4
  31. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +9 -8
  32. sempy_labs/directlake/_update_directlake_partition_entity.py +129 -12
  33. sempy_labs/directlake/_warm_cache.py +5 -5
  34. sempy_labs/lakehouse/_get_lakehouse_columns.py +2 -2
  35. sempy_labs/lakehouse/_get_lakehouse_tables.py +4 -4
  36. sempy_labs/lakehouse/_lakehouse.py +3 -4
  37. sempy_labs/lakehouse/_shortcuts.py +17 -13
  38. sempy_labs/migration/__init__.py +1 -1
  39. sempy_labs/migration/_create_pqt_file.py +21 -24
  40. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +16 -13
  41. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +17 -18
  42. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +45 -46
  43. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +14 -14
  44. sempy_labs/migration/_migration_validation.py +6 -2
  45. sempy_labs/migration/_refresh_calc_tables.py +10 -5
  46. sempy_labs/report/__init__.py +2 -2
  47. sempy_labs/report/_generate_report.py +8 -7
  48. sempy_labs/report/_report_functions.py +47 -52
  49. sempy_labs/report/_report_rebind.py +38 -37
  50. sempy_labs/tom/__init__.py +1 -4
  51. sempy_labs/tom/_model.py +541 -180
  52. semantic_link_labs-0.4.2.dist-info/RECORD +0 -53
  53. {semantic_link_labs-0.4.2.dist-info → semantic_link_labs-0.6.0.dist-info}/LICENSE +0 -0
  54. {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, base64, time, os
5
- from typing import List, Optional, Union
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
- workspace_id = fabric.get_workspace_id()
36
- workspace = fabric.resolve_workspace_name(workspace_id)
38
+ workspace = fabric.resolve_workspace_name()
37
39
 
38
- if compatibility_level < 1500:
39
- print(f"{icons.red_dot} Compatiblity level must be at least 1500.")
40
- return
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
- print(
94
- f"WARNING: '{dataset}' already exists as a semantic model in the '{workspace}' workspace."
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
- dataset: str,
154
- new_dataset: Optional[str] = None,
155
- workspace: Optional[str] = None,
156
- new_dataset_workspace: Optional[str] = None,
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
- dataset : str
168
+ source_dataset : str
164
169
  Name of the semantic model to deploy.
165
- new_dataset: str
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
- new_dataset_workspace : str, default=None
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
- if workspace is None:
182
- workspace_id = fabric.get_workspace_id()
183
- workspace = fabric.resolve_workspace_name(workspace_id)
188
+ from sempy_labs import refresh_semantic_model
189
+
190
+ source_workspace = fabric.resolve_workspace_name(source_workspace)
184
191
 
185
- if new_dataset_workspace is None:
186
- new_dataset_workspace = workspace
192
+ if target_workspace is None:
193
+ target_workspace = source_workspace
187
194
 
188
- if new_dataset is None:
189
- new_dataset = dataset
195
+ if target_dataset is None:
196
+ target_dataset = source_dataset
190
197
 
191
- if new_dataset == dataset and new_dataset_workspace == workspace:
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' parameters have the same value. At least one of these must be different. Please update the parameters."
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=dataset, workspace=workspace)
205
+ bim = get_semantic_model_bim(dataset=source_dataset, workspace=source_workspace)
198
206
 
199
207
  create_semantic_model_from_bim(
200
- dataset=new_dataset, bim_file=bim, workspace=new_dataset_workspace
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
- objType = "SemanticModel"
249
+ fmt = "TMSL"
232
250
  client = fabric.FabricRestClient()
233
- itemList = fabric.list_items(workspace=workspace, type=objType)
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
- if response.status_code == 200:
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
- print(
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, workspace)
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):
@@ -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(lakehouse_id: Optional[UUID] = None, workspace: Optional[str] = None):
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
- print(
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
- print(
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
- print(
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"