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.

Files changed (113) hide show
  1. semantic_link_labs-0.7.0.dist-info/METADATA +148 -0
  2. semantic_link_labs-0.7.0.dist-info/RECORD +111 -0
  3. {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +45 -15
  5. sempy_labs/_ai.py +42 -85
  6. sempy_labs/_bpa_translation/_translations_am-ET.po +828 -0
  7. sempy_labs/_bpa_translation/_translations_ar-AE.po +860 -0
  8. sempy_labs/_bpa_translation/_translations_cs-CZ.po +894 -0
  9. sempy_labs/_bpa_translation/_translations_da-DK.po +894 -0
  10. sempy_labs/_bpa_translation/_translations_de-DE.po +933 -0
  11. sempy_labs/_bpa_translation/_translations_el-GR.po +936 -0
  12. sempy_labs/_bpa_translation/_translations_es-ES.po +915 -0
  13. sempy_labs/_bpa_translation/_translations_fa-IR.po +883 -0
  14. sempy_labs/_bpa_translation/_translations_fr-FR.po +938 -0
  15. sempy_labs/_bpa_translation/_translations_ga-IE.po +912 -0
  16. sempy_labs/_bpa_translation/_translations_he-IL.po +855 -0
  17. sempy_labs/_bpa_translation/_translations_hi-IN.po +892 -0
  18. sempy_labs/_bpa_translation/_translations_hu-HU.po +910 -0
  19. sempy_labs/_bpa_translation/_translations_is-IS.po +887 -0
  20. sempy_labs/_bpa_translation/_translations_it-IT.po +931 -0
  21. sempy_labs/_bpa_translation/_translations_ja-JP.po +805 -0
  22. sempy_labs/_bpa_translation/_translations_nl-NL.po +924 -0
  23. sempy_labs/_bpa_translation/_translations_pl-PL.po +913 -0
  24. sempy_labs/_bpa_translation/_translations_pt-BR.po +909 -0
  25. sempy_labs/_bpa_translation/_translations_pt-PT.po +904 -0
  26. sempy_labs/_bpa_translation/_translations_ru-RU.po +909 -0
  27. sempy_labs/_bpa_translation/_translations_ta-IN.po +922 -0
  28. sempy_labs/_bpa_translation/_translations_te-IN.po +896 -0
  29. sempy_labs/_bpa_translation/_translations_th-TH.po +873 -0
  30. sempy_labs/_bpa_translation/_translations_zh-CN.po +767 -0
  31. sempy_labs/_bpa_translation/_translations_zu-ZA.po +916 -0
  32. sempy_labs/_clear_cache.py +12 -8
  33. sempy_labs/_connections.py +77 -70
  34. sempy_labs/_dax.py +7 -9
  35. sempy_labs/_generate_semantic_model.py +75 -90
  36. sempy_labs/_helper_functions.py +371 -20
  37. sempy_labs/_icons.py +23 -0
  38. sempy_labs/_list_functions.py +855 -427
  39. sempy_labs/_model_auto_build.py +4 -3
  40. sempy_labs/_model_bpa.py +307 -1118
  41. sempy_labs/_model_bpa_bulk.py +363 -0
  42. sempy_labs/_model_bpa_rules.py +831 -0
  43. sempy_labs/_model_dependencies.py +20 -16
  44. sempy_labs/_one_lake_integration.py +18 -12
  45. sempy_labs/_query_scale_out.py +116 -129
  46. sempy_labs/_refresh_semantic_model.py +23 -10
  47. sempy_labs/_translations.py +367 -288
  48. sempy_labs/_vertipaq.py +152 -123
  49. sempy_labs/directlake/__init__.py +7 -1
  50. sempy_labs/directlake/_directlake_schema_compare.py +33 -30
  51. sempy_labs/directlake/_directlake_schema_sync.py +60 -77
  52. sempy_labs/directlake/_dl_helper.py +233 -0
  53. sempy_labs/directlake/_get_directlake_lakehouse.py +7 -8
  54. sempy_labs/directlake/_get_shared_expression.py +5 -3
  55. sempy_labs/directlake/_guardrails.py +20 -16
  56. sempy_labs/directlake/_list_directlake_model_calc_tables.py +17 -10
  57. sempy_labs/directlake/_show_unsupported_directlake_objects.py +3 -2
  58. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +10 -5
  59. sempy_labs/directlake/_update_directlake_partition_entity.py +169 -22
  60. sempy_labs/directlake/_warm_cache.py +7 -4
  61. sempy_labs/lakehouse/_get_lakehouse_columns.py +1 -1
  62. sempy_labs/lakehouse/_get_lakehouse_tables.py +65 -71
  63. sempy_labs/lakehouse/_lakehouse.py +5 -3
  64. sempy_labs/lakehouse/_shortcuts.py +20 -13
  65. sempy_labs/migration/__init__.py +1 -1
  66. sempy_labs/migration/_create_pqt_file.py +184 -186
  67. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +240 -269
  68. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +78 -77
  69. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +444 -425
  70. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +96 -102
  71. sempy_labs/migration/_migration_validation.py +2 -2
  72. sempy_labs/migration/_refresh_calc_tables.py +94 -100
  73. sempy_labs/report/_BPAReportTemplate.json +232 -0
  74. sempy_labs/report/__init__.py +6 -2
  75. sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
  76. sempy_labs/report/_bpareporttemplate/.platform +11 -0
  77. sempy_labs/report/_bpareporttemplate/StaticResources/SharedResources/BaseThemes/CY24SU06.json +710 -0
  78. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/page.json +11 -0
  79. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/1b08bce3bebabb0a27a8/visual.json +191 -0
  80. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/2f22ddb70c301693c165/visual.json +438 -0
  81. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/3b1182230aa6c600b43a/visual.json +127 -0
  82. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/58577ba6380c69891500/visual.json +576 -0
  83. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/a2a8fa5028b3b776c96c/visual.json +207 -0
  84. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/adfd47ef30652707b987/visual.json +506 -0
  85. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/b6a80ee459e716e170b1/visual.json +127 -0
  86. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/ce3130a721c020cc3d81/visual.json +513 -0
  87. sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/page.json +8 -0
  88. sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/visuals/66e60dfb526437cd78d1/visual.json +112 -0
  89. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/page.json +11 -0
  90. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/07deb8bce824e1be37d7/visual.json +513 -0
  91. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0b1c68838818b32ad03b/visual.json +352 -0
  92. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0c171de9d2683d10b930/visual.json +37 -0
  93. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0efa01be0510e40a645e/visual.json +542 -0
  94. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/6bf2f0eb830ab53cc668/visual.json +221 -0
  95. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/88d8141cb8500b60030c/visual.json +127 -0
  96. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/a753273590beed656a03/visual.json +576 -0
  97. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/b8fdc82cddd61ac447bc/visual.json +127 -0
  98. sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/page.json +9 -0
  99. sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/visuals/ce8532a7e25020271077/visual.json +38 -0
  100. sempy_labs/report/_bpareporttemplate/definition/pages/pages.json +10 -0
  101. sempy_labs/report/_bpareporttemplate/definition/report.json +176 -0
  102. sempy_labs/report/_bpareporttemplate/definition/version.json +4 -0
  103. sempy_labs/report/_bpareporttemplate/definition.pbir +14 -0
  104. sempy_labs/report/_generate_report.py +260 -139
  105. sempy_labs/report/_report_functions.py +90 -59
  106. sempy_labs/report/_report_rebind.py +40 -34
  107. sempy_labs/tom/__init__.py +1 -4
  108. sempy_labs/tom/_model.py +601 -181
  109. semantic_link_labs-0.5.0.dist-info/METADATA +0 -22
  110. semantic_link_labs-0.5.0.dist-info/RECORD +0 -53
  111. sempy_labs/directlake/_fallback.py +0 -58
  112. {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/LICENSE +0 -0
  113. {semantic_link_labs-0.5.0.dist-info → semantic_link_labs-0.7.0.dist-info}/top_level.txt +0 -0
@@ -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(lakehouse_id: Optional[UUID] = None, workspace: Optional[str] = None):
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
- raise ValueError(
295
- f"The '{dataset}' semantic model in the '{workspace}' workspace is not in Direct Lake mode."
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
- dfE = fabric.list_expressions(dataset=dataset, workspace=workspace)
299
- dfE_filt = dfE[dfE["Name"] == "DatabaseQuery"]
300
- expr = dfE_filt["Expression"].iloc[0]
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
- matches = re.findall(r'"([^"]*)"', expr)
303
- sqlEndpointId = matches[1]
317
+ if sqlEndpointId is None:
318
+ raise ValueError("SQL Endpoint not found.")
304
319
 
305
- return sqlEndpointId
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(f"{icons.red_dot} Invalid 'write_type' parameter. Choose from one of the following values: {writeModes}.")
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(f"{icons.red_dot} Invalid 'delta_table_name'. Delta tables in the lakehouse cannot have spaces in their names.")
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
- spark_df.write.mode(write_mode).format("delta").save(filePath)
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(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}.")
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 = ['"', "/", '"', ":", "|", "<", ">", "*", "?", "'", "!"]