semantic-link-labs 0.5.0__py3-none-any.whl → 0.7.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.7.0.dist-info/METADATA +148 -0
- semantic_link_labs-0.7.0.dist-info/RECORD +111 -0
- {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +45 -15
- sempy_labs/_ai.py +42 -85
- sempy_labs/_bpa_translation/_translations_am-ET.po +828 -0
- sempy_labs/_bpa_translation/_translations_ar-AE.po +860 -0
- sempy_labs/_bpa_translation/_translations_cs-CZ.po +894 -0
- sempy_labs/_bpa_translation/_translations_da-DK.po +894 -0
- sempy_labs/_bpa_translation/_translations_de-DE.po +933 -0
- sempy_labs/_bpa_translation/_translations_el-GR.po +936 -0
- sempy_labs/_bpa_translation/_translations_es-ES.po +915 -0
- sempy_labs/_bpa_translation/_translations_fa-IR.po +883 -0
- sempy_labs/_bpa_translation/_translations_fr-FR.po +938 -0
- sempy_labs/_bpa_translation/_translations_ga-IE.po +912 -0
- sempy_labs/_bpa_translation/_translations_he-IL.po +855 -0
- sempy_labs/_bpa_translation/_translations_hi-IN.po +892 -0
- sempy_labs/_bpa_translation/_translations_hu-HU.po +910 -0
- sempy_labs/_bpa_translation/_translations_is-IS.po +887 -0
- sempy_labs/_bpa_translation/_translations_it-IT.po +931 -0
- sempy_labs/_bpa_translation/_translations_ja-JP.po +805 -0
- sempy_labs/_bpa_translation/_translations_nl-NL.po +924 -0
- sempy_labs/_bpa_translation/_translations_pl-PL.po +913 -0
- sempy_labs/_bpa_translation/_translations_pt-BR.po +909 -0
- sempy_labs/_bpa_translation/_translations_pt-PT.po +904 -0
- sempy_labs/_bpa_translation/_translations_ru-RU.po +909 -0
- sempy_labs/_bpa_translation/_translations_ta-IN.po +922 -0
- sempy_labs/_bpa_translation/_translations_te-IN.po +896 -0
- sempy_labs/_bpa_translation/_translations_th-TH.po +873 -0
- sempy_labs/_bpa_translation/_translations_zh-CN.po +767 -0
- sempy_labs/_bpa_translation/_translations_zu-ZA.po +916 -0
- sempy_labs/_clear_cache.py +12 -8
- sempy_labs/_connections.py +77 -70
- sempy_labs/_dax.py +7 -9
- sempy_labs/_generate_semantic_model.py +75 -90
- sempy_labs/_helper_functions.py +371 -20
- sempy_labs/_icons.py +23 -0
- sempy_labs/_list_functions.py +855 -427
- sempy_labs/_model_auto_build.py +4 -3
- sempy_labs/_model_bpa.py +307 -1118
- sempy_labs/_model_bpa_bulk.py +363 -0
- sempy_labs/_model_bpa_rules.py +831 -0
- sempy_labs/_model_dependencies.py +20 -16
- sempy_labs/_one_lake_integration.py +18 -12
- sempy_labs/_query_scale_out.py +116 -129
- sempy_labs/_refresh_semantic_model.py +23 -10
- sempy_labs/_translations.py +367 -288
- sempy_labs/_vertipaq.py +152 -123
- sempy_labs/directlake/__init__.py +7 -1
- sempy_labs/directlake/_directlake_schema_compare.py +33 -30
- sempy_labs/directlake/_directlake_schema_sync.py +60 -77
- sempy_labs/directlake/_dl_helper.py +233 -0
- sempy_labs/directlake/_get_directlake_lakehouse.py +7 -8
- sempy_labs/directlake/_get_shared_expression.py +5 -3
- sempy_labs/directlake/_guardrails.py +20 -16
- sempy_labs/directlake/_list_directlake_model_calc_tables.py +17 -10
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +3 -2
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +10 -5
- sempy_labs/directlake/_update_directlake_partition_entity.py +169 -22
- sempy_labs/directlake/_warm_cache.py +7 -4
- sempy_labs/lakehouse/_get_lakehouse_columns.py +1 -1
- sempy_labs/lakehouse/_get_lakehouse_tables.py +65 -71
- sempy_labs/lakehouse/_lakehouse.py +5 -3
- sempy_labs/lakehouse/_shortcuts.py +20 -13
- sempy_labs/migration/__init__.py +1 -1
- sempy_labs/migration/_create_pqt_file.py +184 -186
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +240 -269
- sempy_labs/migration/_migrate_calctables_to_semantic_model.py +78 -77
- sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +444 -425
- sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +96 -102
- sempy_labs/migration/_migration_validation.py +2 -2
- sempy_labs/migration/_refresh_calc_tables.py +94 -100
- sempy_labs/report/_BPAReportTemplate.json +232 -0
- sempy_labs/report/__init__.py +6 -2
- sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
- sempy_labs/report/_bpareporttemplate/.platform +11 -0
- sempy_labs/report/_bpareporttemplate/StaticResources/SharedResources/BaseThemes/CY24SU06.json +710 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/page.json +11 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/1b08bce3bebabb0a27a8/visual.json +191 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/2f22ddb70c301693c165/visual.json +438 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/3b1182230aa6c600b43a/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/58577ba6380c69891500/visual.json +576 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/a2a8fa5028b3b776c96c/visual.json +207 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/adfd47ef30652707b987/visual.json +506 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/b6a80ee459e716e170b1/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/ce3130a721c020cc3d81/visual.json +513 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/page.json +8 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/visuals/66e60dfb526437cd78d1/visual.json +112 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/page.json +11 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/07deb8bce824e1be37d7/visual.json +513 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0b1c68838818b32ad03b/visual.json +352 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0c171de9d2683d10b930/visual.json +37 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0efa01be0510e40a645e/visual.json +542 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/6bf2f0eb830ab53cc668/visual.json +221 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/88d8141cb8500b60030c/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/a753273590beed656a03/visual.json +576 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/b8fdc82cddd61ac447bc/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/page.json +9 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/visuals/ce8532a7e25020271077/visual.json +38 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/pages.json +10 -0
- sempy_labs/report/_bpareporttemplate/definition/report.json +176 -0
- sempy_labs/report/_bpareporttemplate/definition/version.json +4 -0
- sempy_labs/report/_bpareporttemplate/definition.pbir +14 -0
- sempy_labs/report/_generate_report.py +260 -139
- sempy_labs/report/_report_functions.py +90 -59
- sempy_labs/report/_report_rebind.py +40 -34
- sempy_labs/tom/__init__.py +1 -4
- sempy_labs/tom/_model.py +601 -181
- semantic_link_labs-0.5.0.dist-info/METADATA +0 -22
- semantic_link_labs-0.5.0.dist-info/RECORD +0 -53
- sempy_labs/directlake/_fallback.py +0 -58
- {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/top_level.txt +0 -0
sempy_labs/_helper_functions.py
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import sempy
|
|
2
1
|
import sempy.fabric as fabric
|
|
3
2
|
import re
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
4
5
|
import pandas as pd
|
|
6
|
+
from functools import wraps
|
|
7
|
+
import datetime
|
|
8
|
+
import time
|
|
5
9
|
from pyspark.sql import SparkSession
|
|
6
|
-
from typing import Optional, Tuple
|
|
10
|
+
from typing import Optional, Tuple, List
|
|
7
11
|
from uuid import UUID
|
|
8
12
|
import sempy_labs._icons as icons
|
|
13
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
def create_abfss_path(
|
|
@@ -200,7 +205,9 @@ def resolve_dataset_name(dataset_id: UUID, workspace: Optional[str] = None):
|
|
|
200
205
|
return obj
|
|
201
206
|
|
|
202
207
|
|
|
203
|
-
def resolve_lakehouse_name(
|
|
208
|
+
def resolve_lakehouse_name(
|
|
209
|
+
lakehouse_id: Optional[UUID] = None, workspace: Optional[str] = None
|
|
210
|
+
):
|
|
204
211
|
"""
|
|
205
212
|
Obtains the name of the Fabric lakehouse.
|
|
206
213
|
|
|
@@ -223,7 +230,7 @@ def resolve_lakehouse_name(lakehouse_id: Optional[UUID] = None, workspace: Optio
|
|
|
223
230
|
if workspace is None:
|
|
224
231
|
workspace_id = fabric.get_workspace_id()
|
|
225
232
|
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
226
|
-
|
|
233
|
+
|
|
227
234
|
if lakehouse_id is None:
|
|
228
235
|
lakehouse_id = fabric.get_lakehouse_id()
|
|
229
236
|
|
|
@@ -283,26 +290,34 @@ def get_direct_lake_sql_endpoint(dataset: str, workspace: Optional[str] = None)
|
|
|
283
290
|
The ID of SQL Endpoint.
|
|
284
291
|
"""
|
|
285
292
|
|
|
293
|
+
from sempy_labs.tom import connect_semantic_model
|
|
294
|
+
|
|
286
295
|
if workspace is None:
|
|
287
296
|
workspace_id = fabric.get_workspace_id()
|
|
288
297
|
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
289
298
|
|
|
290
|
-
dfP = fabric.list_partitions(dataset=dataset, workspace=workspace)
|
|
291
|
-
dfP_filt = dfP[dfP["Mode"] == "DirectLake"]
|
|
299
|
+
# dfP = fabric.list_partitions(dataset=dataset, workspace=workspace)
|
|
300
|
+
# dfP_filt = dfP[dfP["Mode"] == "DirectLake"]
|
|
292
301
|
|
|
293
|
-
if len(dfP_filt) == 0:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
302
|
+
# if len(dfP_filt) == 0:
|
|
303
|
+
# raise ValueError(
|
|
304
|
+
# f"The '{dataset}' semantic model in the '{workspace}' workspace is not in Direct Lake mode."
|
|
305
|
+
# )
|
|
297
306
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
307
|
+
with connect_semantic_model(
|
|
308
|
+
dataset=dataset, readonly=True, workspace=workspace
|
|
309
|
+
) as tom:
|
|
310
|
+
sqlEndpointId = None
|
|
311
|
+
for e in tom.model.Expressions:
|
|
312
|
+
if e.Name == "DatabaseQuery":
|
|
313
|
+
expr = e.Expression
|
|
314
|
+
matches = re.findall(r'"([^"]+)"', expr)
|
|
315
|
+
sqlEndpointId = matches[1]
|
|
301
316
|
|
|
302
|
-
|
|
303
|
-
|
|
317
|
+
if sqlEndpointId is None:
|
|
318
|
+
raise ValueError("SQL Endpoint not found.")
|
|
304
319
|
|
|
305
|
-
|
|
320
|
+
return sqlEndpointId
|
|
306
321
|
|
|
307
322
|
|
|
308
323
|
def generate_embedded_filter(filter: str):
|
|
@@ -374,6 +389,7 @@ def save_as_delta_table(
|
|
|
374
389
|
dataframe,
|
|
375
390
|
delta_table_name: str,
|
|
376
391
|
write_mode: str,
|
|
392
|
+
merge_schema: Optional[bool] = False,
|
|
377
393
|
lakehouse: Optional[str] = None,
|
|
378
394
|
workspace: Optional[str] = None,
|
|
379
395
|
):
|
|
@@ -388,6 +404,8 @@ def save_as_delta_table(
|
|
|
388
404
|
The name of the delta table.
|
|
389
405
|
write_mode : str
|
|
390
406
|
The write mode for the save operation. Options: 'append', 'overwrite'.
|
|
407
|
+
merge_schema : bool, default=False
|
|
408
|
+
Merges the schemas of the dataframe to the delta table.
|
|
391
409
|
lakehouse : str, default=None
|
|
392
410
|
The Fabric lakehouse used by the Direct Lake semantic model.
|
|
393
411
|
Defaults to None which resolves to the lakehouse attached to the notebook.
|
|
@@ -420,10 +438,14 @@ def save_as_delta_table(
|
|
|
420
438
|
write_mode = write_mode.lower()
|
|
421
439
|
|
|
422
440
|
if write_mode not in writeModes:
|
|
423
|
-
raise ValueError(
|
|
441
|
+
raise ValueError(
|
|
442
|
+
f"{icons.red_dot} Invalid 'write_type' parameter. Choose from one of the following values: {writeModes}."
|
|
443
|
+
)
|
|
424
444
|
|
|
425
445
|
if " " in delta_table_name:
|
|
426
|
-
raise ValueError(
|
|
446
|
+
raise ValueError(
|
|
447
|
+
f"{icons.red_dot} Invalid 'delta_table_name'. Delta tables in the lakehouse cannot have spaces in their names."
|
|
448
|
+
)
|
|
427
449
|
|
|
428
450
|
dataframe.columns = dataframe.columns.str.replace(" ", "_")
|
|
429
451
|
|
|
@@ -435,7 +457,13 @@ def save_as_delta_table(
|
|
|
435
457
|
lakehouse_workspace_id=workspace_id,
|
|
436
458
|
delta_table_name=delta_table_name,
|
|
437
459
|
)
|
|
438
|
-
|
|
460
|
+
|
|
461
|
+
if merge_schema:
|
|
462
|
+
spark_df.write.mode(write_mode).format("delta").option(
|
|
463
|
+
"mergeSchema", "true"
|
|
464
|
+
).save(filePath)
|
|
465
|
+
else:
|
|
466
|
+
spark_df.write.mode(write_mode).format("delta").save(filePath)
|
|
439
467
|
print(
|
|
440
468
|
f"{icons.green_dot} The dataframe has been saved as the '{delta_table_name}' table in the '{lakehouse}' lakehouse within the '{workspace}' workspace."
|
|
441
469
|
)
|
|
@@ -470,7 +498,9 @@ def language_validate(language: str):
|
|
|
470
498
|
elif len(df_filt2) == 1:
|
|
471
499
|
lang = df_filt2["Language"].iloc[0]
|
|
472
500
|
else:
|
|
473
|
-
raise ValueError(
|
|
501
|
+
raise ValueError(
|
|
502
|
+
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}."
|
|
503
|
+
)
|
|
474
504
|
|
|
475
505
|
return lang
|
|
476
506
|
|
|
@@ -499,3 +529,324 @@ def resolve_workspace_name_and_id(workspace: Optional[str] = None) -> Tuple[str,
|
|
|
499
529
|
workspace_id = fabric.resolve_workspace_id(workspace)
|
|
500
530
|
|
|
501
531
|
return str(workspace), str(workspace_id)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def _extract_json(dataframe: pd.DataFrame) -> dict:
|
|
535
|
+
|
|
536
|
+
payload = dataframe["payload"].iloc[0]
|
|
537
|
+
json_file = _decode_b64(payload)
|
|
538
|
+
|
|
539
|
+
return json.loads(json_file)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def _conv_b64(file):
|
|
543
|
+
|
|
544
|
+
loadJson = json.dumps(file)
|
|
545
|
+
f = base64.b64encode(loadJson.encode("utf-8")).decode("utf-8")
|
|
546
|
+
|
|
547
|
+
return f
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def _decode_b64(file, format: Optional[str] = "utf-8"):
|
|
551
|
+
|
|
552
|
+
result = base64.b64decode(file).decode(format)
|
|
553
|
+
|
|
554
|
+
return result
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def is_default_semantic_model(dataset: str, workspace: Optional[str] = None) -> bool:
|
|
558
|
+
"""
|
|
559
|
+
Identifies whether a semantic model is a default semantic model.
|
|
560
|
+
|
|
561
|
+
Parameters
|
|
562
|
+
----------
|
|
563
|
+
dataset : str
|
|
564
|
+
The name of the semantic model.
|
|
565
|
+
workspace : str, default=None
|
|
566
|
+
The Fabric workspace name.
|
|
567
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
568
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
569
|
+
|
|
570
|
+
Returns
|
|
571
|
+
-------
|
|
572
|
+
bool
|
|
573
|
+
A True/False value indicating whether the semantic model is a default semantic model.
|
|
574
|
+
"""
|
|
575
|
+
|
|
576
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
577
|
+
|
|
578
|
+
dfI = fabric.list_items(workspace=workspace)
|
|
579
|
+
filtered_df = dfI.groupby("Display Name").filter(
|
|
580
|
+
lambda x: set(["Warehouse", "SemanticModel"]).issubset(set(x["Type"]))
|
|
581
|
+
or set(["Lakehouse", "SemanticModel"]).issubset(set(x["Type"]))
|
|
582
|
+
)
|
|
583
|
+
default_semantic_models = filtered_df["Display Name"].unique().tolist()
|
|
584
|
+
|
|
585
|
+
return dataset in default_semantic_models
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def resolve_item_type(item_id: UUID, workspace: Optional[str] = None) -> str:
|
|
589
|
+
"""
|
|
590
|
+
Obtains the item type for a given Fabric Item Id within a Fabric workspace.
|
|
591
|
+
|
|
592
|
+
Parameters
|
|
593
|
+
----------
|
|
594
|
+
item_id : UUID
|
|
595
|
+
The item/artifact Id.
|
|
596
|
+
workspace : str, default=None
|
|
597
|
+
The Fabric workspace name.
|
|
598
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
599
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
600
|
+
|
|
601
|
+
Returns
|
|
602
|
+
-------
|
|
603
|
+
str
|
|
604
|
+
The item type for the item Id.
|
|
605
|
+
"""
|
|
606
|
+
|
|
607
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
608
|
+
dfI = fabric.list_items(workspace=workspace)
|
|
609
|
+
dfI_filt = dfI[dfI["Id"] == item_id]
|
|
610
|
+
|
|
611
|
+
if len(dfI_filt) == 0:
|
|
612
|
+
raise ValueError(
|
|
613
|
+
f"Invalid 'item_id' parameter. The '{item_id}' item was not found in the '{workspace}' workspace."
|
|
614
|
+
)
|
|
615
|
+
item_type = dfI_filt["Type"].iloc[0]
|
|
616
|
+
|
|
617
|
+
return item_type
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def resolve_dataset_from_report(
|
|
621
|
+
report: str, workspace: Optional[str] = None
|
|
622
|
+
) -> Tuple[UUID, str, UUID, str]:
|
|
623
|
+
"""
|
|
624
|
+
Obtains the basic semantic model properties from which the report's data is sourced.
|
|
625
|
+
|
|
626
|
+
Parameters
|
|
627
|
+
----------
|
|
628
|
+
report : str
|
|
629
|
+
The name of the Power BI report.
|
|
630
|
+
workspace : str, default=None
|
|
631
|
+
The Fabric workspace name.
|
|
632
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
633
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
634
|
+
|
|
635
|
+
Returns
|
|
636
|
+
-------
|
|
637
|
+
Tuple[UUID, str, UUID, str]
|
|
638
|
+
The semantic model UUID, semantic model name, semantic model workspace UUID, semantic model workspace name
|
|
639
|
+
"""
|
|
640
|
+
|
|
641
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
642
|
+
|
|
643
|
+
dfR = fabric.list_reports(workspace=workspace)
|
|
644
|
+
dfR_filt = dfR[dfR["Name"] == report]
|
|
645
|
+
if len(dfR_filt) == 0:
|
|
646
|
+
raise ValueError(
|
|
647
|
+
f"{icons.red_dot} The '{report}' report does not exist within the '{workspace}' workspace."
|
|
648
|
+
)
|
|
649
|
+
dataset_id = dfR_filt["Dataset Id"].iloc[0]
|
|
650
|
+
dataset_workspace_id = dfR_filt["Dataset Workspace Id"].iloc[0]
|
|
651
|
+
dataset_workspace = fabric.resolve_workspace_name(dataset_workspace_id)
|
|
652
|
+
dataset_name = resolve_dataset_name(
|
|
653
|
+
dataset_id=dataset_id, workspace=dataset_workspace
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
return dataset_id, dataset_name, dataset_workspace_id, dataset_workspace
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
def _add_part(target_dict, path, payload):
|
|
660
|
+
|
|
661
|
+
part = {"path": path, "payload": payload, "payloadType": "InlineBase64"}
|
|
662
|
+
|
|
663
|
+
target_dict["definition"]["parts"].append(part)
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def resolve_workspace_capacity(workspace: Optional[str] = None) -> Tuple[UUID, str]:
|
|
667
|
+
"""
|
|
668
|
+
Obtains the capacity Id and capacity name for a given workspace.
|
|
669
|
+
|
|
670
|
+
Parameters
|
|
671
|
+
----------
|
|
672
|
+
workspace : str, default=None
|
|
673
|
+
The Fabric workspace name.
|
|
674
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
675
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
676
|
+
|
|
677
|
+
Returns
|
|
678
|
+
-------
|
|
679
|
+
Tuple[UUID, str]
|
|
680
|
+
capacity Id; capacity came.
|
|
681
|
+
"""
|
|
682
|
+
|
|
683
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
684
|
+
dfW = fabric.list_workspaces(filter=f"name eq '{workspace}'")
|
|
685
|
+
capacity_id = dfW["Capacity Id"].iloc[0]
|
|
686
|
+
dfC = fabric.list_capacities()
|
|
687
|
+
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
688
|
+
if len(dfC_filt) == 1:
|
|
689
|
+
capacity_name = dfC_filt["Display Name"].iloc[0]
|
|
690
|
+
else:
|
|
691
|
+
capacity_name = None
|
|
692
|
+
|
|
693
|
+
return capacity_id, capacity_name
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def get_capacity_id(workspace: Optional[str] = None) -> UUID:
|
|
697
|
+
"""
|
|
698
|
+
Obtains the Capacity Id for a given workspace.
|
|
699
|
+
|
|
700
|
+
Parameters
|
|
701
|
+
----------
|
|
702
|
+
workspace : str, default=None
|
|
703
|
+
The Fabric workspace name.
|
|
704
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
705
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
706
|
+
|
|
707
|
+
Returns
|
|
708
|
+
-------
|
|
709
|
+
UUID
|
|
710
|
+
The capacity Id.
|
|
711
|
+
"""
|
|
712
|
+
|
|
713
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
714
|
+
dfW = fabric.list_workspaces(filter=f"name eq '{workspace}'")
|
|
715
|
+
if len(dfW) == 0:
|
|
716
|
+
raise ValueError(f"{icons.red_dot} The '{workspace}' does not exist'.")
|
|
717
|
+
|
|
718
|
+
return dfW["Capacity Id"].iloc[0]
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def get_capacity_name(workspace: Optional[str] = None) -> str:
|
|
722
|
+
"""
|
|
723
|
+
Obtains the capacity name for a given workspace.
|
|
724
|
+
|
|
725
|
+
Parameters
|
|
726
|
+
----------
|
|
727
|
+
workspace : str, default=None
|
|
728
|
+
The Fabric workspace name.
|
|
729
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
730
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
731
|
+
|
|
732
|
+
Returns
|
|
733
|
+
-------
|
|
734
|
+
str
|
|
735
|
+
The capacity name.
|
|
736
|
+
"""
|
|
737
|
+
|
|
738
|
+
capacity_id = get_capacity_id(workspace)
|
|
739
|
+
dfC = fabric.list_capacities()
|
|
740
|
+
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
741
|
+
if len(dfC_filt) == 0:
|
|
742
|
+
raise ValueError(
|
|
743
|
+
f"{icons.red_dot} The '{capacity_id}' capacity Id does not exist."
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
return dfC_filt["Display Name"].iloc[0]
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def resolve_capacity_name(capacity_id: Optional[UUID] = None) -> str:
|
|
750
|
+
"""
|
|
751
|
+
Obtains the capacity name for a given capacity Id.
|
|
752
|
+
|
|
753
|
+
Parameters
|
|
754
|
+
----------
|
|
755
|
+
capacity_id : UUID, default=None
|
|
756
|
+
The capacity Id.
|
|
757
|
+
Defaults to None which resolves to the capacity name of the workspace of the attached lakehouse
|
|
758
|
+
or if no lakehouse attached, resolves to the capacity name of the workspace of the notebook.
|
|
759
|
+
|
|
760
|
+
Returns
|
|
761
|
+
-------
|
|
762
|
+
str
|
|
763
|
+
The capacity name.
|
|
764
|
+
"""
|
|
765
|
+
|
|
766
|
+
if capacity_id is None:
|
|
767
|
+
return get_capacity_name()
|
|
768
|
+
|
|
769
|
+
dfC = fabric.list_capacities()
|
|
770
|
+
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
771
|
+
|
|
772
|
+
if len(dfC_filt) == 0:
|
|
773
|
+
raise ValueError(
|
|
774
|
+
f"{icons.red_dot} The '{capacity_id}' capacity Id does not exist."
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
return dfC_filt["Display Name"].iloc[0]
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
def retry(sleep_time: int, timeout_error_message: str):
|
|
781
|
+
def decorator(func):
|
|
782
|
+
@wraps(func)
|
|
783
|
+
def wrapper(*args, **kwargs):
|
|
784
|
+
start_time = datetime.datetime.now()
|
|
785
|
+
timeout = datetime.timedelta(minutes=1)
|
|
786
|
+
while datetime.datetime.now() - start_time <= timeout:
|
|
787
|
+
try:
|
|
788
|
+
return func(*args, **kwargs)
|
|
789
|
+
except Exception:
|
|
790
|
+
time.sleep(sleep_time)
|
|
791
|
+
raise TimeoutError(timeout_error_message)
|
|
792
|
+
|
|
793
|
+
return wrapper
|
|
794
|
+
|
|
795
|
+
return decorator
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def lro(
|
|
799
|
+
client,
|
|
800
|
+
response,
|
|
801
|
+
status_codes: Optional[List[str]] = [200, 202],
|
|
802
|
+
sleep_time: Optional[int] = 1,
|
|
803
|
+
return_status_code: Optional[bool] = False,
|
|
804
|
+
):
|
|
805
|
+
|
|
806
|
+
if response.status_code not in status_codes:
|
|
807
|
+
raise FabricHTTPException(response)
|
|
808
|
+
if response.status_code == status_codes[0]:
|
|
809
|
+
if return_status_code:
|
|
810
|
+
result = response.status_code
|
|
811
|
+
else:
|
|
812
|
+
result = response
|
|
813
|
+
if response.status_code == status_codes[1]:
|
|
814
|
+
operationId = response.headers["x-ms-operation-id"]
|
|
815
|
+
response = client.get(f"/v1/operations/{operationId}")
|
|
816
|
+
response_body = json.loads(response.content)
|
|
817
|
+
while response_body["status"] not in ["Succeeded", "Failed"]:
|
|
818
|
+
time.sleep(sleep_time)
|
|
819
|
+
response = client.get(f"/v1/operations/{operationId}")
|
|
820
|
+
response_body = json.loads(response.content)
|
|
821
|
+
if response_body["status"] != "Succeeded":
|
|
822
|
+
raise FabricHTTPException(response)
|
|
823
|
+
if return_status_code:
|
|
824
|
+
result = response.status_code
|
|
825
|
+
else:
|
|
826
|
+
response = client.get(f"/v1/operations/{operationId}/result")
|
|
827
|
+
result = response
|
|
828
|
+
|
|
829
|
+
return result
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
def pagination(client, response):
|
|
833
|
+
|
|
834
|
+
responses = []
|
|
835
|
+
response_json = response.json()
|
|
836
|
+
responses.append(response_json)
|
|
837
|
+
|
|
838
|
+
# Check for pagination
|
|
839
|
+
continuation_token = response_json.get("continuationToken")
|
|
840
|
+
continuation_uri = response_json.get("continuationUri")
|
|
841
|
+
|
|
842
|
+
# Loop to handle pagination
|
|
843
|
+
while continuation_token is not None:
|
|
844
|
+
response = client.get(continuation_uri)
|
|
845
|
+
response_json = response.json()
|
|
846
|
+
responses.append(response_json)
|
|
847
|
+
|
|
848
|
+
# Update the continuation token and URI for the next iteration
|
|
849
|
+
continuation_token = response_json.get("continuationToken")
|
|
850
|
+
continuation_uri = response_json.get("continuationUri")
|
|
851
|
+
|
|
852
|
+
return responses
|
sempy_labs/_icons.py
CHANGED
|
@@ -8,3 +8,26 @@ start_bold = "\033[1m"
|
|
|
8
8
|
end_bold = "\033[0m"
|
|
9
9
|
bullet = "\u2022"
|
|
10
10
|
warning = "⚠️"
|
|
11
|
+
error = "\u274C"
|
|
12
|
+
info = "ℹ️"
|
|
13
|
+
data_type_mapping = {
|
|
14
|
+
"string": "String",
|
|
15
|
+
"int": "Int64",
|
|
16
|
+
"tinyint": "Int64",
|
|
17
|
+
"smallint": "Int64",
|
|
18
|
+
"bigint": "Int64",
|
|
19
|
+
"boolean": "Boolean",
|
|
20
|
+
"timestamp": "DateTime",
|
|
21
|
+
"date": "DateTime",
|
|
22
|
+
"decimal(38,18)": "Decimal",
|
|
23
|
+
"decimal(19,4)": "Decimal",
|
|
24
|
+
"double": "Double",
|
|
25
|
+
"float": "Double",
|
|
26
|
+
}
|
|
27
|
+
measure_icon = "\u2211"
|
|
28
|
+
table_icon = "\u229E"
|
|
29
|
+
column_icon = "\u229F"
|
|
30
|
+
model_bpa_name = "ModelBPA"
|
|
31
|
+
report_bpa_name = "ReportBPA"
|
|
32
|
+
severity_mapping = {warning: "Warning", error: "Error", info: "Info"}
|
|
33
|
+
special_characters = ['"', "/", '"', ":", "|", "<", ">", "*", "?", "'", "!"]
|