semantic-link-labs 0.7.3__py3-none-any.whl → 0.8.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 (75) hide show
  1. {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/METADATA +19 -4
  2. {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/RECORD +75 -50
  3. {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +109 -31
  5. sempy_labs/_bpa_translation/{_translations_am-ET.po → _model/_translations_am-ET.po} +22 -0
  6. sempy_labs/_bpa_translation/{_translations_ar-AE.po → _model/_translations_ar-AE.po} +24 -0
  7. sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +938 -0
  8. sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +934 -0
  9. sempy_labs/_bpa_translation/{_translations_cs-CZ.po → _model/_translations_cs-CZ.po} +179 -157
  10. sempy_labs/_bpa_translation/{_translations_da-DK.po → _model/_translations_da-DK.po} +24 -0
  11. sempy_labs/_bpa_translation/{_translations_de-DE.po → _model/_translations_de-DE.po} +77 -52
  12. sempy_labs/_bpa_translation/{_translations_el-GR.po → _model/_translations_el-GR.po} +25 -0
  13. sempy_labs/_bpa_translation/{_translations_es-ES.po → _model/_translations_es-ES.po} +67 -43
  14. sempy_labs/_bpa_translation/{_translations_fa-IR.po → _model/_translations_fa-IR.po} +24 -0
  15. sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +915 -0
  16. sempy_labs/_bpa_translation/{_translations_fr-FR.po → _model/_translations_fr-FR.po} +83 -57
  17. sempy_labs/_bpa_translation/{_translations_ga-IE.po → _model/_translations_ga-IE.po} +25 -0
  18. sempy_labs/_bpa_translation/{_translations_he-IL.po → _model/_translations_he-IL.po} +23 -0
  19. sempy_labs/_bpa_translation/{_translations_hi-IN.po → _model/_translations_hi-IN.po} +24 -0
  20. sempy_labs/_bpa_translation/{_translations_hu-HU.po → _model/_translations_hu-HU.po} +25 -0
  21. sempy_labs/_bpa_translation/_model/_translations_id-ID.po +918 -0
  22. sempy_labs/_bpa_translation/{_translations_is-IS.po → _model/_translations_is-IS.po} +25 -0
  23. sempy_labs/_bpa_translation/{_translations_it-IT.po → _model/_translations_it-IT.po} +25 -0
  24. sempy_labs/_bpa_translation/{_translations_ja-JP.po → _model/_translations_ja-JP.po} +21 -0
  25. sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +823 -0
  26. sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +937 -0
  27. sempy_labs/_bpa_translation/{_translations_nl-NL.po → _model/_translations_nl-NL.po} +80 -56
  28. sempy_labs/_bpa_translation/{_translations_pl-PL.po → _model/_translations_pl-PL.po} +101 -76
  29. sempy_labs/_bpa_translation/{_translations_pt-BR.po → _model/_translations_pt-BR.po} +25 -0
  30. sempy_labs/_bpa_translation/{_translations_pt-PT.po → _model/_translations_pt-PT.po} +25 -0
  31. sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +939 -0
  32. sempy_labs/_bpa_translation/{_translations_ru-RU.po → _model/_translations_ru-RU.po} +25 -0
  33. sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +925 -0
  34. sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +922 -0
  35. sempy_labs/_bpa_translation/{_translations_ta-IN.po → _model/_translations_ta-IN.po} +26 -0
  36. sempy_labs/_bpa_translation/{_translations_te-IN.po → _model/_translations_te-IN.po} +24 -0
  37. sempy_labs/_bpa_translation/{_translations_th-TH.po → _model/_translations_th-TH.po} +24 -0
  38. sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +925 -0
  39. sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +933 -0
  40. sempy_labs/_bpa_translation/{_translations_zh-CN.po → _model/_translations_zh-CN.po} +116 -97
  41. sempy_labs/_bpa_translation/{_translations_zu-ZA.po → _model/_translations_zu-ZA.po} +25 -0
  42. sempy_labs/_capacities.py +577 -0
  43. sempy_labs/_capacity_migration.py +624 -0
  44. sempy_labs/_clear_cache.py +8 -8
  45. sempy_labs/_connections.py +140 -0
  46. sempy_labs/_environments.py +156 -0
  47. sempy_labs/_git.py +20 -21
  48. sempy_labs/_helper_functions.py +151 -10
  49. sempy_labs/_icons.py +62 -0
  50. sempy_labs/_list_functions.py +232 -887
  51. sempy_labs/_model_bpa.py +8 -32
  52. sempy_labs/_notebooks.py +143 -0
  53. sempy_labs/_query_scale_out.py +30 -8
  54. sempy_labs/_spark.py +460 -0
  55. sempy_labs/_sql.py +88 -19
  56. sempy_labs/_translations.py +3 -0
  57. sempy_labs/_vertipaq.py +162 -99
  58. sempy_labs/_workspaces.py +294 -0
  59. sempy_labs/admin/__init__.py +53 -0
  60. sempy_labs/admin/_basic_functions.py +806 -0
  61. sempy_labs/admin/_domains.py +411 -0
  62. sempy_labs/directlake/_directlake_schema_sync.py +1 -2
  63. sempy_labs/directlake/_generate_shared_expression.py +11 -14
  64. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +14 -24
  65. sempy_labs/report/__init__.py +9 -6
  66. sempy_labs/report/_report_bpa.py +359 -0
  67. sempy_labs/report/_report_bpa_rules.py +113 -0
  68. sempy_labs/report/_report_helper.py +254 -0
  69. sempy_labs/report/_report_list_functions.py +95 -0
  70. sempy_labs/report/_report_rebind.py +0 -4
  71. sempy_labs/report/_reportwrapper.py +2039 -0
  72. sempy_labs/tom/_model.py +83 -5
  73. {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/LICENSE +0 -0
  74. {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/top_level.txt +0 -0
  75. /sempy_labs/_bpa_translation/{_translations_sv-SE.po → _model/_translations_sv-SE.po} +0 -0
sempy_labs/_spark.py ADDED
@@ -0,0 +1,460 @@
1
+ import sempy.fabric as fabric
2
+ import pandas as pd
3
+ import sempy_labs._icons as icons
4
+ from typing import Optional
5
+ from sempy_labs._helper_functions import (
6
+ resolve_workspace_name_and_id,
7
+ )
8
+ from sempy.fabric.exceptions import FabricHTTPException
9
+
10
+
11
+ def list_custom_pools(workspace: Optional[str] = None) -> pd.DataFrame:
12
+ """
13
+ Lists all `custom pools <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
14
+
15
+ Parameters
16
+ ----------
17
+ workspace : str, default=None
18
+ The name of the Fabric workspace.
19
+ Defaults to None which resolves to the workspace of the attached lakehouse
20
+ or if no lakehouse attached, resolves to the workspace of the notebook.
21
+
22
+ Returns
23
+ -------
24
+ pandas.DataFrame
25
+ A pandas dataframe showing all the custom pools within the Fabric workspace.
26
+ """
27
+
28
+ # https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/list-workspace-custom-pools
29
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
30
+
31
+ df = pd.DataFrame(
32
+ columns=[
33
+ "Custom Pool ID",
34
+ "Custom Pool Name",
35
+ "Type",
36
+ "Node Family",
37
+ "Node Size",
38
+ "Auto Scale Enabled",
39
+ "Auto Scale Min Node Count",
40
+ "Auto Scale Max Node Count",
41
+ "Dynamic Executor Allocation Enabled",
42
+ "Dynamic Executor Allocation Min Executors",
43
+ "Dynamic Executor Allocation Max Executors",
44
+ ]
45
+ )
46
+
47
+ client = fabric.FabricRestClient()
48
+ response = client.get(f"/v1/workspaces/{workspace_id}/spark/pools")
49
+ if response.status_code != 200:
50
+ raise FabricHTTPException(response)
51
+
52
+ for i in response.json()["value"]:
53
+
54
+ aScale = i.get("autoScale", {})
55
+ d = i.get("dynamicExecutorAllocation", {})
56
+
57
+ new_data = {
58
+ "Custom Pool ID": i.get("id"),
59
+ "Custom Pool Name": i.get("name"),
60
+ "Type": i.get("type"),
61
+ "Node Family": i.get("nodeFamily"),
62
+ "Node Size": i.get("nodeSize"),
63
+ "Auto Scale Enabled": aScale.get("enabled"),
64
+ "Auto Scale Min Node Count": aScale.get("minNodeCount"),
65
+ "Auto Scale Max Node Count": aScale.get("maxNodeCount"),
66
+ "Dynamic Executor Allocation Enabled": d.get("enabled"),
67
+ "Dynamic Executor Allocation Min Executors": d.get("minExecutors"),
68
+ "Dynamic Executor Allocation Max Executors": d.get("maxExecutors"),
69
+ }
70
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
71
+
72
+ bool_cols = ["Auto Scale Enabled", "Dynamic Executor Allocation Enabled"]
73
+ int_cols = [
74
+ "Auto Scale Min Node Count",
75
+ "Auto Scale Max Node Count",
76
+ "Dynamic Executor Allocation Enabled",
77
+ "Dynamic Executor Allocation Min Executors",
78
+ "Dynamic Executor Allocation Max Executors",
79
+ ]
80
+
81
+ df[bool_cols] = df[bool_cols].astype(bool)
82
+ df[int_cols] = df[int_cols].astype(int)
83
+
84
+ return df
85
+
86
+
87
+ def create_custom_pool(
88
+ pool_name: str,
89
+ node_size: str,
90
+ min_node_count: int,
91
+ max_node_count: int,
92
+ min_executors: int,
93
+ max_executors: int,
94
+ node_family: Optional[str] = "MemoryOptimized",
95
+ auto_scale_enabled: Optional[bool] = True,
96
+ dynamic_executor_allocation_enabled: Optional[bool] = True,
97
+ workspace: Optional[str] = None,
98
+ ):
99
+ """
100
+ Creates a `custom pool <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
101
+
102
+ Parameters
103
+ ----------
104
+ pool_name : str
105
+ The custom pool name.
106
+ node_size : str
107
+ The `node size <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#nodesize>`_.
108
+ min_node_count : int
109
+ The `minimum node count <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
110
+ max_node_count : int
111
+ The `maximum node count <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
112
+ min_executors : int
113
+ The `minimum executors <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
114
+ max_executors : int
115
+ The `maximum executors <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
116
+ node_family : str, default='MemoryOptimized'
117
+ The `node family <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#nodefamily>`_.
118
+ auto_scale_enabled : bool, default=True
119
+ The status of `auto scale <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
120
+ dynamic_executor_allocation_enabled : bool, default=True
121
+ The status of the `dynamic executor allocation <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
122
+ workspace : str, default=None
123
+ The name of the Fabric workspace.
124
+ Defaults to None which resolves to the workspace of the attached lakehouse
125
+ or if no lakehouse attached, resolves to the workspace of the notebook.
126
+ """
127
+
128
+ # https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool
129
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
130
+
131
+ request_body = {
132
+ "name": pool_name,
133
+ "nodeFamily": node_family,
134
+ "nodeSize": node_size,
135
+ "autoScale": {
136
+ "enabled": auto_scale_enabled,
137
+ "minNodeCount": min_node_count,
138
+ "maxNodeCount": max_node_count,
139
+ },
140
+ "dynamicExecutorAllocation": {
141
+ "enabled": dynamic_executor_allocation_enabled,
142
+ "minExecutors": min_executors,
143
+ "maxExecutors": max_executors,
144
+ },
145
+ }
146
+
147
+ client = fabric.FabricRestClient()
148
+ response = client.post(
149
+ f"/v1/workspaces/{workspace_id}/spark/pools", json=request_body
150
+ )
151
+
152
+ if response.status_code != 201:
153
+ raise FabricHTTPException(response)
154
+ print(
155
+ f"{icons.green_dot} The '{pool_name}' spark pool has been created within the '{workspace}' workspace."
156
+ )
157
+
158
+
159
+ def update_custom_pool(
160
+ pool_name: str,
161
+ node_size: Optional[str] = None,
162
+ min_node_count: Optional[int] = None,
163
+ max_node_count: Optional[int] = None,
164
+ min_executors: Optional[int] = None,
165
+ max_executors: Optional[int] = None,
166
+ node_family: Optional[str] = None,
167
+ auto_scale_enabled: Optional[bool] = None,
168
+ dynamic_executor_allocation_enabled: Optional[bool] = None,
169
+ workspace: Optional[str] = None,
170
+ ):
171
+ """
172
+ Updates the properties of a `custom pool <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
173
+
174
+ Parameters
175
+ ----------
176
+ pool_name : str
177
+ The custom pool name.
178
+ node_size : str, default=None
179
+ The `node size <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#nodesize>`_.
180
+ Defaults to None which keeps the existing property setting.
181
+ min_node_count : int, default=None
182
+ The `minimum node count <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
183
+ Defaults to None which keeps the existing property setting.
184
+ max_node_count : int, default=None
185
+ The `maximum node count <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
186
+ Defaults to None which keeps the existing property setting.
187
+ min_executors : int, default=None
188
+ The `minimum executors <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
189
+ Defaults to None which keeps the existing property setting.
190
+ max_executors : int, default=None
191
+ The `maximum executors <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
192
+ Defaults to None which keeps the existing property setting.
193
+ node_family : str, default=None
194
+ The `node family <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#nodefamily>`_.
195
+ Defaults to None which keeps the existing property setting.
196
+ auto_scale_enabled : bool, default=None
197
+ The status of `auto scale <https://learn.microsoft.com/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#autoscaleproperties>`_.
198
+ Defaults to None which keeps the existing property setting.
199
+ dynamic_executor_allocation_enabled : bool, default=None
200
+ The status of the `dynamic executor allocation <https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool?tabs=HTTP#dynamicexecutorallocationproperties>`_.
201
+ Defaults to None which keeps the existing property setting.
202
+ workspace : str, default=None
203
+ The name of the Fabric workspace.
204
+ Defaults to None which resolves to the workspace of the attached lakehouse
205
+ or if no lakehouse attached, resolves to the workspace of the notebook.
206
+ """
207
+
208
+ # https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/update-workspace-custom-pool?tabs=HTTP
209
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
210
+
211
+ df = list_custom_pools(workspace=workspace)
212
+ df_pool = df[df["Custom Pool Name"] == pool_name]
213
+
214
+ if len(df_pool) == 0:
215
+ raise ValueError(
216
+ f"{icons.red_dot} The '{pool_name}' custom pool does not exist within the '{workspace}'. Please choose a valid custom pool."
217
+ )
218
+
219
+ if node_family is None:
220
+ node_family = df_pool["Node Family"].iloc[0]
221
+ if node_size is None:
222
+ node_size = df_pool["Node Size"].iloc[0]
223
+ if auto_scale_enabled is None:
224
+ auto_scale_enabled = bool(df_pool["Auto Scale Enabled"].iloc[0])
225
+ if min_node_count is None:
226
+ min_node_count = int(df_pool["Min Node Count"].iloc[0])
227
+ if max_node_count is None:
228
+ max_node_count = int(df_pool["Max Node Count"].iloc[0])
229
+ if dynamic_executor_allocation_enabled is None:
230
+ dynamic_executor_allocation_enabled = bool(
231
+ df_pool["Dynami Executor Allocation Enabled"].iloc[0]
232
+ )
233
+ if min_executors is None:
234
+ min_executors = int(df_pool["Min Executors"].iloc[0])
235
+ if max_executors is None:
236
+ max_executors = int(df_pool["Max Executors"].iloc[0])
237
+
238
+ request_body = {
239
+ "name": pool_name,
240
+ "nodeFamily": node_family,
241
+ "nodeSize": node_size,
242
+ "autoScale": {
243
+ "enabled": auto_scale_enabled,
244
+ "minNodeCount": min_node_count,
245
+ "maxNodeCount": max_node_count,
246
+ },
247
+ "dynamicExecutorAllocation": {
248
+ "enabled": dynamic_executor_allocation_enabled,
249
+ "minExecutors": min_executors,
250
+ "maxExecutors": max_executors,
251
+ },
252
+ }
253
+
254
+ client = fabric.FabricRestClient()
255
+ response = client.post(
256
+ f"/v1/workspaces/{workspace_id}/spark/pools", json=request_body
257
+ )
258
+
259
+ if response.status_code != 200:
260
+ raise FabricHTTPException(response)
261
+ print(
262
+ f"{icons.green_dot} The '{pool_name}' spark pool within the '{workspace}' workspace has been updated."
263
+ )
264
+
265
+
266
+ def delete_custom_pool(pool_name: str, workspace: Optional[str] = None):
267
+ """
268
+ Deletes a `custom pool <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
269
+
270
+ Parameters
271
+ ----------
272
+ pool_name : str
273
+ The custom pool name.
274
+ workspace : str, default=None
275
+ The name of the Fabric workspace.
276
+ Defaults to None which resolves to the workspace of the attached lakehouse
277
+ or if no lakehouse attached, resolves to the workspace of the notebook.
278
+ """
279
+
280
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
281
+
282
+ dfL = list_custom_pools(workspace=workspace)
283
+ dfL_filt = dfL[dfL["Custom Pool Name"] == pool_name]
284
+
285
+ if len(dfL_filt) == 0:
286
+ raise ValueError(
287
+ f"{icons.red_dot} The '{pool_name}' custom pool does not exist within the '{workspace}' workspace."
288
+ )
289
+ poolId = dfL_filt["Custom Pool ID"].iloc[0]
290
+
291
+ client = fabric.FabricRestClient()
292
+ response = client.delete(f"/v1/workspaces/{workspace_id}/spark/pools/{poolId}")
293
+
294
+ if response.status_code != 200:
295
+ raise FabricHTTPException(response)
296
+ print(
297
+ f"{icons.green_dot} The '{pool_name}' spark pool has been deleted from the '{workspace}' workspace."
298
+ )
299
+
300
+
301
+ def get_spark_settings(
302
+ workspace: Optional[str] = None, return_dataframe: Optional[bool] = True
303
+ ) -> pd.DataFrame | dict:
304
+ """
305
+ Shows the spark settings for a workspace.
306
+
307
+ Parameters
308
+ ----------
309
+ workspace : str, default=None
310
+ The name of the Fabric workspace.
311
+ Defaults to None which resolves to the workspace of the attached lakehouse
312
+ or if no lakehouse attached, resolves to the workspace of the notebook.
313
+ return_dataframe : bool, default=True
314
+ If True, returns a pandas dataframe. If False, returns a json dictionary.
315
+
316
+ Returns
317
+ -------
318
+ pandas.DataFrame | dict
319
+ A pandas dataframe showing the spark settings for a workspace.
320
+ """
321
+
322
+ # https://learn.microsoft.com/en-us/rest/api/fabric/spark/workspace-settings/get-spark-settings?tabs=HTTP
323
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
324
+
325
+ df = pd.DataFrame(
326
+ columns=[
327
+ "Automatic Log Enabled",
328
+ "High Concurrency Enabled",
329
+ "Customize Compute Enabled",
330
+ "Default Pool Name",
331
+ "Default Pool Type",
332
+ "Max Node Count",
333
+ "Max Executors",
334
+ "Environment Name",
335
+ "Runtime Version",
336
+ ]
337
+ )
338
+
339
+ client = fabric.FabricRestClient()
340
+ response = client.get(f"/v1/workspaces/{workspace_id}/spark/settings")
341
+ if response.status_code != 200:
342
+ raise FabricHTTPException(response)
343
+
344
+ i = response.json()
345
+ p = i.get("pool")
346
+ dp = i.get("pool", {}).get("defaultPool", {})
347
+ sp = i.get("pool", {}).get("starterPool", {})
348
+ e = i.get("environment", {})
349
+
350
+ new_data = {
351
+ "Automatic Log Enabled": i.get("automaticLog").get("enabled"),
352
+ "High Concurrency Enabled": i.get("highConcurrency").get(
353
+ "notebookInteractiveRunEnabled"
354
+ ),
355
+ "Customize Compute Enabled": p.get("customizeComputeEnabled"),
356
+ "Default Pool Name": dp.get("name"),
357
+ "Default Pool Type": dp.get("type"),
358
+ "Max Node Count": sp.get("maxNodeCount"),
359
+ "Max Node Executors": sp.get("maxExecutors"),
360
+ "Environment Name": e.get("name"),
361
+ "Runtime Version": e.get("runtimeVersion"),
362
+ }
363
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
364
+
365
+ bool_cols = [
366
+ "Automatic Log Enabled",
367
+ "High Concurrency Enabled",
368
+ "Customize Compute Enabled",
369
+ ]
370
+ # int_cols = ["Max Node Count", "Max Executors"]
371
+
372
+ df[bool_cols] = df[bool_cols].astype(bool)
373
+ # df[int_cols] = df[int_cols].astype(int)
374
+
375
+ if return_dataframe:
376
+ return df
377
+ else:
378
+ return response.json()
379
+
380
+
381
+ def update_spark_settings(
382
+ automatic_log_enabled: Optional[bool] = None,
383
+ high_concurrency_enabled: Optional[bool] = None,
384
+ customize_compute_enabled: Optional[bool] = None,
385
+ default_pool_name: Optional[str] = None,
386
+ max_node_count: Optional[int] = None,
387
+ max_executors: Optional[int] = None,
388
+ environment_name: Optional[str] = None,
389
+ runtime_version: Optional[str] = None,
390
+ workspace: Optional[str] = None,
391
+ ):
392
+ """
393
+ Updates the spark settings for a workspace.
394
+
395
+ Parameters
396
+ ----------
397
+ automatic_log_enabled : bool, default=None
398
+ The status of the `automatic log <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#automaticlogproperties>`_.
399
+ Defaults to None which keeps the existing property setting.
400
+ high_concurrency_enabled : bool, default=None
401
+ The status of the `high concurrency <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#highconcurrencyproperties>`_ for notebook interactive run.
402
+ Defaults to None which keeps the existing property setting.
403
+ customize_compute_enabled : bool, default=None
404
+ `Customize compute <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#poolproperties>`_ configurations for items.
405
+ Defaults to None which keeps the existing property setting.
406
+ default_pool_name : str, default=None
407
+ `Default pool <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#poolproperties>`_ for workspace.
408
+ Defaults to None which keeps the existing property setting.
409
+ max_node_count : int, default=None
410
+ The `maximum node count <https://learn.microsoft.com/en-us/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#starterpoolproperties>`_.
411
+ Defaults to None which keeps the existing property setting.
412
+ max_executors : int, default=None
413
+ The `maximum executors <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#starterpoolproperties>`_.
414
+ Defaults to None which keeps the existing property setting.
415
+ environment_name : str, default=None
416
+ The name of the `default environment <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#environmentproperties>`_. Empty string indicated there is no workspace default environment
417
+ Defaults to None which keeps the existing property setting.
418
+ runtime_version : str, default=None
419
+ The `runtime version <https://learn.microsoft.com/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP#environmentproperties>`_.
420
+ Defaults to None which keeps the existing property setting.
421
+ workspace : str, default=None
422
+ The name of the Fabric workspace.
423
+ Defaults to None which resolves to the workspace of the attached lakehouse
424
+ or if no lakehouse attached, resolves to the workspace of the notebook.
425
+ """
426
+
427
+ # https://learn.microsoft.com/en-us/rest/api/fabric/spark/workspace-settings/update-spark-settings?tabs=HTTP
428
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
429
+
430
+ request_body = get_spark_settings(workspace=workspace, return_dataframe=False)
431
+
432
+ if automatic_log_enabled is not None:
433
+ request_body["automaticLog"]["enabled"] = automatic_log_enabled
434
+ if high_concurrency_enabled is not None:
435
+ request_body["highConcurrency"][
436
+ "notebookInteractiveRunEnabled"
437
+ ] = high_concurrency_enabled
438
+ if customize_compute_enabled is not None:
439
+ request_body["pool"]["customizeComputeEnabled"] = customize_compute_enabled
440
+ if default_pool_name is not None:
441
+ request_body["pool"]["defaultPool"]["name"] = default_pool_name
442
+ if max_node_count is not None:
443
+ request_body["pool"]["starterPool"]["maxNodeCount"] = max_node_count
444
+ if max_executors is not None:
445
+ request_body["pool"]["starterPool"]["maxExecutors"] = max_executors
446
+ if environment_name is not None:
447
+ request_body["environment"]["name"] = environment_name
448
+ if runtime_version is not None:
449
+ request_body["environment"]["runtimeVersion"] = runtime_version
450
+
451
+ client = fabric.FabricRestClient()
452
+ response = client.patch(
453
+ f"/v1/workspaces/{workspace_id}/spark/settings", json=request_body
454
+ )
455
+
456
+ if response.status_code != 200:
457
+ raise FabricHTTPException(response)
458
+ print(
459
+ f"{icons.green_dot} The spark settings within the '{workspace}' workspace have been updated accordingly."
460
+ )
sempy_labs/_sql.py CHANGED
@@ -1,12 +1,12 @@
1
1
  import sempy.fabric as fabric
2
2
  import pandas as pd
3
- from typing import Optional, Union
3
+ from typing import Optional, Union, List
4
4
  from sempy._utils._log import log
5
5
  import struct
6
6
  import uuid
7
7
  from itertools import chain, repeat
8
8
  from sempy.fabric.exceptions import FabricHTTPException
9
- from sempy_labs._helper_functions import resolve_warehouse_id
9
+ from sempy_labs._helper_functions import resolve_warehouse_id, resolve_lakehouse_id
10
10
 
11
11
 
12
12
  def bytes2mswin_bstr(value: bytes) -> bytes:
@@ -28,30 +28,48 @@ def bytes2mswin_bstr(value: bytes) -> bytes:
28
28
  return struct.pack("<i", len(encoded_bytes)) + encoded_bytes
29
29
 
30
30
 
31
- class ConnectWarehouse:
31
+ class ConnectBase:
32
32
  def __init__(
33
33
  self,
34
- warehouse: str,
34
+ name: str,
35
35
  workspace: Optional[Union[str, uuid.UUID]] = None,
36
36
  timeout: Optional[int] = None,
37
+ endpoint_type: str = "warehouse",
37
38
  ):
38
39
  from sempy.fabric._token_provider import SynapseTokenProvider
39
40
  import pyodbc
40
41
 
41
42
  workspace = fabric.resolve_workspace_name(workspace)
42
43
  workspace_id = fabric.resolve_workspace_id(workspace)
43
- warehouse_id = resolve_warehouse_id(warehouse=warehouse, workspace=workspace)
44
44
 
45
- # get the TDS endpoint
45
+ # Resolve the appropriate ID (warehouse or lakehouse)
46
+ if endpoint_type == "warehouse":
47
+ resource_id = resolve_warehouse_id(warehouse=name, workspace=workspace)
48
+ else:
49
+ resource_id = resolve_lakehouse_id(lakehouse=name, workspace=workspace)
50
+
51
+ # Get the TDS endpoint
46
52
  client = fabric.FabricRestClient()
47
- response = client.get(f"v1/workspaces/{workspace_id}/warehouses/{warehouse_id}")
53
+ response = client.get(
54
+ f"v1/workspaces/{workspace_id}/{endpoint_type}s/{resource_id}"
55
+ )
48
56
  if response.status_code != 200:
49
57
  raise FabricHTTPException(response)
50
- tds_endpoint = response.json().get("properties", {}).get("connectionString")
51
58
 
59
+ if endpoint_type == "warehouse":
60
+ tds_endpoint = response.json().get("properties", {}).get("connectionString")
61
+ else:
62
+ tds_endpoint = (
63
+ response.json()
64
+ .get("properties", {})
65
+ .get("sqlEndpointProperties", {})
66
+ .get("connectionString")
67
+ )
68
+
69
+ # Set up the connection string
52
70
  access_token = SynapseTokenProvider()()
53
71
  tokenstruct = bytes2mswin_bstr(access_token.encode())
54
- conn_str = f"DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={tds_endpoint};DATABASE={warehouse};Encrypt=Yes;"
72
+ conn_str = f"DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={tds_endpoint};DATABASE={name};Encrypt=Yes;"
55
73
 
56
74
  if timeout is not None:
57
75
  conn_str += f"Connect Timeout={timeout};"
@@ -59,29 +77,50 @@ class ConnectWarehouse:
59
77
  self.connection = pyodbc.connect(conn_str, attrs_before={1256: tokenstruct})
60
78
 
61
79
  @log
62
- def query(self, sql: str) -> pd.DataFrame:
80
+ def query(
81
+ self, sql: Union[str, List[str]]
82
+ ) -> Union[List[pd.DataFrame], pd.DataFrame, None]:
63
83
  """
64
- Runs a SQL query against a Fabric Warehouse.
84
+ Runs a SQL or T-SQL query (or multiple queries) against a Fabric Warehouse/Lakehouse.
65
85
 
66
86
  Parameters
67
87
  ----------
68
- sql : str
69
- The SQL query.
88
+ sql : str or List[str]
89
+ A single SQL or T-SQL query, or a list of queries to be executed.
70
90
 
71
91
  Returns
72
92
  -------
73
- pandas.DataFrame
74
- A pandas dataframe with the result of the SQL query.
93
+ Union[List[pandas.DataFrame], pandas.DataFrame, None]
94
+ A list of pandas DataFrames if multiple SQL queries return results,
95
+ a single DataFrame if one query is executed and returns results, or None.
75
96
  """
97
+
76
98
  cursor = None
99
+ results = []
100
+
101
+ if isinstance(sql, str):
102
+ sql = [sql]
77
103
 
78
104
  try:
79
105
  cursor = self.connection.cursor()
80
- cursor.execute(sql)
81
106
 
82
- return pd.DataFrame.from_records(
83
- cursor.fetchall(), columns=[col[0] for col in cursor.description]
84
- )
107
+ for sql_query in sql:
108
+ cursor.execute(sql_query)
109
+
110
+ # Commit for non-select queries (like CREATE, INSERT, etc.)
111
+ if not cursor.description:
112
+ self.connection.commit()
113
+ else:
114
+ # Fetch and append results for queries that return a result set
115
+ result = pd.DataFrame.from_records(
116
+ cursor.fetchall(),
117
+ columns=[col[0] for col in cursor.description],
118
+ )
119
+ results.append(result)
120
+
121
+ # Return results if any queries returned a result set
122
+ return results if len(results) > 1 else (results[0] if results else None)
123
+
85
124
  finally:
86
125
  if cursor:
87
126
  cursor.close()
@@ -94,3 +133,33 @@ class ConnectWarehouse:
94
133
 
95
134
  def close(self):
96
135
  self.connection.close()
136
+
137
+
138
+ class ConnectWarehouse(ConnectBase):
139
+ def __init__(
140
+ self,
141
+ warehouse: str,
142
+ workspace: Optional[Union[str, uuid.UUID]] = None,
143
+ timeout: Optional[int] = None,
144
+ ):
145
+ super().__init__(
146
+ name=warehouse,
147
+ workspace=workspace,
148
+ timeout=timeout,
149
+ endpoint_type="warehouse",
150
+ )
151
+
152
+
153
+ class ConnectLakehouse(ConnectBase):
154
+ def __init__(
155
+ self,
156
+ lakehouse: str,
157
+ workspace: Optional[Union[str, uuid.UUID]] = None,
158
+ timeout: Optional[int] = None,
159
+ ):
160
+ super().__init__(
161
+ name=lakehouse,
162
+ workspace=workspace,
163
+ timeout=timeout,
164
+ endpoint_type="lakehouse",
165
+ )
@@ -3,6 +3,7 @@ import pandas as pd
3
3
  from typing import List, Optional, Union
4
4
  from sempy._utils._log import log
5
5
  import sempy_labs._icons as icons
6
+ from sempy_labs._helper_functions import get_language_codes
6
7
 
7
8
 
8
9
  @log
@@ -48,6 +49,8 @@ def translate_semantic_model(
48
49
  if isinstance(languages, str):
49
50
  languages = [languages]
50
51
 
52
+ languages = get_language_codes(languages)
53
+
51
54
  df_prep = pd.DataFrame(
52
55
  columns=["Object Type", "Name", "Description", "Display Folder"]
53
56
  )