semantic-link-labs 0.9.5__py3-none-any.whl → 0.9.7__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.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/METADATA +8 -5
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/RECORD +65 -61
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +19 -1
- sempy_labs/_ai.py +3 -1
- sempy_labs/_capacities.py +37 -2
- sempy_labs/_capacity_migration.py +11 -14
- sempy_labs/_connections.py +2 -4
- sempy_labs/_dataflows.py +2 -2
- sempy_labs/_dax_query_view.py +57 -0
- sempy_labs/_delta_analyzer.py +16 -14
- sempy_labs/_delta_analyzer_history.py +298 -0
- sempy_labs/_environments.py +8 -1
- sempy_labs/_eventhouses.py +5 -1
- sempy_labs/_external_data_shares.py +4 -10
- sempy_labs/_generate_semantic_model.py +2 -1
- sempy_labs/_graphQL.py +5 -1
- sempy_labs/_helper_functions.py +440 -63
- sempy_labs/_icons.py +6 -6
- sempy_labs/_kql_databases.py +5 -1
- sempy_labs/_list_functions.py +8 -38
- sempy_labs/_managed_private_endpoints.py +9 -2
- sempy_labs/_mirrored_databases.py +3 -1
- sempy_labs/_ml_experiments.py +1 -1
- sempy_labs/_model_bpa.py +2 -11
- sempy_labs/_model_bpa_bulk.py +33 -38
- sempy_labs/_model_bpa_rules.py +1 -1
- sempy_labs/_one_lake_integration.py +2 -1
- sempy_labs/_semantic_models.py +20 -0
- sempy_labs/_sql.py +6 -2
- sempy_labs/_sqldatabase.py +61 -100
- sempy_labs/_vertipaq.py +8 -11
- sempy_labs/_warehouses.py +14 -3
- sempy_labs/_workspace_identity.py +6 -0
- sempy_labs/_workspaces.py +42 -2
- sempy_labs/admin/_basic_functions.py +29 -2
- sempy_labs/admin/_reports.py +1 -1
- sempy_labs/admin/_scanner.py +2 -4
- sempy_labs/admin/_tenant.py +8 -3
- sempy_labs/directlake/_directlake_schema_compare.py +2 -1
- sempy_labs/directlake/_directlake_schema_sync.py +65 -19
- sempy_labs/directlake/_dl_helper.py +0 -6
- sempy_labs/directlake/_generate_shared_expression.py +19 -12
- sempy_labs/directlake/_guardrails.py +2 -1
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +90 -57
- sempy_labs/directlake/_update_directlake_partition_entity.py +5 -2
- sempy_labs/graph/_groups.py +6 -0
- sempy_labs/graph/_teams.py +2 -0
- sempy_labs/graph/_users.py +4 -0
- sempy_labs/lakehouse/__init__.py +12 -3
- sempy_labs/lakehouse/_blobs.py +231 -0
- sempy_labs/lakehouse/_shortcuts.py +29 -8
- sempy_labs/migration/_direct_lake_to_import.py +47 -10
- sempy_labs/migration/_migration_validation.py +0 -4
- sempy_labs/report/__init__.py +4 -0
- sempy_labs/report/_download_report.py +4 -6
- sempy_labs/report/_generate_report.py +6 -6
- sempy_labs/report/_report_functions.py +5 -4
- sempy_labs/report/_report_helper.py +17 -5
- sempy_labs/report/_report_rebind.py +8 -6
- sempy_labs/report/_reportwrapper.py +17 -8
- sempy_labs/report/_save_report.py +147 -0
- sempy_labs/tom/_model.py +154 -23
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info/licenses}/LICENSE +0 -0
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/top_level.txt +0 -0
sempy_labs/_helper_functions.py
CHANGED
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import base64
|
|
5
5
|
import time
|
|
6
6
|
import uuid
|
|
7
|
-
from sempy.fabric.exceptions import FabricHTTPException
|
|
7
|
+
from sempy.fabric.exceptions import FabricHTTPException, WorkspaceNotFoundException
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from functools import wraps
|
|
10
10
|
import datetime
|
|
@@ -39,6 +39,7 @@ def create_abfss_path(
|
|
|
39
39
|
lakehouse_id: UUID,
|
|
40
40
|
lakehouse_workspace_id: UUID,
|
|
41
41
|
delta_table_name: Optional[str] = None,
|
|
42
|
+
schema: Optional[str] = None,
|
|
42
43
|
) -> str:
|
|
43
44
|
"""
|
|
44
45
|
Creates an abfss path for a delta table in a Fabric lakehouse.
|
|
@@ -51,6 +52,8 @@ def create_abfss_path(
|
|
|
51
52
|
ID of the Fabric workspace.
|
|
52
53
|
delta_table_name : str, default=None
|
|
53
54
|
Name of the delta table name.
|
|
55
|
+
schema : str, default=None
|
|
56
|
+
The schema of the delta table.
|
|
54
57
|
|
|
55
58
|
Returns
|
|
56
59
|
-------
|
|
@@ -62,6 +65,8 @@ def create_abfss_path(
|
|
|
62
65
|
path = f"abfss://{lakehouse_workspace_id}@{fp}/{lakehouse_id}"
|
|
63
66
|
|
|
64
67
|
if delta_table_name is not None:
|
|
68
|
+
if schema is not None:
|
|
69
|
+
path += f"/{schema}"
|
|
65
70
|
path += f"/Tables/{delta_table_name}"
|
|
66
71
|
|
|
67
72
|
return path
|
|
@@ -178,9 +183,7 @@ def resolve_report_name(report_id: UUID, workspace: Optional[str | UUID] = None)
|
|
|
178
183
|
The name of the Power BI report.
|
|
179
184
|
"""
|
|
180
185
|
|
|
181
|
-
return
|
|
182
|
-
item_id=report_id, type="Report", workspace=workspace
|
|
183
|
-
)
|
|
186
|
+
return resolve_item_name(item_id=report_id, workspace=workspace)
|
|
184
187
|
|
|
185
188
|
|
|
186
189
|
def delete_item(
|
|
@@ -305,37 +308,84 @@ def get_item_definition(
|
|
|
305
308
|
|
|
306
309
|
|
|
307
310
|
def resolve_item_id(
|
|
308
|
-
item: str | UUID, type: str, workspace: Optional[str] = None
|
|
311
|
+
item: str | UUID, type: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
309
312
|
) -> UUID:
|
|
310
313
|
|
|
314
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
315
|
+
item_id = None
|
|
316
|
+
|
|
311
317
|
if _is_valid_uuid(item):
|
|
312
|
-
|
|
318
|
+
# Check (optional)
|
|
319
|
+
item_id = item
|
|
320
|
+
try:
|
|
321
|
+
_base_api(
|
|
322
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}",
|
|
323
|
+
client="fabric_sp",
|
|
324
|
+
)
|
|
325
|
+
except FabricHTTPException:
|
|
326
|
+
raise ValueError(
|
|
327
|
+
f"{icons.red_dot} The '{item_id}' item was not found in the '{workspace_name}' workspace."
|
|
328
|
+
)
|
|
313
329
|
else:
|
|
314
|
-
|
|
330
|
+
if type is None:
|
|
331
|
+
raise ValueError(
|
|
332
|
+
f"{icons.red_dot} The 'type' parameter is required if specifying an item name."
|
|
333
|
+
)
|
|
334
|
+
responses = _base_api(
|
|
335
|
+
request=f"/v1/workspaces/{workspace_id}/items?type={type}",
|
|
336
|
+
client="fabric_sp",
|
|
337
|
+
uses_pagination=True,
|
|
338
|
+
)
|
|
339
|
+
for r in responses:
|
|
340
|
+
for v in r.get("value", []):
|
|
341
|
+
display_name = v.get("displayName")
|
|
342
|
+
if display_name == item:
|
|
343
|
+
item_id = v.get("id")
|
|
344
|
+
break
|
|
345
|
+
|
|
346
|
+
if item_id is None:
|
|
347
|
+
raise ValueError(
|
|
348
|
+
f"{icons.red_dot} There's no item '{item}' of type '{type}' in the '{workspace_name}' workspace."
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
return item_id
|
|
315
352
|
|
|
316
353
|
|
|
317
354
|
def resolve_item_name_and_id(
|
|
318
355
|
item: str | UUID, type: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
319
356
|
) -> Tuple[str, UUID]:
|
|
320
357
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
item_id=item_id, type=type, workspace=workspace_id
|
|
358
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
359
|
+
item_id = resolve_item_id(item=item, type=type, workspace=workspace_id)
|
|
360
|
+
item_name = (
|
|
361
|
+
_base_api(
|
|
362
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}", client="fabric_sp"
|
|
327
363
|
)
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
364
|
+
.json()
|
|
365
|
+
.get("displayName")
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return item_name, item_id
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def resolve_item_name(item_id: UUID, workspace: Optional[str | UUID] = None) -> str:
|
|
372
|
+
|
|
373
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
374
|
+
try:
|
|
375
|
+
item_name = (
|
|
376
|
+
_base_api(
|
|
377
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}",
|
|
378
|
+
client="fabric_sp",
|
|
332
379
|
)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
380
|
+
.json()
|
|
381
|
+
.get("displayName")
|
|
382
|
+
)
|
|
383
|
+
except FabricHTTPException:
|
|
384
|
+
raise ValueError(
|
|
385
|
+
f"{icons.red_dot} The '{item_id}' item was not found in the '{workspace_id}' workspace."
|
|
336
386
|
)
|
|
337
387
|
|
|
338
|
-
return item_name
|
|
388
|
+
return item_name
|
|
339
389
|
|
|
340
390
|
|
|
341
391
|
def resolve_lakehouse_name_and_id(
|
|
@@ -346,19 +396,18 @@ def resolve_lakehouse_name_and_id(
|
|
|
346
396
|
type = "Lakehouse"
|
|
347
397
|
|
|
348
398
|
if lakehouse is None:
|
|
349
|
-
lakehouse_id =
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
lakehouse_id =
|
|
355
|
-
|
|
356
|
-
item_id=lakehouse_id, type=type, workspace=workspace_id
|
|
399
|
+
lakehouse_id = _get_fabric_context_setting(name="trident.lakehouse.id")
|
|
400
|
+
if lakehouse_id == "":
|
|
401
|
+
raise ValueError(
|
|
402
|
+
f"{icons.red_dot} Cannot resolve a lakehouse. Please enter a valid lakehouse or make sure a lakehouse is attached to the notebook."
|
|
403
|
+
)
|
|
404
|
+
(lakehouse_name, lakehouse_id) = resolve_item_name_and_id(
|
|
405
|
+
item=lakehouse_id, type=type, workspace=workspace_id
|
|
357
406
|
)
|
|
407
|
+
|
|
358
408
|
else:
|
|
359
|
-
lakehouse_name =
|
|
360
|
-
|
|
361
|
-
item_name=lakehouse, type=type, workspace=workspace_id
|
|
409
|
+
(lakehouse_name, lakehouse_id) = resolve_item_name_and_id(
|
|
410
|
+
item=lakehouse, type=type, workspace=workspace_id
|
|
362
411
|
)
|
|
363
412
|
|
|
364
413
|
return lakehouse_name, lakehouse_id
|
|
@@ -420,9 +469,7 @@ def resolve_dataset_name(
|
|
|
420
469
|
The name of the semantic model.
|
|
421
470
|
"""
|
|
422
471
|
|
|
423
|
-
return
|
|
424
|
-
item_id=dataset_id, type="SemanticModel", workspace=workspace
|
|
425
|
-
)
|
|
472
|
+
return resolve_item_name(item_id=dataset_id, workspace=workspace)
|
|
426
473
|
|
|
427
474
|
|
|
428
475
|
def resolve_lakehouse_name(
|
|
@@ -448,11 +495,13 @@ def resolve_lakehouse_name(
|
|
|
448
495
|
"""
|
|
449
496
|
|
|
450
497
|
if lakehouse_id is None:
|
|
451
|
-
lakehouse_id =
|
|
498
|
+
lakehouse_id = _get_fabric_context_setting(name="trident.lakehouse.id")
|
|
499
|
+
if lakehouse_id == "":
|
|
500
|
+
raise ValueError(
|
|
501
|
+
f"{icons.red_dot} Cannot resolve a lakehouse. Please enter a valid lakehouse or make sure a lakehouse is attached to the notebook."
|
|
502
|
+
)
|
|
452
503
|
|
|
453
|
-
return
|
|
454
|
-
item_id=lakehouse_id, type="Lakehouse", workspace=workspace
|
|
455
|
-
)
|
|
504
|
+
return resolve_item_name(item_id=lakehouse_id, workspace=workspace)
|
|
456
505
|
|
|
457
506
|
|
|
458
507
|
def resolve_lakehouse_id(
|
|
@@ -477,12 +526,14 @@ def resolve_lakehouse_id(
|
|
|
477
526
|
"""
|
|
478
527
|
|
|
479
528
|
if lakehouse is None:
|
|
480
|
-
lakehouse_id =
|
|
481
|
-
|
|
482
|
-
|
|
529
|
+
lakehouse_id = _get_fabric_context_setting(name="trident.lakehouse.id")
|
|
530
|
+
if lakehouse_id == "":
|
|
531
|
+
raise ValueError(
|
|
532
|
+
f"{icons.red_dot} Cannot resolve a lakehouse. Please enter a valid lakehouse or make sure a lakehouse is attached to the notebook."
|
|
533
|
+
)
|
|
483
534
|
else:
|
|
484
|
-
lakehouse_id =
|
|
485
|
-
|
|
535
|
+
lakehouse_id = resolve_item_id(
|
|
536
|
+
item=lakehouse, type="Lakehouse", workspace=workspace
|
|
486
537
|
)
|
|
487
538
|
|
|
488
539
|
return lakehouse_id
|
|
@@ -751,6 +802,55 @@ def language_validate(language: str):
|
|
|
751
802
|
return lang
|
|
752
803
|
|
|
753
804
|
|
|
805
|
+
def resolve_workspace_id(
|
|
806
|
+
workspace: Optional[str | UUID] = None,
|
|
807
|
+
) -> UUID:
|
|
808
|
+
if workspace is None:
|
|
809
|
+
workspace_id = _get_fabric_context_setting(name="trident.workspace.id")
|
|
810
|
+
elif _is_valid_uuid(workspace):
|
|
811
|
+
# Check (optional)
|
|
812
|
+
workspace_id = workspace
|
|
813
|
+
try:
|
|
814
|
+
_base_api(request=f"/v1/workspaces/{workspace_id}", client="fabric_sp")
|
|
815
|
+
except FabricHTTPException:
|
|
816
|
+
raise ValueError(
|
|
817
|
+
f"{icons.red_dot} The '{workspace_id}' workspace was not found."
|
|
818
|
+
)
|
|
819
|
+
else:
|
|
820
|
+
responses = _base_api(
|
|
821
|
+
request="/v1/workspaces", client="fabric_sp", uses_pagination=True
|
|
822
|
+
)
|
|
823
|
+
workspace_id = None
|
|
824
|
+
for r in responses:
|
|
825
|
+
for v in r.get("value", []):
|
|
826
|
+
display_name = v.get("displayName")
|
|
827
|
+
if display_name == workspace:
|
|
828
|
+
workspace_id = v.get("id")
|
|
829
|
+
break
|
|
830
|
+
|
|
831
|
+
if workspace_id is None:
|
|
832
|
+
raise WorkspaceNotFoundException(workspace)
|
|
833
|
+
|
|
834
|
+
return workspace_id
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
def resolve_workspace_name(workspace_id: Optional[UUID] = None) -> str:
|
|
838
|
+
|
|
839
|
+
if workspace_id is None:
|
|
840
|
+
workspace_id = _get_fabric_context_setting(name="trident.workspace.id")
|
|
841
|
+
|
|
842
|
+
try:
|
|
843
|
+
response = _base_api(
|
|
844
|
+
request=f"/v1/workspaces/{workspace_id}", client="fabric_sp"
|
|
845
|
+
).json()
|
|
846
|
+
except FabricHTTPException:
|
|
847
|
+
raise ValueError(
|
|
848
|
+
f"{icons.red_dot} The '{workspace_id}' workspace was not found."
|
|
849
|
+
)
|
|
850
|
+
|
|
851
|
+
return response.get("displayName")
|
|
852
|
+
|
|
853
|
+
|
|
754
854
|
def resolve_workspace_name_and_id(
|
|
755
855
|
workspace: Optional[str | UUID] = None,
|
|
756
856
|
) -> Tuple[str, str]:
|
|
@@ -771,16 +871,136 @@ def resolve_workspace_name_and_id(
|
|
|
771
871
|
"""
|
|
772
872
|
|
|
773
873
|
if workspace is None:
|
|
774
|
-
workspace_id =
|
|
775
|
-
workspace_name =
|
|
874
|
+
workspace_id = _get_fabric_context_setting(name="trident.workspace.id")
|
|
875
|
+
workspace_name = resolve_workspace_name(workspace_id)
|
|
776
876
|
elif _is_valid_uuid(workspace):
|
|
777
877
|
workspace_id = workspace
|
|
778
|
-
workspace_name =
|
|
878
|
+
workspace_name = resolve_workspace_name(workspace_id)
|
|
879
|
+
else:
|
|
880
|
+
responses = _base_api(
|
|
881
|
+
request="/v1/workspaces", client="fabric_sp", uses_pagination=True
|
|
882
|
+
)
|
|
883
|
+
workspace_id = None
|
|
884
|
+
workspace_name = None
|
|
885
|
+
for r in responses:
|
|
886
|
+
for v in r.get("value", []):
|
|
887
|
+
display_name = v.get("displayName")
|
|
888
|
+
if display_name == workspace:
|
|
889
|
+
workspace_name = workspace
|
|
890
|
+
workspace_id = v.get("id")
|
|
891
|
+
break
|
|
892
|
+
|
|
893
|
+
if workspace_name is None or workspace_id is None:
|
|
894
|
+
raise WorkspaceNotFoundException(workspace)
|
|
895
|
+
|
|
896
|
+
return workspace_name, workspace_id
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
def resolve_item_id(
|
|
900
|
+
item: str | UUID, type: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
901
|
+
) -> UUID:
|
|
902
|
+
|
|
903
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
904
|
+
item_id = None
|
|
905
|
+
|
|
906
|
+
if _is_valid_uuid(item):
|
|
907
|
+
# Check (optional)
|
|
908
|
+
item_id = item
|
|
909
|
+
try:
|
|
910
|
+
_base_api(
|
|
911
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}",
|
|
912
|
+
client="fabric_sp",
|
|
913
|
+
)
|
|
914
|
+
except FabricHTTPException:
|
|
915
|
+
raise ValueError(
|
|
916
|
+
f"{icons.red_dot} The '{item_id}' item was not found in the '{workspace_name}' workspace."
|
|
917
|
+
)
|
|
918
|
+
else:
|
|
919
|
+
if type is None:
|
|
920
|
+
raise ValueError(
|
|
921
|
+
f"{icons.red_dot} The 'type' parameter is required if specifying an item name."
|
|
922
|
+
)
|
|
923
|
+
responses = _base_api(
|
|
924
|
+
request=f"/v1/workspaces/{workspace_id}/items?type={type}",
|
|
925
|
+
client="fabric_sp",
|
|
926
|
+
uses_pagination=True,
|
|
927
|
+
)
|
|
928
|
+
for r in responses:
|
|
929
|
+
for v in r.get("value", []):
|
|
930
|
+
display_name = v.get("displayName")
|
|
931
|
+
if display_name == item:
|
|
932
|
+
item_id = v.get("id")
|
|
933
|
+
break
|
|
934
|
+
|
|
935
|
+
if item_id is None:
|
|
936
|
+
raise ValueError(
|
|
937
|
+
f"{icons.red_dot} There's no item '{item}' of type '{type}' in the '{workspace_name}' workspace."
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
return item_id
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
def resolve_item_name_and_id(
|
|
944
|
+
item: str | UUID, type: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
945
|
+
) -> Tuple[str, UUID]:
|
|
946
|
+
|
|
947
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
948
|
+
item_id = resolve_item_id(item=item, type=type, workspace=workspace_id)
|
|
949
|
+
item_name = (
|
|
950
|
+
_base_api(
|
|
951
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}", client="fabric_sp"
|
|
952
|
+
)
|
|
953
|
+
.json()
|
|
954
|
+
.get("displayName")
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
return item_name, item_id
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
def resolve_item_name(item_id: UUID, workspace: Optional[str | UUID] = None) -> str:
|
|
961
|
+
|
|
962
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
963
|
+
try:
|
|
964
|
+
item_name = (
|
|
965
|
+
_base_api(
|
|
966
|
+
request=f"/v1/workspaces/{workspace_id}/items/{item_id}",
|
|
967
|
+
client="fabric_sp",
|
|
968
|
+
)
|
|
969
|
+
.json()
|
|
970
|
+
.get("displayName")
|
|
971
|
+
)
|
|
972
|
+
except FabricHTTPException:
|
|
973
|
+
raise ValueError(
|
|
974
|
+
f"{icons.red_dot} The '{item_id}' item was not found in the '{workspace_id}' workspace."
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
return item_name
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
def resolve_lakehouse_name_and_id(
|
|
981
|
+
lakehouse: Optional[str | UUID] = None, workspace: Optional[str | UUID] = None
|
|
982
|
+
) -> Tuple[str, UUID]:
|
|
983
|
+
|
|
984
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
985
|
+
type = "Lakehouse"
|
|
986
|
+
|
|
987
|
+
if lakehouse is None:
|
|
988
|
+
lakehouse_id = fabric.get_lakehouse_id()
|
|
989
|
+
lakehouse_name = fabric.resolve_item_name(
|
|
990
|
+
item_id=lakehouse_id, type=type, workspace=workspace_id
|
|
991
|
+
)
|
|
992
|
+
elif _is_valid_uuid(lakehouse):
|
|
993
|
+
lakehouse_id = lakehouse
|
|
994
|
+
lakehouse_name = fabric.resolve_item_name(
|
|
995
|
+
item_id=lakehouse_id, type=type, workspace=workspace_id
|
|
996
|
+
)
|
|
779
997
|
else:
|
|
780
|
-
|
|
781
|
-
|
|
998
|
+
lakehouse_name = lakehouse
|
|
999
|
+
lakehouse_id = fabric.resolve_item_id(
|
|
1000
|
+
item_name=lakehouse, type=type, workspace=workspace_id
|
|
1001
|
+
)
|
|
782
1002
|
|
|
783
|
-
return
|
|
1003
|
+
return lakehouse_name, lakehouse_id
|
|
784
1004
|
|
|
785
1005
|
|
|
786
1006
|
def _extract_json(dataframe: pd.DataFrame) -> dict:
|
|
@@ -893,7 +1113,7 @@ def resolve_dataset_from_report(
|
|
|
893
1113
|
dfR = _get_report(report=report, workspace=workspace)
|
|
894
1114
|
dataset_id = dfR["Dataset Id"].iloc[0]
|
|
895
1115
|
dataset_workspace_id = dfR["Dataset Workspace Id"].iloc[0]
|
|
896
|
-
dataset_workspace =
|
|
1116
|
+
dataset_workspace = resolve_workspace_name(workspace_id=dataset_workspace_id)
|
|
897
1117
|
dataset_name = resolve_dataset_name(
|
|
898
1118
|
dataset_id=dataset_id, workspace=dataset_workspace
|
|
899
1119
|
)
|
|
@@ -926,12 +1146,13 @@ def resolve_workspace_capacity(
|
|
|
926
1146
|
Tuple[uuid.UUID, str]
|
|
927
1147
|
capacity Id; capacity came.
|
|
928
1148
|
"""
|
|
1149
|
+
from sempy_labs._capacities import list_capacities
|
|
929
1150
|
|
|
930
1151
|
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
931
1152
|
filter_condition = urllib.parse.quote(workspace_id)
|
|
932
1153
|
dfW = fabric.list_workspaces(filter=f"id eq '{filter_condition}'")
|
|
933
1154
|
capacity_id = dfW["Capacity Id"].iloc[0]
|
|
934
|
-
dfC =
|
|
1155
|
+
dfC = list_capacities()
|
|
935
1156
|
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
936
1157
|
if len(dfC_filt) == 1:
|
|
937
1158
|
capacity_name = dfC_filt["Display Name"].iloc[0]
|
|
@@ -989,8 +1210,10 @@ def get_capacity_name(workspace: Optional[str | UUID] = None) -> str:
|
|
|
989
1210
|
The capacity name.
|
|
990
1211
|
"""
|
|
991
1212
|
|
|
1213
|
+
from sempy_labs._capacities import list_capacities
|
|
1214
|
+
|
|
992
1215
|
capacity_id = get_capacity_id(workspace)
|
|
993
|
-
dfC =
|
|
1216
|
+
dfC = list_capacities()
|
|
994
1217
|
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
995
1218
|
if dfC_filt.empty:
|
|
996
1219
|
raise ValueError(
|
|
@@ -1016,11 +1239,12 @@ def resolve_capacity_name(capacity_id: Optional[UUID] = None) -> str:
|
|
|
1016
1239
|
str
|
|
1017
1240
|
The capacity name.
|
|
1018
1241
|
"""
|
|
1242
|
+
from sempy_labs._capacities import list_capacities
|
|
1019
1243
|
|
|
1020
1244
|
if capacity_id is None:
|
|
1021
1245
|
return get_capacity_name()
|
|
1022
1246
|
|
|
1023
|
-
dfC =
|
|
1247
|
+
dfC = list_capacities()
|
|
1024
1248
|
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
1025
1249
|
|
|
1026
1250
|
if dfC_filt.empty:
|
|
@@ -1047,6 +1271,7 @@ def resolve_capacity_id(capacity: Optional[str | UUID] = None, **kwargs) -> UUID
|
|
|
1047
1271
|
uuid.UUID
|
|
1048
1272
|
The capacity Id.
|
|
1049
1273
|
"""
|
|
1274
|
+
from sempy_labs._capacities import list_capacities
|
|
1050
1275
|
|
|
1051
1276
|
if "capacity_name" in kwargs:
|
|
1052
1277
|
capacity = kwargs["capacity_name"]
|
|
@@ -1059,7 +1284,7 @@ def resolve_capacity_id(capacity: Optional[str | UUID] = None, **kwargs) -> UUID
|
|
|
1059
1284
|
if _is_valid_uuid(capacity):
|
|
1060
1285
|
return capacity
|
|
1061
1286
|
|
|
1062
|
-
dfC =
|
|
1287
|
+
dfC = list_capacities()
|
|
1063
1288
|
dfC_filt = dfC[dfC["Display Name"] == capacity]
|
|
1064
1289
|
|
|
1065
1290
|
if dfC_filt.empty:
|
|
@@ -1186,10 +1411,8 @@ class FabricTokenCredential(TokenCredential):
|
|
|
1186
1411
|
|
|
1187
1412
|
import notebookutils
|
|
1188
1413
|
|
|
1189
|
-
token = notebookutils.credentials.getToken(
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
return access_token
|
|
1414
|
+
token = notebookutils.credentials.getToken("storage")
|
|
1415
|
+
return AccessToken(token, 0)
|
|
1193
1416
|
|
|
1194
1417
|
|
|
1195
1418
|
def _get_adls_client(account_name):
|
|
@@ -1198,11 +1421,21 @@ def _get_adls_client(account_name):
|
|
|
1198
1421
|
|
|
1199
1422
|
account_url = f"https://{account_name}.dfs.core.windows.net"
|
|
1200
1423
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1424
|
+
return DataLakeServiceClient(account_url, credential=FabricTokenCredential())
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
def _get_blob_client(workspace_id: UUID, item_id: UUID):
|
|
1428
|
+
|
|
1429
|
+
from azure.storage.blob import BlobServiceClient
|
|
1430
|
+
|
|
1431
|
+
endpoint = _get_fabric_context_setting(name="trident.onelake.endpoint").replace(
|
|
1432
|
+
".dfs.", ".blob."
|
|
1203
1433
|
)
|
|
1434
|
+
url = f"https://{endpoint}/{workspace_id}/{item_id}"
|
|
1204
1435
|
|
|
1205
|
-
|
|
1436
|
+
# account_url = f"https://{account_name}.blob.core.windows.net"
|
|
1437
|
+
|
|
1438
|
+
return BlobServiceClient(url, credential=FabricTokenCredential())
|
|
1206
1439
|
|
|
1207
1440
|
|
|
1208
1441
|
def resolve_warehouse_id(
|
|
@@ -1558,6 +1791,7 @@ def _convert_data_type(input_data_type: str) -> str:
|
|
|
1558
1791
|
"date": "DateTime",
|
|
1559
1792
|
"double": "Double",
|
|
1560
1793
|
"float": "Double",
|
|
1794
|
+
"binary": "Boolean",
|
|
1561
1795
|
}
|
|
1562
1796
|
|
|
1563
1797
|
if "decimal" in input_data_type:
|
|
@@ -1766,7 +2000,9 @@ def _run_spark_sql_query(query):
|
|
|
1766
2000
|
return spark.sql(query)
|
|
1767
2001
|
|
|
1768
2002
|
|
|
1769
|
-
def _mount(
|
|
2003
|
+
def _mount(
|
|
2004
|
+
lakehouse: Optional[str | UUID] = None, workspace: Optional[str | UUID] = None
|
|
2005
|
+
) -> str:
|
|
1770
2006
|
"""
|
|
1771
2007
|
Mounts a lakehouse to a notebook if it is not already mounted. Returns the local path to the lakehouse.
|
|
1772
2008
|
"""
|
|
@@ -1778,6 +2014,16 @@ def _mount(lakehouse, workspace) -> str:
|
|
|
1778
2014
|
lakehouse=lakehouse, workspace=workspace
|
|
1779
2015
|
)
|
|
1780
2016
|
|
|
2017
|
+
# Hide display mounts
|
|
2018
|
+
current_setting = ""
|
|
2019
|
+
try:
|
|
2020
|
+
current_setting = notebookutils.conf.get(
|
|
2021
|
+
"spark.notebookutils.displaymountpoint.enabled"
|
|
2022
|
+
)
|
|
2023
|
+
notebookutils.conf.set("spark.notebookutils.displaymountpoint.enabled", "false")
|
|
2024
|
+
except Exception:
|
|
2025
|
+
pass
|
|
2026
|
+
|
|
1781
2027
|
lake_path = create_abfss_path(lakehouse_id, workspace_id)
|
|
1782
2028
|
mounts = notebookutils.fs.mounts()
|
|
1783
2029
|
mount_point = f"/{workspace_name.replace(' ', '')}{lakehouse_name.replace(' ', '')}"
|
|
@@ -1789,8 +2035,139 @@ def _mount(lakehouse, workspace) -> str:
|
|
|
1789
2035
|
)
|
|
1790
2036
|
|
|
1791
2037
|
mounts = notebookutils.fs.mounts()
|
|
2038
|
+
|
|
2039
|
+
# Set display mounts to original setting
|
|
2040
|
+
try:
|
|
2041
|
+
if current_setting != "false":
|
|
2042
|
+
notebookutils.conf.set(
|
|
2043
|
+
"spark.notebookutils.displaymountpoint.enabled", "true"
|
|
2044
|
+
)
|
|
2045
|
+
except Exception:
|
|
2046
|
+
pass
|
|
2047
|
+
|
|
1792
2048
|
local_path = next(
|
|
1793
2049
|
i.get("localPath") for i in mounts if i.get("source") == lake_path
|
|
1794
2050
|
)
|
|
1795
2051
|
|
|
1796
2052
|
return local_path
|
|
2053
|
+
|
|
2054
|
+
|
|
2055
|
+
def _get_or_create_workspace(
|
|
2056
|
+
workspace: str,
|
|
2057
|
+
capacity: Optional[str | UUID] = None,
|
|
2058
|
+
description: Optional[str] = None,
|
|
2059
|
+
) -> Tuple[str, UUID]:
|
|
2060
|
+
|
|
2061
|
+
capacity_id = resolve_capacity_id(capacity)
|
|
2062
|
+
dfW = fabric.list_workspaces()
|
|
2063
|
+
dfW_filt_name = dfW[dfW["Name"] == workspace]
|
|
2064
|
+
dfW_filt_id = dfW[dfW["Id"] == workspace]
|
|
2065
|
+
|
|
2066
|
+
# Workspace already exists
|
|
2067
|
+
if (not dfW_filt_name.empty) or (not dfW_filt_id.empty):
|
|
2068
|
+
print(f"{icons.green_dot} The '{workspace}' workspace already exists.")
|
|
2069
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
2070
|
+
return (workspace_name, workspace_id)
|
|
2071
|
+
|
|
2072
|
+
# Do not create workspace with name of an ID
|
|
2073
|
+
if _is_valid_uuid(workspace):
|
|
2074
|
+
raise ValueError(f"{icons.warning} Must enter a workspace name, not an ID.")
|
|
2075
|
+
|
|
2076
|
+
print(f"{icons.in_progress} Creating the '{workspace}' workspace...")
|
|
2077
|
+
workspace_id = fabric.create_workspace(
|
|
2078
|
+
display_name=workspace, capacity_id=capacity_id, description=description
|
|
2079
|
+
)
|
|
2080
|
+
print(
|
|
2081
|
+
f"{icons.green_dot} The '{workspace}' workspace has been successfully created."
|
|
2082
|
+
)
|
|
2083
|
+
|
|
2084
|
+
return (workspace, workspace_id)
|
|
2085
|
+
|
|
2086
|
+
|
|
2087
|
+
def _get_or_create_lakehouse(
|
|
2088
|
+
lakehouse: str,
|
|
2089
|
+
workspace: Optional[str | UUID] = None,
|
|
2090
|
+
description: Optional[str] = None,
|
|
2091
|
+
) -> Tuple[str, UUID]:
|
|
2092
|
+
|
|
2093
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
2094
|
+
|
|
2095
|
+
dfI = fabric.list_items(type="Lakehouse", workspace=workspace)
|
|
2096
|
+
dfI_filt_name = dfI[dfI["Display Name"] == lakehouse]
|
|
2097
|
+
dfI_filt_id = dfI[dfI["Id"] == lakehouse]
|
|
2098
|
+
|
|
2099
|
+
if (not dfI_filt_name.empty) or (not dfI_filt_id.empty):
|
|
2100
|
+
print(f"{icons.green_dot} The '{lakehouse}' lakehouse already exists.")
|
|
2101
|
+
(lakehouse_name, lakehouse_id) = resolve_lakehouse_name_and_id(
|
|
2102
|
+
lakehouse=lakehouse, workspace=workspace
|
|
2103
|
+
)
|
|
2104
|
+
return (lakehouse_name, lakehouse_id)
|
|
2105
|
+
if _is_valid_uuid(lakehouse):
|
|
2106
|
+
raise ValueError(f"{icons.warning} Must enter a lakehouse name, not an ID.")
|
|
2107
|
+
|
|
2108
|
+
print(f"{icons.in_progress} Creating the '{lakehouse}' lakehouse...")
|
|
2109
|
+
lakehouse_id = fabric.create_lakehouse(
|
|
2110
|
+
display_name=lakehouse, workspace=workspace, description=description
|
|
2111
|
+
)
|
|
2112
|
+
print(
|
|
2113
|
+
f"{icons.green_dot} The '{lakehouse}' lakehouse has been successfully created within the '{workspace_name}' workspace."
|
|
2114
|
+
)
|
|
2115
|
+
|
|
2116
|
+
return (lakehouse, lakehouse_id)
|
|
2117
|
+
|
|
2118
|
+
|
|
2119
|
+
def _get_or_create_warehouse(
|
|
2120
|
+
warehouse: str,
|
|
2121
|
+
workspace: Optional[str | UUID] = None,
|
|
2122
|
+
description: Optional[str] = None,
|
|
2123
|
+
) -> Tuple[str, UUID]:
|
|
2124
|
+
|
|
2125
|
+
from sempy_labs._warehouses import create_warehouse
|
|
2126
|
+
|
|
2127
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
2128
|
+
|
|
2129
|
+
dfI = fabric.list_items(type="Warehouse", workspace=workspace)
|
|
2130
|
+
dfI_filt_name = dfI[dfI["Display Name"] == warehouse]
|
|
2131
|
+
dfI_filt_id = dfI[dfI["Id"] == warehouse]
|
|
2132
|
+
|
|
2133
|
+
if (not dfI_filt_name.empty) or (not dfI_filt_id.empty):
|
|
2134
|
+
print(f"{icons.green_dot} The '{warehouse}' warehouse already exists.")
|
|
2135
|
+
(warehouse_name, warehouse_id) = resolve_item_name_and_id(
|
|
2136
|
+
warehouse=warehouse, type="Warehouse", workspace=workspace
|
|
2137
|
+
)
|
|
2138
|
+
return (warehouse_name, warehouse_id)
|
|
2139
|
+
if _is_valid_uuid(warehouse):
|
|
2140
|
+
raise ValueError(f"{icons.warning} Must enter a warehouse name, not an ID.")
|
|
2141
|
+
|
|
2142
|
+
print(f"{icons.in_progress} Creating the '{warehouse}' warehouse...")
|
|
2143
|
+
warehouse_id = create_warehouse(
|
|
2144
|
+
display_name=warehouse, workspace=workspace, description=description
|
|
2145
|
+
)
|
|
2146
|
+
print(
|
|
2147
|
+
f"{icons.green_dot} The '{warehouse}' warehouse has been successfully created within the '{workspace_name}' workspace."
|
|
2148
|
+
)
|
|
2149
|
+
|
|
2150
|
+
return (warehouse, warehouse_id)
|
|
2151
|
+
|
|
2152
|
+
|
|
2153
|
+
def _xml_to_dict(element):
|
|
2154
|
+
data = {element.tag: {} if element.attrib else None}
|
|
2155
|
+
children = list(element)
|
|
2156
|
+
if children:
|
|
2157
|
+
temp_dict = {}
|
|
2158
|
+
for child in children:
|
|
2159
|
+
child_dict = _xml_to_dict(child)
|
|
2160
|
+
for key, value in child_dict.items():
|
|
2161
|
+
if key in temp_dict:
|
|
2162
|
+
if isinstance(temp_dict[key], list):
|
|
2163
|
+
temp_dict[key].append(value)
|
|
2164
|
+
else:
|
|
2165
|
+
temp_dict[key] = [temp_dict[key], value]
|
|
2166
|
+
else:
|
|
2167
|
+
temp_dict[key] = value
|
|
2168
|
+
data[element.tag] = temp_dict
|
|
2169
|
+
else:
|
|
2170
|
+
data[element.tag] = (
|
|
2171
|
+
element.text.strip() if element.text and element.text.strip() else None
|
|
2172
|
+
)
|
|
2173
|
+
return data
|