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.

Files changed (65) hide show
  1. {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/METADATA +8 -5
  2. {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/RECORD +65 -61
  3. {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +19 -1
  5. sempy_labs/_ai.py +3 -1
  6. sempy_labs/_capacities.py +37 -2
  7. sempy_labs/_capacity_migration.py +11 -14
  8. sempy_labs/_connections.py +2 -4
  9. sempy_labs/_dataflows.py +2 -2
  10. sempy_labs/_dax_query_view.py +57 -0
  11. sempy_labs/_delta_analyzer.py +16 -14
  12. sempy_labs/_delta_analyzer_history.py +298 -0
  13. sempy_labs/_environments.py +8 -1
  14. sempy_labs/_eventhouses.py +5 -1
  15. sempy_labs/_external_data_shares.py +4 -10
  16. sempy_labs/_generate_semantic_model.py +2 -1
  17. sempy_labs/_graphQL.py +5 -1
  18. sempy_labs/_helper_functions.py +440 -63
  19. sempy_labs/_icons.py +6 -6
  20. sempy_labs/_kql_databases.py +5 -1
  21. sempy_labs/_list_functions.py +8 -38
  22. sempy_labs/_managed_private_endpoints.py +9 -2
  23. sempy_labs/_mirrored_databases.py +3 -1
  24. sempy_labs/_ml_experiments.py +1 -1
  25. sempy_labs/_model_bpa.py +2 -11
  26. sempy_labs/_model_bpa_bulk.py +33 -38
  27. sempy_labs/_model_bpa_rules.py +1 -1
  28. sempy_labs/_one_lake_integration.py +2 -1
  29. sempy_labs/_semantic_models.py +20 -0
  30. sempy_labs/_sql.py +6 -2
  31. sempy_labs/_sqldatabase.py +61 -100
  32. sempy_labs/_vertipaq.py +8 -11
  33. sempy_labs/_warehouses.py +14 -3
  34. sempy_labs/_workspace_identity.py +6 -0
  35. sempy_labs/_workspaces.py +42 -2
  36. sempy_labs/admin/_basic_functions.py +29 -2
  37. sempy_labs/admin/_reports.py +1 -1
  38. sempy_labs/admin/_scanner.py +2 -4
  39. sempy_labs/admin/_tenant.py +8 -3
  40. sempy_labs/directlake/_directlake_schema_compare.py +2 -1
  41. sempy_labs/directlake/_directlake_schema_sync.py +65 -19
  42. sempy_labs/directlake/_dl_helper.py +0 -6
  43. sempy_labs/directlake/_generate_shared_expression.py +19 -12
  44. sempy_labs/directlake/_guardrails.py +2 -1
  45. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +90 -57
  46. sempy_labs/directlake/_update_directlake_partition_entity.py +5 -2
  47. sempy_labs/graph/_groups.py +6 -0
  48. sempy_labs/graph/_teams.py +2 -0
  49. sempy_labs/graph/_users.py +4 -0
  50. sempy_labs/lakehouse/__init__.py +12 -3
  51. sempy_labs/lakehouse/_blobs.py +231 -0
  52. sempy_labs/lakehouse/_shortcuts.py +29 -8
  53. sempy_labs/migration/_direct_lake_to_import.py +47 -10
  54. sempy_labs/migration/_migration_validation.py +0 -4
  55. sempy_labs/report/__init__.py +4 -0
  56. sempy_labs/report/_download_report.py +4 -6
  57. sempy_labs/report/_generate_report.py +6 -6
  58. sempy_labs/report/_report_functions.py +5 -4
  59. sempy_labs/report/_report_helper.py +17 -5
  60. sempy_labs/report/_report_rebind.py +8 -6
  61. sempy_labs/report/_reportwrapper.py +17 -8
  62. sempy_labs/report/_save_report.py +147 -0
  63. sempy_labs/tom/_model.py +154 -23
  64. {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info/licenses}/LICENSE +0 -0
  65. {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/top_level.txt +0 -0
@@ -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 fabric.resolve_item_name(
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
- return item
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
- return fabric.resolve_item_id(item_name=item, type=type, workspace=workspace)
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
- (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
322
-
323
- if _is_valid_uuid(item):
324
- item_id = item
325
- item_name = fabric.resolve_item_name(
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
- else:
329
- if type is None:
330
- raise ValueError(
331
- f"{icons.warning} Must specify a 'type' if specifying a name as the 'item'."
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
- item_name = item
334
- item_id = fabric.resolve_item_id(
335
- item_name=item, type=type, workspace=workspace_id
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, item_id
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 = fabric.get_lakehouse_id()
350
- lakehouse_name = fabric.resolve_item_name(
351
- item_id=lakehouse_id, type=type, workspace=workspace_id
352
- )
353
- elif _is_valid_uuid(lakehouse):
354
- lakehouse_id = lakehouse
355
- lakehouse_name = fabric.resolve_item_name(
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 = lakehouse
360
- lakehouse_id = fabric.resolve_item_id(
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 fabric.resolve_item_name(
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 = fabric.get_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 fabric.resolve_item_name(
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 = fabric.get_lakehouse_id()
481
- elif _is_valid_uuid(lakehouse):
482
- lakehouse_id = lakehouse
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 = fabric.resolve_item_id(
485
- item_name=lakehouse, type="Lakehouse", workspace=workspace
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 = fabric.get_workspace_id()
775
- workspace_name = fabric.resolve_workspace_name(workspace_id)
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 = fabric.resolve_workspace_name(workspace_id)
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
- workspace_name = workspace
781
- workspace_id = fabric.resolve_workspace_id(workspace_name)
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 str(workspace_name), str(workspace_id)
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 = fabric.resolve_workspace_name(dataset_workspace_id)
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 = fabric.list_capacities()
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 = fabric.list_capacities()
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 = fabric.list_capacities()
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 = fabric.list_capacities()
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(scopes)
1190
- access_token = AccessToken(token, 0)
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
- service_client = DataLakeServiceClient(
1202
- account_url, credential=FabricTokenCredential()
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
- return service_client
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(lakehouse, workspace) -> str:
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