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,227 @@
1
+ import requests
2
+ import sempy_labs._icons as icons
3
+
4
+
5
+ vis_type_mapping = {
6
+ "barChart": "Bar chart",
7
+ "columnChart": "Column chart",
8
+ "clusteredBarChart": "Clustered bar chart",
9
+ "clusteredColumnChart": "Clustered column chart",
10
+ "hundredPercentStackedBarChart": "100% Stacked bar chart",
11
+ "hundredPercentStackedColumnChart": "100% Stacked column chart",
12
+ "lineChart": "Line chart",
13
+ "areaChart": "Area chart",
14
+ "stackedAreaChart": "Stacked area chart",
15
+ "lineStackedColumnComboChart": "Line and stacked column chart",
16
+ "lineClusteredColumnComboChart": "Line and clustered column chart",
17
+ "ribbonChart": "Ribbon chart",
18
+ "waterfallChart": "Waterfall chart",
19
+ "funnel": "Funnel chart",
20
+ "scatterChart": "Scatter chart",
21
+ "pieChart": "Pie chart",
22
+ "donutChart": "Donut chart",
23
+ "treemap": "Treemap",
24
+ "map": "Map",
25
+ "filledMap": "Filled map",
26
+ "shapeMap": "Shape map",
27
+ "azureMap": "Azure map",
28
+ "gauge": "Gauge",
29
+ "card": "Card",
30
+ "multiRowCard": "Multi-row card",
31
+ "kpi": "KPI",
32
+ "slicer": "Slicer",
33
+ "tableEx": "Table",
34
+ "pivotTable": "Matrix",
35
+ "scriptVisual": "R script visual",
36
+ "pythonVisual": "Python visual",
37
+ "keyDriversVisual": "Key influencers",
38
+ "decompositionTreeVisual": "Decomposition tree",
39
+ "qnaVisual": "Q&A",
40
+ "aiNarratives": "Narrative",
41
+ "scorecard": "Goals (Preview)",
42
+ "rdlVisual": "Paginated report",
43
+ "cardVisual": "Card (new)",
44
+ "actionButton": "Button",
45
+ "bookmarkNavigator": "Bookmark navigator",
46
+ "image": "Image",
47
+ "textbox": "Textbox",
48
+ "pageNavigator": "Page navigator",
49
+ "shape": "Shape",
50
+ "Group": "Group",
51
+ "listSlicer": "List Slicer",
52
+ "advancedSlicerVisual": "Button Slicer",
53
+ "FlowVisual_C29F1DCC_81F5_4973_94AD_0517D44CC06A": "Power Automate for Power BI",
54
+ }
55
+
56
+
57
+ def generate_visual_file_path(page_file_path: str, visual_id: str) -> str:
58
+
59
+ return page_file_path.split("/page.json")[0] + f"/visuals/{visual_id}.json"
60
+
61
+
62
+ def resolve_visual_type(visual_type: str) -> str:
63
+ vt_lower = visual_type.lower()
64
+
65
+ vis_map_lower = {k.lower(): v for k, v in vis_type_mapping.items()}
66
+ flipped_lower = {v.lower(): k for k, v in vis_type_mapping.items()}
67
+
68
+ if vt_lower in vis_map_lower:
69
+ resolved = vis_map_lower.get(vt_lower)
70
+ elif vt_lower in flipped_lower:
71
+ resolved = flipped_lower.get(vt_lower)
72
+ else:
73
+ raise ValueError(f"{icons.red_dot} Unknown visual type: {visual_type}")
74
+
75
+ return resolved
76
+
77
+
78
+ page_type_mapping = {
79
+ (320, 240): "Tooltip",
80
+ (816, 1056): "Letter",
81
+ (960, 720): "4:3",
82
+ (1280, 720): "16:9",
83
+ }
84
+
85
+ page_types = ["Tooltip", "Letter", "4:3", "16:9"]
86
+
87
+
88
+ def populate_custom_visual_display_names():
89
+
90
+ url = "https://catalogapi.azure.com/offers?api-version=2018-08-01-beta&storefront=appsource&$filter=offerType+eq+%27PowerBIVisuals%27"
91
+
92
+ def fetch_all_pages(start_url):
93
+ combined_json = {}
94
+ current_url = start_url
95
+
96
+ while current_url:
97
+ # Send GET request to the current page URL
98
+ response = requests.get(current_url)
99
+
100
+ if response.status_code == 200:
101
+ data = response.json()
102
+ # Merge the current page JSON into the combined JSON
103
+ for key, value in data.items():
104
+ if key not in combined_json:
105
+ combined_json[key] = value
106
+ else:
107
+ # If the key already exists and is a list, extend it
108
+ if isinstance(value, list):
109
+ combined_json[key].extend(value)
110
+ # For other types (non-lists), update the value
111
+ else:
112
+ combined_json[key] = value
113
+
114
+ # Get the next page link if it exists
115
+ current_url = data.get("nextPageLink")
116
+ else:
117
+ print(f"Error fetching page: {response.status_code}")
118
+ break
119
+
120
+ return combined_json
121
+
122
+ cvJson = fetch_all_pages(url)
123
+
124
+ for i in cvJson.get("items", []):
125
+ vizId = i.get("powerBIVisualId")
126
+ displayName = i.get("displayName")
127
+ vis_type_mapping[vizId] = displayName
128
+
129
+
130
+ def find_entity_property_pairs(data, result=None, keys_path=None):
131
+
132
+ if result is None:
133
+ result = {}
134
+ if keys_path is None:
135
+ keys_path = []
136
+
137
+ if isinstance(data, dict):
138
+ expression = data.get("Expression", {})
139
+ source_ref = (
140
+ expression.get("SourceRef", {}) if isinstance(expression, dict) else {}
141
+ )
142
+
143
+ if (
144
+ isinstance(source_ref, dict)
145
+ and "Entity" in source_ref
146
+ and "Property" in data
147
+ ):
148
+ entity = source_ref.get("Entity", "")
149
+ property_value = data.get("Property", "")
150
+
151
+ object_type = (
152
+ keys_path[-1].replace("HierarchyLevel", "Hierarchy")
153
+ if keys_path
154
+ else "Unknown"
155
+ )
156
+ result[property_value] = (entity, object_type)
157
+ if keys_path:
158
+ keys_path.pop()
159
+
160
+ # Recursively search the rest of the dictionary
161
+ for key, value in data.items():
162
+ keys_path.append(key)
163
+ find_entity_property_pairs(value, result, keys_path)
164
+
165
+ elif isinstance(data, list):
166
+ for item in data:
167
+ find_entity_property_pairs(item, result, keys_path)
168
+
169
+ return result
170
+
171
+
172
+ def _get_agg_type_mapping() -> dict:
173
+ """
174
+ This function extracts a mapping dictionary like this:
175
+ {
176
+ "0": "Sum",
177
+ "1": "Average",
178
+ "2": "Distinct count",
179
+ }
180
+ """
181
+
182
+ schema_url = "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/semanticQuery/1.2.0/schema.json"
183
+ response = requests.get(schema_url)
184
+ schema = response.json()
185
+ aggtypes_schema = schema.get("definitions", {}).get("QueryAggregateFunction", {})
186
+
187
+ agg_type_map = {}
188
+ agg_type_map = {
189
+ a.get("const"): a.get("description")
190
+ for a in aggtypes_schema.get("anyOf", [])
191
+ if "const" in a and "description" in a
192
+ }
193
+ agg_type_map["-1"] = "Unknown"
194
+
195
+ return agg_type_map
196
+
197
+
198
+ def _get_expression(expr_json, agg_type_map):
199
+
200
+ expr_type = list(expr_json.keys())[0]
201
+ if expr_type == "Literal":
202
+ expr = expr_json.get("Literal", {}).get("Value")[1:-1]
203
+ elif expr_type == "Aggregation":
204
+ entity = (
205
+ expr_json.get("Aggregation", {})
206
+ .get("Expression", {})
207
+ .get("Column", {})
208
+ .get("Expression", {})
209
+ .get("SourceRef", {})
210
+ .get("Entity", "Unknown")
211
+ )
212
+ column = (
213
+ expr_json.get("Aggregation", {})
214
+ .get("Expression", {})
215
+ .get("Column", {})
216
+ .get("Property", "Unknown")
217
+ )
218
+ function_id = expr_json.get("Aggregation", {}).get("Function", "-1")
219
+ function = agg_type_map.get(function_id)
220
+ expr = f"{function}('{entity}'[{column}])"
221
+ elif expr_type == "Measure":
222
+ measure = expr_json.get("Measure", {}).get("Property", "Unknown")
223
+ expr = f"[{measure}]"
224
+ else:
225
+ expr = "Unknown"
226
+
227
+ return expr
@@ -0,0 +1,110 @@
1
+ import sempy.fabric as fabric
2
+ from typing import Optional
3
+ import pandas as pd
4
+ from sempy_labs._helper_functions import (
5
+ format_dax_object_name,
6
+ resolve_workspace_name_and_id,
7
+ resolve_dataset_name_and_id,
8
+ )
9
+ from sempy_labs.report._reportwrapper import ReportWrapper
10
+ from sempy_labs._list_functions import list_reports_using_semantic_model
11
+ from uuid import UUID
12
+
13
+
14
+ def list_unused_objects_in_reports(
15
+ dataset: str | UUID, workspace: Optional[str | UUID] = None
16
+ ) -> pd.DataFrame:
17
+ """
18
+ Shows a list of all columns in the semantic model which are not used in any related Power BI reports (including dependencies).
19
+ Note: As with all functions which rely on the ReportWrapper, this function requires the report to be in the 'PBIR' format.
20
+
21
+ Parameters
22
+ ----------
23
+ dataset : str | uuid.UUID
24
+ Name or ID of the semantic model.
25
+ workspace : str | uuid.UUID, default=None
26
+ The Fabric workspace name or ID.
27
+ Defaults to None which resolves to the workspace of the attached lakehouse
28
+ or if no lakehouse attached, resolves to the workspace of the notebook.
29
+
30
+ Returns
31
+ -------
32
+ pandas.DataFrame
33
+ A pandas dataframe showing a list of all columns in the semantic model which are not used in any related Power BI reports (including dependencies).
34
+ """
35
+
36
+ # TODO: what about relationships/RLS?
37
+
38
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
39
+ (dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
40
+
41
+ fabric.refresh_tom_cache(workspace=workspace)
42
+
43
+ dfR = _list_all_report_semantic_model_objects(
44
+ dataset=dataset_id, workspace=workspace_id
45
+ )
46
+ dfR_filt = (
47
+ dfR[dfR["Object Type"] == "Column"][["Table Name", "Object Name"]]
48
+ .drop_duplicates()
49
+ .reset_index(drop=True)
50
+ )
51
+ dfR_filt["Column Object"] = format_dax_object_name(
52
+ dfR_filt["Table Name"], dfR_filt["Object Name"]
53
+ )
54
+
55
+ dfC = fabric.list_columns(dataset=dataset_id, workspace=workspace_id)
56
+ dfC["Column Object"] = format_dax_object_name(dfC["Table Name"], dfC["Column Name"])
57
+
58
+ df = dfC[~(dfC["Column Object"].isin(dfR_filt["Column Object"].values))]
59
+ df = df.drop("Column Object", axis=1)
60
+
61
+ return df
62
+
63
+
64
+ def _list_all_report_semantic_model_objects(
65
+ dataset: str | UUID, workspace: Optional[str | UUID] = None
66
+ ) -> pd.DataFrame:
67
+ """
68
+ Shows a unique list of all semantic model objects (columns, measures, hierarchies) which are used in all reports which leverage the semantic model.
69
+ Note: As with all functions which rely on the ReportWrapper, this function requires the report to be in the 'PBIR' format.
70
+
71
+ Parameters
72
+ ----------
73
+ dataset : str | uuid.UUID
74
+ Name or ID of the semantic model.
75
+ workspace : str | uuid.UUID, default=None
76
+ The Fabric workspace name or ID.
77
+ Defaults to None which resolves to the workspace of the attached lakehouse
78
+ or if no lakehouse attached, resolves to the workspace of the notebook.
79
+
80
+ Returns
81
+ -------
82
+ pandas.DataFrame
83
+ A pandas dataframe.
84
+ """
85
+
86
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
87
+ (dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
88
+
89
+ dfR = list_reports_using_semantic_model(dataset=dataset_id, workspace=workspace_id)
90
+ dfs = []
91
+
92
+ for _, r in dfR.iterrows():
93
+ report_name = r["Report Name"]
94
+ report_workspace = r["Report Workspace Name"]
95
+
96
+ rpt = ReportWrapper(report=report_name, workspace=report_workspace)
97
+
98
+ new_data = rpt._list_all_semantic_model_objects()
99
+ new_data["Report Name"] = report_name
100
+ new_data["Report Workspace"] = report_workspace
101
+ dfs.append(new_data)
102
+
103
+ df = pd.concat(dfs, ignore_index=True)
104
+
105
+ colName = "Report Name"
106
+ df.insert(2, colName, df.pop(colName))
107
+ colName = "Report Workspace"
108
+ df.insert(3, colName, df.pop(colName))
109
+
110
+ return df
@@ -0,0 +1,149 @@
1
+ from sempy_labs._helper_functions import (
2
+ resolve_item_id,
3
+ resolve_workspace_id,
4
+ resolve_workspace_name_and_id,
5
+ resolve_item_name_and_id,
6
+ _base_api,
7
+ )
8
+ from typing import Optional, List
9
+ from sempy._utils._log import log
10
+ import sempy_labs._icons as icons
11
+ from uuid import UUID
12
+ import sempy.fabric as fabric
13
+
14
+
15
+ @log
16
+ def report_rebind(
17
+ report: str | UUID | List[str | UUID],
18
+ dataset: str | UUID,
19
+ report_workspace: Optional[str | UUID] = None,
20
+ dataset_workspace: Optional[str | UUID] = None,
21
+ ):
22
+ """
23
+ Rebinds a report to a semantic model.
24
+
25
+ This is a wrapper function for the following API: `Reports - Rebind Report In Group <https://learn.microsoft.com/rest/api/power-bi/reports/rebind-report-in-group>`_.
26
+
27
+ Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
28
+
29
+ Parameters
30
+ ----------
31
+ report : str | uuid.UUID | List[str | uuid.UUID]
32
+ Name(s) or ID(s) of the Power BI report(s).
33
+ dataset : str | uuid.UUID
34
+ Name or ID of the semantic model.
35
+ report_workspace : str | uuid.UUID, default=None
36
+ The name or ID of the Fabric workspace in which the report resides.
37
+ Defaults to None which resolves to the workspace of the attached lakehouse
38
+ or if no lakehouse attached, resolves to the workspace of the notebook.
39
+ dataset_workspace : str | uuid.UUID, default=None
40
+ The name or ID of the Fabric workspace in which the semantic model resides.
41
+ Defaults to None which resolves to the workspace of the attached lakehouse
42
+ or if no lakehouse attached, resolves to the workspace of the notebook.
43
+ """
44
+
45
+ (report_workspace_name, report_workspace_id) = resolve_workspace_name_and_id(
46
+ report_workspace
47
+ )
48
+
49
+ if dataset_workspace is None:
50
+ dataset_workspace = report_workspace_name
51
+
52
+ (dataset_workspace_name, dataset_workspace_id) = resolve_workspace_name_and_id(
53
+ dataset_workspace
54
+ )
55
+ if isinstance(report, str):
56
+ report = [report]
57
+
58
+ for rpt in report:
59
+ (report_name, report_id) = resolve_item_name_and_id(
60
+ item=rpt, type="Report", workspace=report_workspace_id
61
+ )
62
+ (dataset_name, dataset_id) = resolve_item_name_and_id(
63
+ item=dataset, type="SemanticModel", workspace=dataset_workspace
64
+ )
65
+
66
+ payload = {"datasetId": dataset_id}
67
+
68
+ _base_api(
69
+ request=f"v1.0/myorg/groups/{report_workspace_id}/reports/{report_id}/Rebind",
70
+ method="post",
71
+ payload=payload,
72
+ client="fabric_sp",
73
+ )
74
+
75
+ print(
76
+ f"{icons.green_dot} The '{report_name}' report within the '{report_workspace_name}' workspace has been successfully rebinded to the '{dataset_name}' semantic model within the '{dataset_workspace_name}' workspace."
77
+ )
78
+
79
+
80
+ @log
81
+ def report_rebind_all(
82
+ dataset: str | UUID,
83
+ new_dataset: str | UUID,
84
+ dataset_workspace: Optional[str | UUID] = None,
85
+ new_dataset_workspace: Optional[str | UUID] = None,
86
+ report_workspace: Optional[str | UUID | List[str | UUID]] = None,
87
+ ):
88
+ """
89
+ Rebinds all reports across the provided report workspaces which are bound to a specific semantic model to a new semantic model.
90
+
91
+ Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
92
+
93
+ Parameters
94
+ ----------
95
+ dataset : str | uuid.UUID
96
+ Name of the semantic model currently binded to the reports.
97
+ new_dataset : str | uuid.UUID
98
+ Name of the semantic model to rebind to the reports.
99
+ dataset_workspace : str | uuid.UUID, default=None
100
+ The name of the Fabric workspace in which the original semantic model resides.
101
+ Defaults to None which resolves to the workspace of the attached lakehouse
102
+ or if no lakehouse attached, resolves to the workspace of the notebook.
103
+ new_dataset_workspace : str | uuid.UUID, default=None
104
+ The name of the Fabric workspace in which the new semantic model resides.
105
+ Defaults to None which resolves to the workspace of the attached lakehouse
106
+ or if no lakehouse attached, resolves to the workspace of the notebook.
107
+ report_workspace : str | uuid.UUID | List[str | uuid.UUID], default=None
108
+ The name(s) or IDs of the Fabric workspace(s) in which the report(s) reside(s).
109
+ Defaults to None which finds all reports in all workspaces which use the semantic model and rebinds them to
110
+ the new semantic model.
111
+ """
112
+
113
+ (dataset_name, dataset_id) = resolve_item_name_and_id(
114
+ item=dataset, type="SemanticModel", workspace=dataset_workspace
115
+ )
116
+ new_dataset_id = resolve_item_id(
117
+ item=new_dataset, type="SemanticModel", workspace=new_dataset_workspace
118
+ )
119
+
120
+ if dataset_id == new_dataset_id:
121
+ raise ValueError(
122
+ f"{icons.red_dot} The 'dataset' and 'new_dataset' parameters are both set to the same semantic model within the same workspace. These parameters must be set to different values."
123
+ )
124
+ dataset_workspace_id = resolve_workspace_id(workspace=dataset_workspace)
125
+
126
+ if isinstance(report_workspace, str) or report_workspace is None:
127
+ report_workspace = [report_workspace]
128
+
129
+ for w in report_workspace:
130
+ dfR = fabric.list_reports(workspace=w)
131
+ dfR_filt = dfR[
132
+ (dfR["Dataset ID"] == dataset_id)
133
+ & (dfR["Dataset Workspace Id"] == dataset_workspace_id)
134
+ ]
135
+ if dfR_filt.empty:
136
+ (wksp_name, _) = resolve_workspace_name_and_id(workspace=w)
137
+ print(
138
+ f"{icons.info} No reports found for the '{dataset_name}' semantic model within the '{wksp_name}' workspace."
139
+ )
140
+ else:
141
+ # Rebind reports to new dataset
142
+ for _, r in dfR_filt.iterrows():
143
+ rpt_name = r["Name"]
144
+ report_rebind(
145
+ report=rpt_name,
146
+ dataset=new_dataset,
147
+ report_workspace=w,
148
+ dataset_workspace=new_dataset_workspace,
149
+ )