semantic-link-labs 0.12.8__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.
Files changed (243) hide show
  1. semantic_link_labs-0.12.8.dist-info/METADATA +354 -0
  2. semantic_link_labs-0.12.8.dist-info/RECORD +243 -0
  3. semantic_link_labs-0.12.8.dist-info/WHEEL +5 -0
  4. semantic_link_labs-0.12.8.dist-info/licenses/LICENSE +21 -0
  5. semantic_link_labs-0.12.8.dist-info/top_level.txt +1 -0
  6. sempy_labs/__init__.py +606 -0
  7. sempy_labs/_a_lib_info.py +2 -0
  8. sempy_labs/_ai.py +437 -0
  9. sempy_labs/_authentication.py +264 -0
  10. sempy_labs/_bpa_translation/_model/_translations_am-ET.po +869 -0
  11. sempy_labs/_bpa_translation/_model/_translations_ar-AE.po +908 -0
  12. sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +968 -0
  13. sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +963 -0
  14. sempy_labs/_bpa_translation/_model/_translations_cs-CZ.po +943 -0
  15. sempy_labs/_bpa_translation/_model/_translations_da-DK.po +945 -0
  16. sempy_labs/_bpa_translation/_model/_translations_de-DE.po +988 -0
  17. sempy_labs/_bpa_translation/_model/_translations_el-GR.po +993 -0
  18. sempy_labs/_bpa_translation/_model/_translations_es-ES.po +971 -0
  19. sempy_labs/_bpa_translation/_model/_translations_fa-IR.po +933 -0
  20. sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +942 -0
  21. sempy_labs/_bpa_translation/_model/_translations_fr-FR.po +994 -0
  22. sempy_labs/_bpa_translation/_model/_translations_ga-IE.po +967 -0
  23. sempy_labs/_bpa_translation/_model/_translations_he-IL.po +902 -0
  24. sempy_labs/_bpa_translation/_model/_translations_hi-IN.po +944 -0
  25. sempy_labs/_bpa_translation/_model/_translations_hu-HU.po +963 -0
  26. sempy_labs/_bpa_translation/_model/_translations_id-ID.po +946 -0
  27. sempy_labs/_bpa_translation/_model/_translations_is-IS.po +939 -0
  28. sempy_labs/_bpa_translation/_model/_translations_it-IT.po +986 -0
  29. sempy_labs/_bpa_translation/_model/_translations_ja-JP.po +846 -0
  30. sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +839 -0
  31. sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +967 -0
  32. sempy_labs/_bpa_translation/_model/_translations_nl-NL.po +978 -0
  33. sempy_labs/_bpa_translation/_model/_translations_pl-PL.po +962 -0
  34. sempy_labs/_bpa_translation/_model/_translations_pt-BR.po +962 -0
  35. sempy_labs/_bpa_translation/_model/_translations_pt-PT.po +957 -0
  36. sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +968 -0
  37. sempy_labs/_bpa_translation/_model/_translations_ru-RU.po +964 -0
  38. sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +952 -0
  39. sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +950 -0
  40. sempy_labs/_bpa_translation/_model/_translations_sv-SE.po +942 -0
  41. sempy_labs/_bpa_translation/_model/_translations_ta-IN.po +976 -0
  42. sempy_labs/_bpa_translation/_model/_translations_te-IN.po +947 -0
  43. sempy_labs/_bpa_translation/_model/_translations_th-TH.po +924 -0
  44. sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +953 -0
  45. sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +961 -0
  46. sempy_labs/_bpa_translation/_model/_translations_zh-CN.po +804 -0
  47. sempy_labs/_bpa_translation/_model/_translations_zu-ZA.po +969 -0
  48. sempy_labs/_capacities.py +1198 -0
  49. sempy_labs/_capacity_migration.py +660 -0
  50. sempy_labs/_clear_cache.py +351 -0
  51. sempy_labs/_connections.py +610 -0
  52. sempy_labs/_dashboards.py +69 -0
  53. sempy_labs/_data_access_security.py +98 -0
  54. sempy_labs/_data_pipelines.py +162 -0
  55. sempy_labs/_dataflows.py +668 -0
  56. sempy_labs/_dax.py +501 -0
  57. sempy_labs/_daxformatter.py +80 -0
  58. sempy_labs/_delta_analyzer.py +467 -0
  59. sempy_labs/_delta_analyzer_history.py +301 -0
  60. sempy_labs/_dictionary_diffs.py +221 -0
  61. sempy_labs/_documentation.py +147 -0
  62. sempy_labs/_domains.py +51 -0
  63. sempy_labs/_eventhouses.py +182 -0
  64. sempy_labs/_external_data_shares.py +230 -0
  65. sempy_labs/_gateways.py +521 -0
  66. sempy_labs/_generate_semantic_model.py +521 -0
  67. sempy_labs/_get_connection_string.py +84 -0
  68. sempy_labs/_git.py +543 -0
  69. sempy_labs/_graphQL.py +90 -0
  70. sempy_labs/_helper_functions.py +2833 -0
  71. sempy_labs/_icons.py +149 -0
  72. sempy_labs/_job_scheduler.py +609 -0
  73. sempy_labs/_kql_databases.py +149 -0
  74. sempy_labs/_kql_querysets.py +124 -0
  75. sempy_labs/_kusto.py +137 -0
  76. sempy_labs/_labels.py +124 -0
  77. sempy_labs/_list_functions.py +1720 -0
  78. sempy_labs/_managed_private_endpoints.py +253 -0
  79. sempy_labs/_mirrored_databases.py +416 -0
  80. sempy_labs/_mirrored_warehouses.py +60 -0
  81. sempy_labs/_ml_experiments.py +113 -0
  82. sempy_labs/_model_auto_build.py +140 -0
  83. sempy_labs/_model_bpa.py +557 -0
  84. sempy_labs/_model_bpa_bulk.py +378 -0
  85. sempy_labs/_model_bpa_rules.py +859 -0
  86. sempy_labs/_model_dependencies.py +343 -0
  87. sempy_labs/_mounted_data_factories.py +123 -0
  88. sempy_labs/_notebooks.py +441 -0
  89. sempy_labs/_one_lake_integration.py +151 -0
  90. sempy_labs/_onelake.py +131 -0
  91. sempy_labs/_query_scale_out.py +433 -0
  92. sempy_labs/_refresh_semantic_model.py +435 -0
  93. sempy_labs/_semantic_models.py +468 -0
  94. sempy_labs/_spark.py +455 -0
  95. sempy_labs/_sql.py +241 -0
  96. sempy_labs/_sql_audit_settings.py +207 -0
  97. sempy_labs/_sql_endpoints.py +214 -0
  98. sempy_labs/_tags.py +201 -0
  99. sempy_labs/_translations.py +43 -0
  100. sempy_labs/_user_delegation_key.py +44 -0
  101. sempy_labs/_utils.py +79 -0
  102. sempy_labs/_vertipaq.py +1021 -0
  103. sempy_labs/_vpax.py +388 -0
  104. sempy_labs/_warehouses.py +234 -0
  105. sempy_labs/_workloads.py +140 -0
  106. sempy_labs/_workspace_identity.py +72 -0
  107. sempy_labs/_workspaces.py +595 -0
  108. sempy_labs/admin/__init__.py +170 -0
  109. sempy_labs/admin/_activities.py +167 -0
  110. sempy_labs/admin/_apps.py +145 -0
  111. sempy_labs/admin/_artifacts.py +65 -0
  112. sempy_labs/admin/_basic_functions.py +463 -0
  113. sempy_labs/admin/_capacities.py +508 -0
  114. sempy_labs/admin/_dataflows.py +45 -0
  115. sempy_labs/admin/_datasets.py +186 -0
  116. sempy_labs/admin/_domains.py +522 -0
  117. sempy_labs/admin/_external_data_share.py +100 -0
  118. sempy_labs/admin/_git.py +72 -0
  119. sempy_labs/admin/_items.py +265 -0
  120. sempy_labs/admin/_labels.py +211 -0
  121. sempy_labs/admin/_reports.py +241 -0
  122. sempy_labs/admin/_scanner.py +118 -0
  123. sempy_labs/admin/_shared.py +82 -0
  124. sempy_labs/admin/_sharing_links.py +110 -0
  125. sempy_labs/admin/_tags.py +131 -0
  126. sempy_labs/admin/_tenant.py +503 -0
  127. sempy_labs/admin/_tenant_keys.py +89 -0
  128. sempy_labs/admin/_users.py +140 -0
  129. sempy_labs/admin/_workspaces.py +236 -0
  130. sempy_labs/deployment_pipeline/__init__.py +23 -0
  131. sempy_labs/deployment_pipeline/_items.py +580 -0
  132. sempy_labs/directlake/__init__.py +57 -0
  133. sempy_labs/directlake/_autosync.py +58 -0
  134. sempy_labs/directlake/_directlake_schema_compare.py +120 -0
  135. sempy_labs/directlake/_directlake_schema_sync.py +161 -0
  136. sempy_labs/directlake/_dl_helper.py +274 -0
  137. sempy_labs/directlake/_generate_shared_expression.py +94 -0
  138. sempy_labs/directlake/_get_directlake_lakehouse.py +62 -0
  139. sempy_labs/directlake/_get_shared_expression.py +34 -0
  140. sempy_labs/directlake/_guardrails.py +96 -0
  141. sempy_labs/directlake/_list_directlake_model_calc_tables.py +70 -0
  142. sempy_labs/directlake/_show_unsupported_directlake_objects.py +90 -0
  143. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +239 -0
  144. sempy_labs/directlake/_update_directlake_partition_entity.py +259 -0
  145. sempy_labs/directlake/_warm_cache.py +236 -0
  146. sempy_labs/dotnet_lib/dotnet.runtime.config.json +10 -0
  147. sempy_labs/environment/__init__.py +23 -0
  148. sempy_labs/environment/_items.py +212 -0
  149. sempy_labs/environment/_pubstage.py +223 -0
  150. sempy_labs/eventstream/__init__.py +37 -0
  151. sempy_labs/eventstream/_items.py +263 -0
  152. sempy_labs/eventstream/_topology.py +652 -0
  153. sempy_labs/graph/__init__.py +59 -0
  154. sempy_labs/graph/_groups.py +651 -0
  155. sempy_labs/graph/_sensitivity_labels.py +120 -0
  156. sempy_labs/graph/_teams.py +125 -0
  157. sempy_labs/graph/_user_licenses.py +96 -0
  158. sempy_labs/graph/_users.py +516 -0
  159. sempy_labs/graph_model/__init__.py +15 -0
  160. sempy_labs/graph_model/_background_jobs.py +63 -0
  161. sempy_labs/graph_model/_items.py +149 -0
  162. sempy_labs/lakehouse/__init__.py +67 -0
  163. sempy_labs/lakehouse/_blobs.py +247 -0
  164. sempy_labs/lakehouse/_get_lakehouse_columns.py +102 -0
  165. sempy_labs/lakehouse/_get_lakehouse_tables.py +274 -0
  166. sempy_labs/lakehouse/_helper.py +250 -0
  167. sempy_labs/lakehouse/_lakehouse.py +351 -0
  168. sempy_labs/lakehouse/_livy_sessions.py +143 -0
  169. sempy_labs/lakehouse/_materialized_lake_views.py +157 -0
  170. sempy_labs/lakehouse/_partitioning.py +165 -0
  171. sempy_labs/lakehouse/_schemas.py +217 -0
  172. sempy_labs/lakehouse/_shortcuts.py +440 -0
  173. sempy_labs/migration/__init__.py +35 -0
  174. sempy_labs/migration/_create_pqt_file.py +238 -0
  175. sempy_labs/migration/_direct_lake_to_import.py +105 -0
  176. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +398 -0
  177. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +148 -0
  178. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +533 -0
  179. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +172 -0
  180. sempy_labs/migration/_migration_validation.py +71 -0
  181. sempy_labs/migration/_refresh_calc_tables.py +131 -0
  182. sempy_labs/mirrored_azure_databricks_catalog/__init__.py +15 -0
  183. sempy_labs/mirrored_azure_databricks_catalog/_discover.py +213 -0
  184. sempy_labs/mirrored_azure_databricks_catalog/_refresh_catalog_metadata.py +45 -0
  185. sempy_labs/ml_model/__init__.py +23 -0
  186. sempy_labs/ml_model/_functions.py +427 -0
  187. sempy_labs/report/_BPAReportTemplate.json +232 -0
  188. sempy_labs/report/__init__.py +55 -0
  189. sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
  190. sempy_labs/report/_bpareporttemplate/.platform +11 -0
  191. sempy_labs/report/_bpareporttemplate/StaticResources/SharedResources/BaseThemes/CY24SU06.json +710 -0
  192. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/page.json +11 -0
  193. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/1b08bce3bebabb0a27a8/visual.json +191 -0
  194. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/2f22ddb70c301693c165/visual.json +438 -0
  195. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/3b1182230aa6c600b43a/visual.json +127 -0
  196. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/58577ba6380c69891500/visual.json +576 -0
  197. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/a2a8fa5028b3b776c96c/visual.json +207 -0
  198. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/adfd47ef30652707b987/visual.json +506 -0
  199. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/b6a80ee459e716e170b1/visual.json +127 -0
  200. sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/ce3130a721c020cc3d81/visual.json +513 -0
  201. sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/page.json +8 -0
  202. sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/visuals/66e60dfb526437cd78d1/visual.json +112 -0
  203. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/page.json +11 -0
  204. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/07deb8bce824e1be37d7/visual.json +513 -0
  205. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0b1c68838818b32ad03b/visual.json +352 -0
  206. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0c171de9d2683d10b930/visual.json +37 -0
  207. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0efa01be0510e40a645e/visual.json +542 -0
  208. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/6bf2f0eb830ab53cc668/visual.json +221 -0
  209. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/88d8141cb8500b60030c/visual.json +127 -0
  210. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/a753273590beed656a03/visual.json +576 -0
  211. sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/b8fdc82cddd61ac447bc/visual.json +127 -0
  212. sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/page.json +9 -0
  213. sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/visuals/ce8532a7e25020271077/visual.json +38 -0
  214. sempy_labs/report/_bpareporttemplate/definition/pages/pages.json +10 -0
  215. sempy_labs/report/_bpareporttemplate/definition/report.json +176 -0
  216. sempy_labs/report/_bpareporttemplate/definition/version.json +4 -0
  217. sempy_labs/report/_bpareporttemplate/definition.pbir +14 -0
  218. sempy_labs/report/_download_report.py +76 -0
  219. sempy_labs/report/_export_report.py +257 -0
  220. sempy_labs/report/_generate_report.py +427 -0
  221. sempy_labs/report/_paginated.py +76 -0
  222. sempy_labs/report/_report_bpa.py +354 -0
  223. sempy_labs/report/_report_bpa_rules.py +115 -0
  224. sempy_labs/report/_report_functions.py +581 -0
  225. sempy_labs/report/_report_helper.py +227 -0
  226. sempy_labs/report/_report_list_functions.py +110 -0
  227. sempy_labs/report/_report_rebind.py +149 -0
  228. sempy_labs/report/_reportwrapper.py +3100 -0
  229. sempy_labs/report/_save_report.py +147 -0
  230. sempy_labs/snowflake_database/__init__.py +10 -0
  231. sempy_labs/snowflake_database/_items.py +105 -0
  232. sempy_labs/sql_database/__init__.py +21 -0
  233. sempy_labs/sql_database/_items.py +201 -0
  234. sempy_labs/sql_database/_mirroring.py +79 -0
  235. sempy_labs/theme/__init__.py +12 -0
  236. sempy_labs/theme/_org_themes.py +129 -0
  237. sempy_labs/tom/__init__.py +3 -0
  238. sempy_labs/tom/_model.py +5977 -0
  239. sempy_labs/variable_library/__init__.py +19 -0
  240. sempy_labs/variable_library/_functions.py +403 -0
  241. sempy_labs/warehouse/__init__.py +28 -0
  242. sempy_labs/warehouse/_items.py +234 -0
  243. sempy_labs/warehouse/_restore_points.py +309 -0
@@ -0,0 +1,581 @@
1
+ import sempy.fabric as fabric
2
+ import pandas as pd
3
+ import json
4
+ import os
5
+ import copy
6
+ from anytree import Node, RenderTree
7
+ from powerbiclient import Report
8
+ from pyspark.sql.functions import col, flatten
9
+ from sempy_labs.report._generate_report import update_report_from_reportjson
10
+ from sempy_labs.lakehouse._lakehouse import lakehouse_attached
11
+ from sempy_labs._helper_functions import (
12
+ resolve_report_id,
13
+ language_validate,
14
+ resolve_workspace_name_and_id,
15
+ _decode_b64,
16
+ resolve_dataset_id,
17
+ _update_dataframe_datatypes,
18
+ _base_api,
19
+ _create_spark_session,
20
+ _mount,
21
+ resolve_workspace_id,
22
+ resolve_item_name_and_id,
23
+ )
24
+ from typing import List, Optional, Union
25
+ from sempy._utils._log import log
26
+ import sempy_labs._icons as icons
27
+ from uuid import UUID
28
+
29
+
30
+ @log
31
+ def get_report_json(
32
+ report: str,
33
+ workspace: Optional[str | UUID] = None,
34
+ save_to_file_name: Optional[str] = None,
35
+ ) -> dict:
36
+ """
37
+ Gets the report.json file content of a Power BI report. This function only supports reports in the PBIR-Legacy format.
38
+
39
+ This is a wrapper function for the following API: `Items - Get Report Definition <https://learn.microsoft.com/rest/api/fabric/report/items/get-report-definition>`_.
40
+
41
+ Parameters
42
+ ----------
43
+ report : str | uuid.UUID
44
+ Name or ID of the Power BI report.
45
+ workspace : str | uuid.UUID, default=None
46
+ The Fabric workspace name or ID in which the report exists.
47
+ Defaults to None which resolves to the workspace of the attached lakehouse
48
+ or if no lakehouse attached, resolves to the workspace of the notebook.
49
+ save_to_file_name : str, default=None
50
+ Specifying this parameter will save the report.json file to the lakehouse attached to the notebook with the file name of this parameter.
51
+
52
+ Returns
53
+ -------
54
+ dict
55
+ The report.json file for a given Power BI report.
56
+ """
57
+
58
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
59
+ (report_name, report_id) = resolve_item_name_and_id(
60
+ item=report, type="Report", workspace=workspace_id
61
+ )
62
+
63
+ result = _base_api(
64
+ request=f"/v1/workspaces/{workspace_id}/reports/{report_id}/getDefinition",
65
+ method="post",
66
+ lro_return_json=True,
67
+ status_codes=None,
68
+ )
69
+ report_json = None
70
+ for part in result.get("definition", {}).get("parts", {}):
71
+ if part.get("path") == "report.json":
72
+ payload = part.get("payload")
73
+ report_file = _decode_b64(payload)
74
+ report_json = json.loads(report_file)
75
+
76
+ if not report_json:
77
+ raise ValueError(
78
+ f"{icons.red_dot} Unable to retrieve report.json for the '{report_name}' report within the '{workspace_name}' workspace. This function only supports reports in the PBIR-Legacy format."
79
+ )
80
+
81
+ if save_to_file_name is not None:
82
+ if not lakehouse_attached():
83
+ raise ValueError(
84
+ f"{icons.red_dot} In order to save the report.json file, a lakehouse must be attached to the notebook. Please attach a lakehouse to this notebook."
85
+ )
86
+
87
+ local_path = _mount()
88
+ save_folder = f"{local_path}/Files"
89
+ file_ext = ".json"
90
+ if not save_to_file_name.endswith(file_ext):
91
+ save_to_file_name = f"{save_to_file_name}{file_ext}"
92
+ file_path = os.path.join(save_folder, save_to_file_name)
93
+ with open(file_path, "w") as json_file:
94
+ json.dump(report_json, json_file, indent=4)
95
+ print(
96
+ f"{icons.green_dot} The report.json file for the '{report}' report has been saved to the lakehouse attached to this notebook in this location: Files/'{save_to_file_name}'.\n\n"
97
+ )
98
+
99
+ return report_json
100
+
101
+
102
+ @log
103
+ def report_dependency_tree(workspace: Optional[str | UUID] = None):
104
+ """
105
+ Prints a dependency between reports and semantic models.
106
+
107
+ Parameters
108
+ ----------
109
+ workspace : str | uuid.UUID, default=None
110
+ The Fabric workspace name or ID.
111
+ Defaults to None which resolves to the workspace of the attached lakehouse
112
+ or if no lakehouse attached, resolves to the workspace of the notebook.
113
+ """
114
+
115
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
116
+
117
+ dfR = fabric.list_reports(workspace=workspace_id)
118
+ dfD = fabric.list_datasets(workspace=workspace_id)
119
+ dfR = pd.merge(
120
+ dfR,
121
+ dfD[["Dataset ID", "Dataset Name"]],
122
+ left_on="Dataset Id",
123
+ right_on="Dataset ID",
124
+ how="left",
125
+ )
126
+ dfR.rename(columns={"Name": "Report Name"}, inplace=True)
127
+ dfR = dfR[["Report Name", "Dataset Name"]]
128
+
129
+ report_icon = "\U0001f4f6"
130
+ dataset_icon = "\U0001f9ca"
131
+ workspace_icon = "\U0001f465"
132
+
133
+ node_dict = {}
134
+ rootNode = Node(workspace_name)
135
+ node_dict[workspace_name] = rootNode
136
+ rootNode.custom_property = f"{workspace_icon} "
137
+
138
+ for _, r in dfR.iterrows():
139
+ datasetName = r["Dataset Name"]
140
+ reportName = r["Report Name"]
141
+ parentNode = node_dict.get(datasetName)
142
+ if parentNode is None:
143
+ parentNode = Node(datasetName, parent=rootNode)
144
+ node_dict[datasetName] = parentNode
145
+ parentNode.custom_property = f"{dataset_icon} "
146
+
147
+ child_node = Node(reportName, parent=parentNode)
148
+ child_node.custom_property = f"{report_icon} "
149
+
150
+ # Print the tree structure
151
+ for pre, _, node in RenderTree(node_dict[workspace_name]):
152
+ print(f"{pre}{node.custom_property}'{node.name}'")
153
+
154
+
155
+ @log
156
+ def clone_report(
157
+ report: str,
158
+ cloned_report: str,
159
+ workspace: Optional[str | UUID] = None,
160
+ target_workspace: Optional[str] = None,
161
+ target_dataset: Optional[str] = None,
162
+ target_dataset_workspace: Optional[str] = None,
163
+ ):
164
+ """
165
+ Clones a Power BI report.
166
+
167
+ This is a wrapper function for the following API: `Reports - Clone Report In Group <https://learn.microsoft.com/rest/api/power-bi/reports/clone-report-in-group>`_.
168
+
169
+ Parameters
170
+ ----------
171
+ report : str
172
+ Name of the Power BI report.
173
+ cloned_report : str
174
+ Name of the new Power BI report.
175
+ workspace : str | uuid.UUID, default=None
176
+ The Fabric workspace name or ID.
177
+ Defaults to None which resolves to the workspace of the attached lakehouse
178
+ or if no lakehouse attached, resolves to the workspace of the notebook.
179
+ target_workspace : str, default=None
180
+ The name of the Fabric workspace to place the cloned report.
181
+ Defaults to None which resolves to the workspace of the attached lakehouse
182
+ or if no lakehouse attached, resolves to the workspace of the notebook.
183
+ target_dataset : str, default=None
184
+ The name of the semantic model to be used by the cloned report.
185
+ Defaults to None which resolves to the semantic model used by the initial report.
186
+ target_dataset_workspace : str, default=None
187
+ The workspace name in which the semantic model to be used by the report resides.
188
+ Defaults to None which resolves to the semantic model used by the initial report.
189
+ """
190
+
191
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
192
+
193
+ dfI = fabric.list_items(workspace=workspace_id, type="Report")
194
+ dfI_filt = dfI[(dfI["Display Name"] == report)]
195
+
196
+ if len(dfI_filt) == 0:
197
+ raise ValueError(
198
+ f"{icons.red_dot} The '{report}' report does not exist within the '{workspace_name}' workspace."
199
+ )
200
+
201
+ reportId = resolve_report_id(report, workspace_id)
202
+
203
+ if target_workspace is None:
204
+ target_workspace = workspace_name
205
+ target_workspace_id = workspace_id
206
+ else:
207
+ target_workspace_id = resolve_workspace_id(workspace=target_workspace)
208
+
209
+ if target_dataset is not None:
210
+ if target_dataset_workspace is None:
211
+ target_dataset_workspace = workspace_name
212
+ target_dataset_id = resolve_dataset_id(target_dataset, target_dataset_workspace)
213
+
214
+ if report == cloned_report and workspace_name == target_workspace:
215
+ raise ValueError(
216
+ f"{icons.warning} The 'report' and 'cloned_report' parameters have the same value of '{report}. The 'workspace' and 'target_workspace' have the same value of '{workspace_name}'. Either the 'cloned_report' or the 'target_workspace' must be different from the original report."
217
+ )
218
+
219
+ payload = {"name": cloned_report}
220
+ if target_dataset is not None:
221
+ payload["targetModelId"] = target_dataset_id
222
+ if target_workspace != workspace_name:
223
+ payload["targetWorkspaceId"] = target_workspace_id
224
+
225
+ _base_api(
226
+ request=f"/v1.0/myorg/groups/{workspace_id}/reports/{reportId}/Clone",
227
+ method="post",
228
+ payload=payload,
229
+ )
230
+ print(
231
+ f"{icons.green_dot} The '{report}' report has been successfully cloned as the '{cloned_report}' report within the '{target_workspace}' workspace."
232
+ )
233
+
234
+
235
+ @log
236
+ def launch_report(report: str, workspace: Optional[str | UUID] = None):
237
+ """
238
+ Shows a Power BI report within a Fabric notebook.
239
+
240
+ Parameters
241
+ ----------
242
+ report : str
243
+ Name of the Power BI report.
244
+ workspace : str | uuid.UUID, default=None
245
+ The Fabric workspace name or ID.
246
+ Defaults to None which resolves to the workspace of the attached lakehouse
247
+ or if no lakehouse attached, resolves to the workspace of the notebook.
248
+
249
+ Returns
250
+ -------
251
+ str
252
+ An embedded Power BI report within the notebook.
253
+ """
254
+
255
+ from sempy_labs import resolve_report_id
256
+
257
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
258
+ report_id = resolve_report_id(report, workspace_id)
259
+ report = Report(group_id=workspace_id, report_id=report_id)
260
+
261
+ return report
262
+
263
+
264
+ @log
265
+ def list_report_pages(report: str, workspace: Optional[str | UUID] = None):
266
+ """
267
+ Shows the properties of all pages within a Power BI report.
268
+
269
+ Parameters
270
+ ----------
271
+ report : str
272
+ Name of the Power BI report.
273
+ workspace : str | uuid.UUID, default=None
274
+ The Fabric workspace name or ID.
275
+ Defaults to None which resolves to the workspace of the attached lakehouse
276
+ or if no lakehouse attached, resolves to the workspace of the notebook.
277
+
278
+ Returns
279
+ -------
280
+ pandas.DataFrame
281
+ A pandas dataframe showing the pages within a Power BI report and their properties.
282
+ """
283
+
284
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
285
+
286
+ df = pd.DataFrame(
287
+ columns=["Page ID", "Page Name", "Hidden", "Width", "Height", "Visual Count"]
288
+ )
289
+
290
+ reportJson = get_report_json(report=report, workspace=workspace_id)
291
+
292
+ for section in reportJson["sections"]:
293
+ pageID = section.get("name")
294
+ pageName = section.get("displayName")
295
+ # pageFilters = section['filters']
296
+ pageWidth = section.get("width")
297
+ pageHeight = section.get("height")
298
+ visualCount = len(section["visualContainers"])
299
+ pageHidden = False
300
+ pageConfig = section.get("config")
301
+ pageConfigJson = json.loads(pageConfig)
302
+
303
+ try:
304
+ pageH = pageConfigJson["visibility"]
305
+ if pageH == 1:
306
+ pageHidden = True
307
+ except Exception:
308
+ pass
309
+
310
+ new_data = {
311
+ "Page ID": pageID,
312
+ "Page Name": pageName,
313
+ "Hidden": pageHidden,
314
+ "Width": pageWidth,
315
+ "Height": pageHeight,
316
+ "Visual Count": visualCount,
317
+ }
318
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
319
+
320
+ column_map = {
321
+ "Hidden": "bool",
322
+ "Width": "int",
323
+ "Height": "int",
324
+ "Visual Count": "int",
325
+ }
326
+
327
+ _update_dataframe_datatypes(dataframe=df, column_map=column_map)
328
+
329
+ return df
330
+
331
+
332
+ @log
333
+ def list_report_visuals(report: str, workspace: Optional[str | UUID] = None):
334
+ """
335
+ Shows the properties of all visuals within a Power BI report.
336
+
337
+ Parameters
338
+ ----------
339
+ report : str
340
+ Name of the Power BI report.
341
+ workspace : str | uuid.UUID, default=None
342
+ The Fabric workspace name or ID.
343
+ Defaults to None which resolves to the workspace of the attached lakehouse
344
+ or if no lakehouse attached, resolves to the workspace of the notebook.
345
+
346
+ Returns
347
+ -------
348
+ pandas.DataFrame
349
+ A pandas dataframe showing the visuals within a Power BI report and their properties.
350
+ """
351
+
352
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
353
+
354
+ reportJson = get_report_json(report=report, workspace=workspace_id)
355
+
356
+ df = pd.DataFrame(columns=["Page Name", "Page ID", "Visual ID", "Title"])
357
+
358
+ for section in reportJson["sections"]:
359
+ pageID = section["name"]
360
+ pageName = section["displayName"]
361
+
362
+ for visual in section["visualContainers"]:
363
+ visualConfig = visual["config"]
364
+ visualConfigJson = json.loads(visualConfig)
365
+ visualID = visualConfigJson["name"]
366
+
367
+ try:
368
+ title = visualConfigJson["singleVisual"]["vcObjects"]["title"][0][
369
+ "properties"
370
+ ]["text"]["expr"]["Literal"]["Value"]
371
+ title = title[1:-1]
372
+ except Exception:
373
+ title = ""
374
+
375
+ new_data = {
376
+ "Page Name": pageName,
377
+ "Page ID": pageID,
378
+ "Visual ID": visualID,
379
+ "Title": title,
380
+ }
381
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
382
+
383
+ return df
384
+
385
+
386
+ @log
387
+ def list_report_bookmarks(report: str, workspace: Optional[str | UUID] = None):
388
+ """
389
+ Shows the properties of all bookmarks within a Power BI report.
390
+
391
+ Parameters
392
+ ----------
393
+ report : str
394
+ Name of the Power BI report.
395
+ workspace : str | uuid.UUID, default=None
396
+ The Fabric workspace name or ID.
397
+ Defaults to None which resolves to the workspace of the attached lakehouse
398
+ or if no lakehouse attached, resolves to the workspace of the notebook.
399
+
400
+ Returns
401
+ -------
402
+ pandas.DataFrame
403
+ A pandas dataframe showing the bookmarks within a Power BI report and their properties.
404
+ """
405
+
406
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
407
+
408
+ df = pd.DataFrame(
409
+ columns=[
410
+ "Bookmark ID",
411
+ "Bookmark Name",
412
+ "Page ID",
413
+ "Visual ID",
414
+ "Visual Hidden",
415
+ ]
416
+ )
417
+
418
+ reportJson = get_report_json(report=report, workspace=workspace_id)
419
+ reportConfig = reportJson["config"]
420
+ reportConfigJson = json.loads(reportConfig)
421
+
422
+ try:
423
+ for bookmark in reportConfigJson["bookmarks"]:
424
+ bID = bookmark["name"]
425
+ bName = bookmark["displayName"]
426
+ rptPageId = bookmark["explorationState"]["activeSection"]
427
+
428
+ for rptPg in bookmark["explorationState"]["sections"]:
429
+ for vc in bookmark["explorationState"]["sections"][rptPg][
430
+ "visualContainers"
431
+ ]:
432
+ vHidden = False
433
+ try:
434
+ hidden = bookmark["explorationState"]["sections"][rptPg][
435
+ "visualContainers"
436
+ ][vc]["singleVisual"]["display"]["mode"]
437
+ if hidden == "hidden":
438
+ vHidden = True
439
+ except Exception:
440
+ pass
441
+
442
+ new_data = {
443
+ "Bookmark ID": bID,
444
+ "Bookmark Name": bName,
445
+ "Page ID": rptPageId,
446
+ "Visual ID": vc,
447
+ "Visual Hidden": vHidden,
448
+ }
449
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
450
+
451
+ listPages = list_report_pages(report=report, workspace=workspace_id)
452
+
453
+ df = pd.merge(df, listPages[["Page ID", "Page Name"]], on="Page ID", how="left")
454
+ df = df[
455
+ [
456
+ "Bookmark ID",
457
+ "Bookmark Name",
458
+ "Page ID",
459
+ "Page Name",
460
+ "Visual ID",
461
+ "Visual Hidden",
462
+ ]
463
+ ]
464
+
465
+ return df
466
+
467
+ except Exception:
468
+ print(
469
+ f"The '{report}' report within the '{workspace_name}' workspace has no bookmarks."
470
+ )
471
+
472
+
473
+ @log
474
+ def translate_report_titles(
475
+ report: str,
476
+ languages: Union[str, List[str]],
477
+ workspace: Optional[str | UUID] = None,
478
+ ):
479
+ """
480
+ Dynamically generates new Power BI reports which have report titles translated into the specified language(s).
481
+
482
+ Parameters
483
+ ----------
484
+ report : str
485
+ Name of the Power BI report.
486
+ languages : str, List[str]
487
+ The language code(s) in which to translate the report titles.
488
+ workspace : str | uuid.UUID, default=None
489
+ The Fabric workspace name or ID.
490
+ Defaults to None which resolves to the workspace of the attached lakehouse
491
+ or if no lakehouse attached, resolves to the workspace of the notebook.
492
+ """
493
+ from synapse.ml.services import Translate
494
+
495
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
496
+
497
+ if isinstance(languages, str):
498
+ languages = [languages]
499
+
500
+ for lang in languages:
501
+ language_validate(lang)
502
+
503
+ reportJson = get_report_json(report=report, workspace=workspace_id)
504
+ dfV = list_report_visuals(report=report, workspace=workspace_id)
505
+ spark = _create_spark_session()
506
+ df = spark.createDataFrame(dfV)
507
+ columnToTranslate = "Title"
508
+
509
+ translate = (
510
+ Translate()
511
+ .setTextCol(columnToTranslate)
512
+ .setToLanguage(languages)
513
+ .setOutputCol("translation")
514
+ .setConcurrency(5)
515
+ )
516
+
517
+ transDF = (
518
+ translate.transform(df)
519
+ .withColumn("translation", flatten(col("translation.translations")))
520
+ .withColumn("translation", col("translation.text"))
521
+ .select("Visual ID", columnToTranslate, "translation")
522
+ )
523
+
524
+ df_panda = transDF.toPandas()
525
+
526
+ i = 0
527
+ for lang in languages:
528
+ # Clone report
529
+ language = language_validate(lang)
530
+ clonedReportName = f"{report}_{language}"
531
+
532
+ dfRep = fabric.list_reports(workspace=workspace_id)
533
+ dfRep_filt = dfRep[
534
+ (dfRep["Name"] == clonedReportName)
535
+ & (dfRep["Report Type"] == "PowerBIReport")
536
+ ]
537
+
538
+ if len(dfRep_filt) > 0:
539
+ print(
540
+ f"{icons.yellow_dot} The '{clonedReportName}' report already exists in the '{workspace_name} workspace."
541
+ )
542
+ else:
543
+ clone_report(
544
+ report=report, cloned_report=clonedReportName, workspace=workspace_id
545
+ )
546
+ print(
547
+ f"{icons.green_dot} The '{clonedReportName}' report has been created via clone in the '{workspace_name} workspace."
548
+ )
549
+
550
+ rptJsonTr = copy.deepcopy(reportJson)
551
+
552
+ # Update report json file
553
+ for section in rptJsonTr["sections"]:
554
+ for visual in section["visualContainers"]:
555
+ visualConfig = visual["config"]
556
+ visualConfigJson = json.loads(visualConfig)
557
+ visualID = visualConfigJson["name"]
558
+
559
+ df_filt = df_panda[
560
+ (df_panda["Visual ID"] == visualID) & (df_panda["Title"] != "")
561
+ ]
562
+
563
+ if len(df_filt) == 1:
564
+ tr = df_filt["translation"].str[i].iloc[0]
565
+ if len(tr) > 0:
566
+ prop = visualConfigJson["singleVisual"]["vcObjects"]["title"][
567
+ 0
568
+ ]["properties"]["text"]["expr"]["Literal"]
569
+ prop["Value"] = f"'{tr}'"
570
+
571
+ visual["config"] = json.dumps(visualConfigJson)
572
+
573
+ i += 1
574
+
575
+ # Post updated report json file to cloned report
576
+ update_report_from_reportjson(
577
+ report=clonedReportName, report_json=rptJsonTr, workspace=workspace_id
578
+ )
579
+ print(
580
+ f"{icons.green_dot} The visual titles within the '{clonedReportName}' report within the '{workspace_name}' have been translated into '{language}' accordingly."
581
+ )