semantic-link-labs 0.9.3__py3-none-any.whl → 0.9.5__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 (68) hide show
  1. {semantic_link_labs-0.9.3.dist-info → semantic_link_labs-0.9.5.dist-info}/METADATA +25 -6
  2. {semantic_link_labs-0.9.3.dist-info → semantic_link_labs-0.9.5.dist-info}/RECORD +68 -52
  3. {semantic_link_labs-0.9.3.dist-info → semantic_link_labs-0.9.5.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +45 -4
  5. sempy_labs/_capacities.py +22 -127
  6. sempy_labs/_capacity_migration.py +11 -9
  7. sempy_labs/_dashboards.py +60 -0
  8. sempy_labs/_data_pipelines.py +5 -31
  9. sempy_labs/_dax.py +17 -3
  10. sempy_labs/_delta_analyzer.py +279 -127
  11. sempy_labs/_environments.py +20 -48
  12. sempy_labs/_eventhouses.py +69 -30
  13. sempy_labs/_eventstreams.py +16 -34
  14. sempy_labs/_gateways.py +4 -4
  15. sempy_labs/_generate_semantic_model.py +30 -10
  16. sempy_labs/_git.py +90 -1
  17. sempy_labs/_graphQL.py +3 -20
  18. sempy_labs/_helper_functions.py +201 -44
  19. sempy_labs/_job_scheduler.py +226 -2
  20. sempy_labs/_kql_databases.py +19 -34
  21. sempy_labs/_kql_querysets.py +15 -32
  22. sempy_labs/_list_functions.py +14 -133
  23. sempy_labs/_mirrored_databases.py +14 -48
  24. sempy_labs/_ml_experiments.py +5 -30
  25. sempy_labs/_ml_models.py +4 -28
  26. sempy_labs/_model_bpa.py +17 -0
  27. sempy_labs/_model_bpa_rules.py +12 -2
  28. sempy_labs/_mounted_data_factories.py +119 -0
  29. sempy_labs/_notebooks.py +16 -26
  30. sempy_labs/_semantic_models.py +117 -0
  31. sempy_labs/_sql.py +78 -10
  32. sempy_labs/_sqldatabase.py +227 -0
  33. sempy_labs/_utils.py +42 -0
  34. sempy_labs/_vertipaq.py +17 -2
  35. sempy_labs/_warehouses.py +5 -17
  36. sempy_labs/_workloads.py +23 -9
  37. sempy_labs/_workspaces.py +13 -5
  38. sempy_labs/admin/__init__.py +70 -9
  39. sempy_labs/admin/_activities.py +166 -0
  40. sempy_labs/admin/_apps.py +143 -0
  41. sempy_labs/admin/_artifacts.py +62 -0
  42. sempy_labs/admin/_basic_functions.py +32 -704
  43. sempy_labs/admin/_capacities.py +311 -0
  44. sempy_labs/admin/_datasets.py +184 -0
  45. sempy_labs/admin/_domains.py +1 -1
  46. sempy_labs/admin/_items.py +3 -1
  47. sempy_labs/admin/_reports.py +239 -0
  48. sempy_labs/admin/_scanner.py +0 -1
  49. sempy_labs/admin/_shared.py +76 -0
  50. sempy_labs/admin/_tenant.py +489 -0
  51. sempy_labs/admin/_users.py +133 -0
  52. sempy_labs/admin/_workspaces.py +148 -0
  53. sempy_labs/directlake/_dl_helper.py +0 -1
  54. sempy_labs/directlake/_update_directlake_partition_entity.py +14 -0
  55. sempy_labs/graph/_teams.py +1 -1
  56. sempy_labs/graph/_users.py +9 -1
  57. sempy_labs/lakehouse/__init__.py +2 -0
  58. sempy_labs/lakehouse/_lakehouse.py +6 -7
  59. sempy_labs/lakehouse/_shortcuts.py +216 -64
  60. sempy_labs/report/__init__.py +3 -1
  61. sempy_labs/report/_download_report.py +4 -1
  62. sempy_labs/report/_export_report.py +272 -0
  63. sempy_labs/report/_generate_report.py +9 -17
  64. sempy_labs/report/_report_bpa.py +12 -19
  65. sempy_labs/report/_report_functions.py +9 -261
  66. sempy_labs/tom/_model.py +307 -40
  67. {semantic_link_labs-0.9.3.dist-info → semantic_link_labs-0.9.5.dist-info}/LICENSE +0 -0
  68. {semantic_link_labs-0.9.3.dist-info → semantic_link_labs-0.9.5.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,6 @@ from sempy_labs.report._download_report import download_report
14
14
  from sempy_labs.report._report_functions import (
15
15
  get_report_json,
16
16
  # report_dependency_tree,
17
- export_report,
18
17
  clone_report,
19
18
  launch_report,
20
19
  # translate_report_titles
@@ -25,6 +24,9 @@ from sempy_labs.report._report_rebind import (
25
24
  )
26
25
  from sempy_labs.report._report_bpa_rules import report_bpa_rules
27
26
  from sempy_labs.report._report_bpa import run_report_bpa
27
+ from sempy_labs.report._export_report import (
28
+ export_report,
29
+ )
28
30
 
29
31
  __all__ = [
30
32
  "create_report_from_reportjson",
@@ -6,6 +6,7 @@ from sempy_labs._helper_functions import (
6
6
  resolve_lakehouse_name,
7
7
  _base_api,
8
8
  resolve_item_id,
9
+ _mount,
9
10
  )
10
11
  from sempy_labs.lakehouse._lakehouse import lakehouse_attached
11
12
  from uuid import UUID
@@ -63,7 +64,9 @@ def download_report(
63
64
  )
64
65
 
65
66
  # Save file to the attached lakehouse
66
- with open(f"/lakehouse/default/Files/{file_name}.pbix", "wb") as file:
67
+ local_path = _mount()
68
+ save_file = f"{local_path}/Files/{file_name}.pbix"
69
+ with open(save_file, "wb") as file:
67
70
  file.write(response.content)
68
71
 
69
72
  print(
@@ -0,0 +1,272 @@
1
+ import sempy.fabric as fabric
2
+ import json
3
+ import os
4
+ import time
5
+ from sempy_labs._helper_functions import (
6
+ generate_embedded_filter,
7
+ resolve_workspace_name_and_id,
8
+ _base_api,
9
+ _mount,
10
+ )
11
+ from typing import Optional
12
+ from sempy._utils._log import log
13
+ import sempy_labs._icons as icons
14
+ from uuid import UUID
15
+ from sempy_labs.report._report_functions import (
16
+ list_report_visuals,
17
+ list_report_pages,
18
+ )
19
+
20
+
21
+ @log
22
+ def export_report(
23
+ report: str,
24
+ export_format: str,
25
+ file_name: Optional[str] = None,
26
+ bookmark_name: Optional[str] = None,
27
+ page_name: Optional[str] = None,
28
+ visual_name: Optional[str] = None,
29
+ report_filter: Optional[str] = None,
30
+ workspace: Optional[str | UUID] = None,
31
+ lakehouse: Optional[str | UUID] = None,
32
+ lakehouse_workspace: Optional[str | UUID] = None,
33
+ ):
34
+ """
35
+ Exports a Power BI report to a file in your lakehouse.
36
+
37
+ This is a wrapper function for the following APIs: `Reports - Export To File In Group <https://learn.microsoft.com/rest/api/power-bi/reports/export-to-file-in-group>`_, `Reports - Get Export To File Status In Group <https://learn.microsoft.com/rest/api/power-bi/reports/get-export-to-file-status-in-group>`_, `Reports - Get File Of Export To File In Group <https://learn.microsoft.com/rest/api/power-bi/reports/get-file-of-export-to-file-in-group>`_.
38
+
39
+ Parameters
40
+ ----------
41
+ report : str
42
+ Name of the Power BI report.
43
+ export_format : str
44
+ The format in which to export the report. For image formats, enter the file extension in this parameter, not 'IMAGE'.
45
+ `Valid formats <https://learn.microsoft.com/rest/api/power-bi/reports/export-to-file-in-group#fileformat>`_
46
+ file_name : str, default=None
47
+ The name of the file to be saved within the lakehouse. Do not include the file extension. Defaults ot the reportName parameter value.
48
+ bookmark_name : str, default=None
49
+ The name (GUID) of a bookmark within the report.
50
+ page_name : str, default=None
51
+ The name (GUID) of the report page.
52
+ visual_name : str, default=None
53
+ The name (GUID) of a visual. If you specify this parameter you must also specify the page_name parameter.
54
+ report_filter : str, default=None
55
+ A report filter to be applied when exporting the report. Syntax is user-friendly. See above for examples.
56
+ workspace : str | uuid.UUID, default=None
57
+ The Fabric workspace name or ID.
58
+ Defaults to None which resolves to the workspace of the attached lakehouse
59
+ or if no lakehouse attached, resolves to the workspace of the notebook.
60
+ lakehouse : str | uuid.UUID, default=None
61
+ The Fabric lakehouse name or ID. This will be the lakehouse to which the export of the report is saved.
62
+ Defaults to None which resolves to the lakehouse attached to the notebook.
63
+ lakehouse_workspace : str | uuid.UUID, default=None
64
+ The Fabric workspace name or ID used by the lakehouse.
65
+ Defaults to None which resolves to the workspace of the attached lakehouse
66
+ or if no lakehouse attached, resolves to the workspace of the notebook.
67
+ """
68
+
69
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
70
+
71
+ if isinstance(page_name, str):
72
+ page_name = [page_name]
73
+ if isinstance(visual_name, str):
74
+ visual_name = [visual_name]
75
+
76
+ if bookmark_name is not None and (page_name is not None or visual_name is not None):
77
+ raise ValueError(
78
+ f"{icons.red_dot} If the 'bookmark_name' parameter is set, the 'page_name' and 'visual_name' parameters must not be set."
79
+ )
80
+
81
+ if visual_name is not None and page_name is None:
82
+ raise ValueError(
83
+ f"{icons.red_dot} If the 'visual_name' parameter is set, the 'page_name' parameter must be set."
84
+ )
85
+
86
+ valid_formats = {
87
+ "ACCESSIBLEPDF": ".pdf",
88
+ "CSV": ".csv",
89
+ "DOCX": ".docx",
90
+ "MHTML": ".mhtml",
91
+ "PDF": ".pdf",
92
+ "PNG": ".png",
93
+ "PPTX": ".pptx",
94
+ "XLSX": ".xlsx",
95
+ "XML": ".xml",
96
+ "BMP": ".bmp",
97
+ "EMF": ".emf",
98
+ "GIF": ".gif",
99
+ "JPEG": ".jpeg",
100
+ "TIFF": ".tiff",
101
+ }
102
+
103
+ export_format = export_format.upper()
104
+ file_ext = valid_formats.get(export_format)
105
+ if file_ext is None:
106
+ raise ValueError(
107
+ f"{icons.red_dot} The '{export_format}' format is not a valid format for exporting Power BI reports. Please enter a valid format. Options: {valid_formats}"
108
+ )
109
+
110
+ if file_name is None:
111
+ file_name = f"{report}{file_ext}"
112
+ else:
113
+ file_name = f"{file_name}{file_ext}"
114
+
115
+ dfI = fabric.list_items(workspace=workspace)
116
+ dfI_filt = dfI[
117
+ (dfI["Type"].isin(["Report", "PaginatedReport"]))
118
+ & (dfI["Display Name"] == report)
119
+ ]
120
+
121
+ if dfI_filt.empty:
122
+ raise ValueError(
123
+ f"{icons.red_dot} The '{report}' report does not exist in the '{workspace_name}' workspace."
124
+ )
125
+
126
+ report_type = dfI_filt["Type"].iloc[0]
127
+
128
+ # Limitations
129
+ pbiOnly = ["PNG"]
130
+ paginatedOnly = [
131
+ "ACCESSIBLEPDF",
132
+ "CSV",
133
+ "DOCX",
134
+ "BMP",
135
+ "EMF",
136
+ "GIF",
137
+ "JPEG",
138
+ "TIFF",
139
+ "MHTML",
140
+ "XLSX",
141
+ "XML",
142
+ ]
143
+
144
+ if report_type == "Report" and export_format in paginatedOnly:
145
+ raise ValueError(
146
+ f"{icons.red_dot} The '{export_format}' format is only supported for paginated reports."
147
+ )
148
+
149
+ if report_type == "PaginatedReport" and export_format in pbiOnly:
150
+ raise ValueError(
151
+ f"{icons.red_dot} The '{export_format}' format is only supported for Power BI reports."
152
+ )
153
+
154
+ if report_type == "PaginatedReport" and (
155
+ bookmark_name is not None or page_name is not None or visual_name is not None
156
+ ):
157
+ raise ValueError(
158
+ f"{icons.red_dot} Export for paginated reports does not support bookmarks/pages/visuals. Those parameters must not be set for paginated reports."
159
+ )
160
+
161
+ reportId = dfI_filt["Id"].iloc[0]
162
+
163
+ if (
164
+ export_format in ["BMP", "EMF", "GIF", "JPEG", "TIFF"]
165
+ and report_type == "PaginatedReport"
166
+ ):
167
+ request_body = {
168
+ "format": "IMAGE",
169
+ "paginatedReportConfiguration": {
170
+ "formatSettings": {"OutputFormat": export_format.lower()}
171
+ },
172
+ }
173
+ elif bookmark_name is None and page_name is None and visual_name is None:
174
+ request_body = {"format": export_format}
175
+ elif bookmark_name is not None:
176
+ if report_type == "Report":
177
+ request_body = {
178
+ "format": export_format,
179
+ "powerBIReportConfiguration": {
180
+ "defaultBookmark": {"name": bookmark_name}
181
+ },
182
+ }
183
+ elif page_name is not None and visual_name is None:
184
+ if report_type == "Report":
185
+ request_body = {"format": export_format, "powerBIReportConfiguration": {}}
186
+
187
+ request_body["powerBIReportConfiguration"]["pages"] = []
188
+ dfPage = list_report_pages(report=report, workspace=workspace_id)
189
+
190
+ for page in page_name:
191
+ dfPage_filt = dfPage[dfPage["Page ID"] == page]
192
+ if len(dfPage_filt) == 0:
193
+ raise ValueError(
194
+ f"{icons.red_dot} The '{page}' page does not exist in the '{report}' report within the '{workspace_name}' workspace."
195
+ )
196
+
197
+ page_dict = {"pageName": page}
198
+ request_body["powerBIReportConfiguration"]["pages"].append(page_dict)
199
+
200
+ elif page_name is not None and visual_name is not None:
201
+ if len(page_name) != len(visual_name):
202
+ raise ValueError(
203
+ f"{icons.red_dot} Each 'visual_name' must map to a single 'page_name'."
204
+ )
205
+
206
+ if report_type == "Report":
207
+ request_body = {"format": export_format, "powerBIReportConfiguration": {}}
208
+
209
+ request_body["powerBIReportConfiguration"]["pages"] = []
210
+ dfVisual = list_report_visuals(report=report, workspace=workspace_id)
211
+ a = 0
212
+ for page in page_name:
213
+ visual = visual_name[a]
214
+
215
+ dfVisual_filt = dfVisual[
216
+ (dfVisual["Page ID"] == page) & (dfVisual["Visual ID"] == visual)
217
+ ]
218
+ if len(dfVisual_filt) == 0:
219
+ raise ValueError(
220
+ f"{icons.red_dot} The '{visual}' visual does not exist on the '{page}' in the '{report}' report within the '{workspace_name}' workspace."
221
+ )
222
+
223
+ page_dict = {"pageName": page, "visualName": visual}
224
+ request_body["powerBIReportConfiguration"]["pages"].append(page_dict)
225
+ a += 1
226
+
227
+ # Transform and add report filter if it is specified
228
+ if report_filter is not None and report_type == "Report":
229
+ reportFilter = generate_embedded_filter(filter=report_filter)
230
+ report_level_filter = {"filter": reportFilter}
231
+
232
+ if "powerBIReportConfiguration" not in request_body:
233
+ request_body["powerBIReportConfiguration"] = {}
234
+ request_body["powerBIReportConfiguration"]["reportLevelFilters"] = [
235
+ report_level_filter
236
+ ]
237
+
238
+ base_url = f"/v1.0/myorg/groups/{workspace_id}/reports/{reportId}"
239
+ response = _base_api(
240
+ request=f"{base_url}/ExportTo",
241
+ method="post",
242
+ payload=request_body,
243
+ status_codes=202,
244
+ )
245
+ export_id = json.loads(response.content).get("id")
246
+
247
+ get_status_url = f"{base_url}/exports/{export_id}"
248
+ response = _base_api(request=get_status_url, status_codes=[200, 202])
249
+ response_body = json.loads(response.content)
250
+ while response_body["status"] not in ["Succeeded", "Failed"]:
251
+ time.sleep(3)
252
+ response = _base_api(request=get_status_url, status_codes=[200, 202])
253
+ response_body = json.loads(response.content)
254
+ if response_body["status"] == "Failed":
255
+ raise ValueError(
256
+ f"{icons.red_dot} The export for the '{report}' report within the '{workspace_name}' workspace in the '{export_format}' format has failed."
257
+ )
258
+ else:
259
+ response = _base_api(request=f"{get_status_url}/file")
260
+ print(
261
+ f"{icons.in_progress} Saving the '{export_format}' export for the '{report}' report within the '{workspace_name}' workspace to the lakehouse..."
262
+ )
263
+
264
+ local_path = _mount(lakehouse=lakehouse, workspace=lakehouse_workspace)
265
+ folder_path = f"{local_path}/Files"
266
+ file_path = os.path.join(folder_path, file_name)
267
+
268
+ with open(file_path, "wb") as export_file:
269
+ export_file.write(response.content)
270
+ print(
271
+ f"{icons.green_dot} The '{export_format}' export for the '{report}' report within the '{workspace_name}' workspace has been saved '{file_name}' in the '{lakehouse}' within the '{lakehouse_workspace}' workspace."
272
+ )
@@ -11,6 +11,7 @@ from sempy_labs._helper_functions import (
11
11
  _update_dataframe_datatypes,
12
12
  _base_api,
13
13
  resolve_item_id,
14
+ get_item_definition,
14
15
  )
15
16
  import sempy_labs._icons as icons
16
17
  from sempy._utils._log import log
@@ -178,7 +179,9 @@ def update_report_from_reportjson(
178
179
 
179
180
 
180
181
  def get_report_definition(
181
- report: str, workspace: Optional[str | UUID] = None, return_dataframe: bool = True
182
+ report: str | UUID,
183
+ workspace: Optional[str | UUID] = None,
184
+ return_dataframe: bool = True,
182
185
  ) -> pd.DataFrame | dict:
183
186
  """
184
187
  Gets the collection of definition files of a report.
@@ -187,8 +190,8 @@ def get_report_definition(
187
190
 
188
191
  Parameters
189
192
  ----------
190
- report : str
191
- Name of the report.
193
+ report : str | uuid.UUID
194
+ Name or ID of the report.
192
195
  workspace : str | uuid.UUID, default=None
193
196
  The Fabric workspace name or ID in which the report resides.
194
197
  Defaults to None which resolves to the workspace of the attached lakehouse
@@ -198,25 +201,14 @@ def get_report_definition(
198
201
 
199
202
  Returns
200
203
  -------
201
- pandas.DataFrame | dict
204
+ pandas.DataFrame
202
205
  The collection of report definition files within a pandas dataframe.
203
206
  """
204
207
 
205
- (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
206
- report_id = resolve_item_id(item=report, type="Report", workspace=workspace)
207
-
208
- result = _base_api(
209
- request=f"/v1/workspaces/{workspace_id}/reports/{report_id}/getDefinition",
210
- method="post",
211
- lro_return_json=True,
212
- status_codes=None,
208
+ return get_item_definition(
209
+ item=report, type="Report", workspace=workspace, return_dataframe=True
213
210
  )
214
211
 
215
- if return_dataframe:
216
- return pd.json_normalize(result["definition"]["parts"])
217
- else:
218
- return result
219
-
220
212
 
221
213
  @log
222
214
  def create_model_bpa_report(
@@ -1,4 +1,3 @@
1
- import sempy.fabric as fabric
2
1
  from typing import Optional
3
2
  import pandas as pd
4
3
  import datetime
@@ -7,8 +6,7 @@ from sempy_labs.report import ReportWrapper, report_bpa_rules
7
6
  from sempy_labs._helper_functions import (
8
7
  format_dax_object_name,
9
8
  save_as_delta_table,
10
- resolve_report_id,
11
- resolve_lakehouse_name,
9
+ resolve_item_name_and_id,
12
10
  resolve_workspace_capacity,
13
11
  _get_column_aggregate,
14
12
  resolve_workspace_name_and_id,
@@ -54,9 +52,7 @@ def run_report_bpa(
54
52
  A pandas dataframe in HTML format showing report objects which violated the best practice analyzer rules.
55
53
  """
56
54
 
57
- (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
58
-
59
- rpt = ReportWrapper(report=report, workspace=workspace_id)
55
+ rpt = ReportWrapper(report=report, workspace=workspace)
60
56
 
61
57
  dfCV = rpt.list_custom_visuals()
62
58
  dfP = rpt.list_pages()
@@ -149,7 +145,7 @@ def run_report_bpa(
149
145
  df_output["Description"] = row["Description"]
150
146
  df_output["URL"] = row["URL"]
151
147
  df_output["Report URL"] = helper.get_web_url(
152
- report=report, workspace=workspace_id
148
+ report=report, workspace=workspace
153
149
  )
154
150
 
155
151
  page_mapping_dict = dfP.set_index("Page Display Name")["Page URL"].to_dict()
@@ -205,31 +201,28 @@ def run_report_bpa(
205
201
 
206
202
  now = datetime.datetime.now()
207
203
  delta_table_name = "reportbparesults"
208
- lakehouse_id = fabric.get_lakehouse_id()
209
- lake_workspace = fabric.resolve_workspace_name()
210
- lakehouse = resolve_lakehouse_name(
211
- lakehouse_id=lakehouse_id, workspace=lake_workspace
212
- )
213
-
214
- lakeT = get_lakehouse_tables(lakehouse=lakehouse, workspace=lake_workspace)
204
+ lakeT = get_lakehouse_tables()
215
205
  lakeT_filt = lakeT[lakeT["Table Name"] == delta_table_name]
216
206
 
217
207
  if len(lakeT_filt) == 0:
218
208
  runId = 1
219
209
  else:
220
- max_run_id = _get_column_aggregate(
221
- lakehouse=lakehouse, table_name=delta_table_name
222
- )
210
+ max_run_id = _get_column_aggregate(table_name=delta_table_name)
223
211
  runId = max_run_id + 1
224
212
 
213
+ (workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
214
+ (report_name, report_id) = resolve_item_name_and_id(
215
+ item=report, type="Report", workspace=workspace_id
216
+ )
217
+
225
218
  export_df = finalDF.copy()
226
219
  capacity_id, capacity_name = resolve_workspace_capacity(workspace=workspace_id)
227
220
  export_df["Capacity Name"] = capacity_name
228
221
  export_df["Capacity Id"] = capacity_id
229
222
  export_df["Workspace Name"] = workspace_name
230
223
  export_df["Workspace Id"] = workspace_id
231
- export_df["Report Name"] = report
232
- export_df["Report Id"] = resolve_report_id(report, workspace_id)
224
+ export_df["Report Name"] = report_name
225
+ export_df["Report Id"] = report_id
233
226
  export_df["RunId"] = runId
234
227
  export_df["Timestamp"] = now
235
228
  export_df["RunId"] = export_df["RunId"].astype(int)