semantic-link-labs 0.10.0__py3-none-any.whl → 0.11.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.
- {semantic_link_labs-0.10.0.dist-info → semantic_link_labs-0.11.0.dist-info}/METADATA +9 -6
- {semantic_link_labs-0.10.0.dist-info → semantic_link_labs-0.11.0.dist-info}/RECORD +95 -87
- sempy_labs/__init__.py +11 -1
- sempy_labs/_a_lib_info.py +2 -0
- sempy_labs/_capacities.py +2 -0
- sempy_labs/_connections.py +11 -0
- sempy_labs/_dashboards.py +9 -4
- sempy_labs/_data_pipelines.py +5 -0
- sempy_labs/_dataflows.py +284 -17
- sempy_labs/_daxformatter.py +80 -0
- sempy_labs/_delta_analyzer_history.py +4 -1
- sempy_labs/_deployment_pipelines.py +4 -0
- sempy_labs/_documentation.py +3 -0
- sempy_labs/_environments.py +10 -1
- sempy_labs/_eventhouses.py +12 -5
- sempy_labs/_eventstreams.py +11 -3
- sempy_labs/_external_data_shares.py +8 -2
- sempy_labs/_gateways.py +26 -5
- sempy_labs/_git.py +11 -0
- sempy_labs/_graphQL.py +10 -3
- sempy_labs/_helper_functions.py +62 -10
- sempy_labs/_job_scheduler.py +54 -7
- sempy_labs/_kql_databases.py +11 -2
- sempy_labs/_kql_querysets.py +11 -3
- sempy_labs/_list_functions.py +17 -45
- sempy_labs/_managed_private_endpoints.py +11 -2
- sempy_labs/_mirrored_databases.py +17 -3
- sempy_labs/_mirrored_warehouses.py +9 -3
- sempy_labs/_ml_experiments.py +11 -3
- sempy_labs/_ml_models.py +11 -3
- sempy_labs/_model_bpa_rules.py +2 -0
- sempy_labs/_mounted_data_factories.py +12 -8
- sempy_labs/_notebooks.py +6 -3
- sempy_labs/_refresh_semantic_model.py +1 -0
- sempy_labs/_semantic_models.py +107 -0
- sempy_labs/_spark.py +7 -0
- sempy_labs/_sql_endpoints.py +208 -0
- sempy_labs/_sqldatabase.py +13 -4
- sempy_labs/_tags.py +5 -1
- sempy_labs/_user_delegation_key.py +2 -0
- sempy_labs/_variable_libraries.py +3 -1
- sempy_labs/_warehouses.py +13 -3
- sempy_labs/_workloads.py +3 -0
- sempy_labs/_workspace_identity.py +3 -0
- sempy_labs/_workspaces.py +14 -1
- sempy_labs/admin/__init__.py +2 -0
- sempy_labs/admin/_activities.py +6 -5
- sempy_labs/admin/_apps.py +31 -31
- sempy_labs/admin/_artifacts.py +8 -3
- sempy_labs/admin/_basic_functions.py +5 -0
- sempy_labs/admin/_capacities.py +39 -28
- sempy_labs/admin/_datasets.py +51 -51
- sempy_labs/admin/_domains.py +17 -1
- sempy_labs/admin/_external_data_share.py +8 -2
- sempy_labs/admin/_git.py +14 -9
- sempy_labs/admin/_items.py +15 -2
- sempy_labs/admin/_reports.py +64 -65
- sempy_labs/admin/_shared.py +7 -1
- sempy_labs/admin/_tags.py +5 -0
- sempy_labs/admin/_tenant.py +5 -2
- sempy_labs/admin/_users.py +9 -3
- sempy_labs/admin/_workspaces.py +88 -0
- sempy_labs/directlake/_dl_helper.py +2 -0
- sempy_labs/directlake/_generate_shared_expression.py +2 -0
- sempy_labs/directlake/_get_directlake_lakehouse.py +2 -4
- sempy_labs/directlake/_get_shared_expression.py +2 -0
- sempy_labs/directlake/_guardrails.py +2 -0
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +5 -3
- sempy_labs/directlake/_warm_cache.py +1 -0
- sempy_labs/graph/_groups.py +22 -7
- sempy_labs/graph/_teams.py +7 -2
- sempy_labs/graph/_users.py +1 -0
- sempy_labs/lakehouse/_blobs.py +1 -0
- sempy_labs/lakehouse/_get_lakehouse_tables.py +88 -27
- sempy_labs/lakehouse/_helper.py +2 -0
- sempy_labs/lakehouse/_lakehouse.py +38 -5
- sempy_labs/lakehouse/_livy_sessions.py +2 -1
- sempy_labs/lakehouse/_shortcuts.py +7 -1
- sempy_labs/migration/_direct_lake_to_import.py +2 -0
- sempy_labs/mirrored_azure_databricks_catalog/__init__.py +15 -0
- sempy_labs/mirrored_azure_databricks_catalog/_discover.py +213 -0
- sempy_labs/mirrored_azure_databricks_catalog/_refresh_catalog_metadata.py +45 -0
- sempy_labs/report/_download_report.py +2 -1
- sempy_labs/report/_generate_report.py +2 -0
- sempy_labs/report/_paginated.py +2 -0
- sempy_labs/report/_report_bpa.py +110 -122
- sempy_labs/report/_report_bpa_rules.py +2 -0
- sempy_labs/report/_report_functions.py +7 -0
- sempy_labs/report/_reportwrapper.py +86 -48
- sempy_labs/theme/__init__.py +12 -0
- sempy_labs/theme/_org_themes.py +96 -0
- sempy_labs/tom/_model.py +702 -35
- {semantic_link_labs-0.10.0.dist-info → semantic_link_labs-0.11.0.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.10.0.dist-info → semantic_link_labs-0.11.0.dist-info}/licenses/LICENSE +0 -0
- {semantic_link_labs-0.10.0.dist-info → semantic_link_labs-0.11.0.dist-info}/top_level.txt +0 -0
sempy_labs/_ml_models.py
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from typing import Optional
|
|
3
3
|
from sempy_labs._helper_functions import (
|
|
4
|
-
|
|
4
|
+
resolve_workspace_id,
|
|
5
5
|
_base_api,
|
|
6
6
|
delete_item,
|
|
7
7
|
_create_dataframe,
|
|
8
8
|
create_item,
|
|
9
9
|
)
|
|
10
10
|
from uuid import UUID
|
|
11
|
+
from sempy._utils._log import log
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
@log
|
|
13
15
|
def list_ml_models(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
14
16
|
"""
|
|
15
17
|
Shows the ML models within a workspace.
|
|
@@ -36,7 +38,7 @@ def list_ml_models(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
36
38
|
}
|
|
37
39
|
df = _create_dataframe(columns=columns)
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
40
42
|
|
|
41
43
|
responses = _base_api(
|
|
42
44
|
request=f"/v1/workspaces/{workspace_id}/mlModels",
|
|
@@ -44,6 +46,7 @@ def list_ml_models(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
44
46
|
uses_pagination=True,
|
|
45
47
|
)
|
|
46
48
|
|
|
49
|
+
dfs = []
|
|
47
50
|
for r in responses:
|
|
48
51
|
for v in r.get("value", []):
|
|
49
52
|
model_id = v.get("id")
|
|
@@ -55,11 +58,15 @@ def list_ml_models(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
55
58
|
"ML Model Id": model_id,
|
|
56
59
|
"Description": desc,
|
|
57
60
|
}
|
|
58
|
-
|
|
61
|
+
dfs.append(pd.DataFrame(new_data, index=[0]))
|
|
62
|
+
|
|
63
|
+
if dfs:
|
|
64
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
59
65
|
|
|
60
66
|
return df
|
|
61
67
|
|
|
62
68
|
|
|
69
|
+
@log
|
|
63
70
|
def create_ml_model(
|
|
64
71
|
name: str, description: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
65
72
|
):
|
|
@@ -83,6 +90,7 @@ def create_ml_model(
|
|
|
83
90
|
create_item(name=name, description=description, type="MLModel", workspace=workspace)
|
|
84
91
|
|
|
85
92
|
|
|
93
|
+
@log
|
|
86
94
|
def delete_ml_model(name: str | UUID, workspace: Optional[str | UUID] = None):
|
|
87
95
|
"""
|
|
88
96
|
Deletes a Fabric ML model.
|
sempy_labs/_model_bpa_rules.py
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
-
import json
|
|
3
2
|
from typing import Optional
|
|
4
3
|
from sempy_labs._helper_functions import (
|
|
5
|
-
|
|
4
|
+
resolve_workspace_id,
|
|
6
5
|
_base_api,
|
|
7
6
|
_create_dataframe,
|
|
8
7
|
_update_dataframe_datatypes,
|
|
9
|
-
resolve_item_id,
|
|
10
|
-
_decode_b64,
|
|
11
|
-
delete_item,
|
|
12
8
|
get_item_definition,
|
|
9
|
+
delete_item,
|
|
13
10
|
)
|
|
14
11
|
|
|
15
12
|
from uuid import UUID
|
|
13
|
+
from sempy._utils._log import log
|
|
16
14
|
|
|
17
15
|
|
|
16
|
+
@log
|
|
18
17
|
def list_mounted_data_factories(
|
|
19
18
|
workspace: Optional[str | UUID] = None,
|
|
20
19
|
) -> pd.DataFrame:
|
|
@@ -36,7 +35,7 @@ def list_mounted_data_factories(
|
|
|
36
35
|
A pandas dataframe showing a list of mounted data factories from the specified workspace.
|
|
37
36
|
"""
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
40
39
|
|
|
41
40
|
columns = {
|
|
42
41
|
"Mounted Data Factory Name": "str",
|
|
@@ -50,6 +49,7 @@ def list_mounted_data_factories(
|
|
|
50
49
|
uses_pagination=True,
|
|
51
50
|
)
|
|
52
51
|
|
|
52
|
+
dfs = []
|
|
53
53
|
for r in responses:
|
|
54
54
|
for v in r.get("value", []):
|
|
55
55
|
new_data = {
|
|
@@ -58,13 +58,16 @@ def list_mounted_data_factories(
|
|
|
58
58
|
"Description": v.get("description"),
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
dfs.append(pd.DataFrame(new_data, index=[0]))
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
if dfs:
|
|
64
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
65
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
64
66
|
|
|
65
67
|
return df
|
|
66
68
|
|
|
67
69
|
|
|
70
|
+
@log
|
|
68
71
|
def get_mounted_data_factory_definition(
|
|
69
72
|
mounted_data_factory: str | UUID, workspace: Optional[str | UUID] = None
|
|
70
73
|
) -> dict:
|
|
@@ -96,6 +99,7 @@ def get_mounted_data_factory_definition(
|
|
|
96
99
|
)
|
|
97
100
|
|
|
98
101
|
|
|
102
|
+
@log
|
|
99
103
|
def delete_mounted_data_factory(
|
|
100
104
|
mounted_data_factory: str | UUID, workspace: Optional[str | UUID]
|
|
101
105
|
):
|
sempy_labs/_notebooks.py
CHANGED
|
@@ -60,6 +60,7 @@ def _get_notebook_type(
|
|
|
60
60
|
return file_extension[1:]
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
@log
|
|
63
64
|
def get_notebook_definition(
|
|
64
65
|
notebook_name: str,
|
|
65
66
|
workspace: Optional[str | UUID] = None,
|
|
@@ -159,6 +160,7 @@ def import_notebook_from_web(
|
|
|
159
160
|
notebook_content=response.content,
|
|
160
161
|
workspace=workspace_id,
|
|
161
162
|
description=description,
|
|
163
|
+
format="ipynb",
|
|
162
164
|
)
|
|
163
165
|
elif len(dfI_filt) > 0 and overwrite:
|
|
164
166
|
print(f"{icons.info} Overwrite of notebooks is currently not supported.")
|
|
@@ -171,6 +173,7 @@ def import_notebook_from_web(
|
|
|
171
173
|
)
|
|
172
174
|
|
|
173
175
|
|
|
176
|
+
@log
|
|
174
177
|
def create_notebook(
|
|
175
178
|
name: str,
|
|
176
179
|
notebook_content: str,
|
|
@@ -202,9 +205,8 @@ def create_notebook(
|
|
|
202
205
|
otherwise notebook_content should be GIT friendly format
|
|
203
206
|
"""
|
|
204
207
|
|
|
205
|
-
notebook_payload = base64.b64encode(notebook_content.
|
|
206
|
-
|
|
207
|
-
)
|
|
208
|
+
notebook_payload = base64.b64encode(notebook_content).decode("utf-8")
|
|
209
|
+
|
|
208
210
|
definition_payload = {
|
|
209
211
|
"parts": [
|
|
210
212
|
{
|
|
@@ -227,6 +229,7 @@ def create_notebook(
|
|
|
227
229
|
)
|
|
228
230
|
|
|
229
231
|
|
|
232
|
+
@log
|
|
230
233
|
def update_notebook_definition(
|
|
231
234
|
name: str,
|
|
232
235
|
notebook_content: str,
|
sempy_labs/_semantic_models.py
CHANGED
|
@@ -8,11 +8,15 @@ from sempy_labs._helper_functions import (
|
|
|
8
8
|
resolve_workspace_name_and_id,
|
|
9
9
|
resolve_dataset_name_and_id,
|
|
10
10
|
delete_item,
|
|
11
|
+
resolve_dataset_id,
|
|
12
|
+
resolve_workspace_id,
|
|
11
13
|
)
|
|
12
14
|
import sempy_labs._icons as icons
|
|
13
15
|
import re
|
|
16
|
+
from sempy._utils._log import log
|
|
14
17
|
|
|
15
18
|
|
|
19
|
+
@log
|
|
16
20
|
def get_semantic_model_refresh_schedule(
|
|
17
21
|
dataset: str | UUID, workspace: Optional[str | UUID] = None
|
|
18
22
|
) -> pd.DataFrame:
|
|
@@ -70,6 +74,7 @@ def get_semantic_model_refresh_schedule(
|
|
|
70
74
|
return df
|
|
71
75
|
|
|
72
76
|
|
|
77
|
+
@log
|
|
73
78
|
def enable_semantic_model_scheduled_refresh(
|
|
74
79
|
dataset: str | UUID,
|
|
75
80
|
workspace: Optional[str | UUID] = None,
|
|
@@ -119,6 +124,7 @@ def enable_semantic_model_scheduled_refresh(
|
|
|
119
124
|
)
|
|
120
125
|
|
|
121
126
|
|
|
127
|
+
@log
|
|
122
128
|
def delete_semantic_model(dataset: str | UUID, workspace: Optional[str | UUID] = None):
|
|
123
129
|
"""
|
|
124
130
|
Deletes a semantic model.
|
|
@@ -138,6 +144,7 @@ def delete_semantic_model(dataset: str | UUID, workspace: Optional[str | UUID] =
|
|
|
138
144
|
delete_item(item=dataset, type="SemanticModel", workspace=workspace)
|
|
139
145
|
|
|
140
146
|
|
|
147
|
+
@log
|
|
141
148
|
def update_semantic_model_refresh_schedule(
|
|
142
149
|
dataset: str | UUID,
|
|
143
150
|
days: Optional[str | List[str]] = None,
|
|
@@ -227,3 +234,103 @@ def update_semantic_model_refresh_schedule(
|
|
|
227
234
|
print(
|
|
228
235
|
f"{icons.green_dot} Refresh schedule for the '{dataset_name}' within the '{workspace_name}' workspace has been updated."
|
|
229
236
|
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@log
|
|
240
|
+
def list_semantic_model_datasources(
|
|
241
|
+
dataset: str | UUID,
|
|
242
|
+
workspace: Optional[str | UUID] = None,
|
|
243
|
+
expand_details: bool = True,
|
|
244
|
+
) -> pd.DataFrame:
|
|
245
|
+
"""
|
|
246
|
+
Lists the data sources for the specified semantic model.
|
|
247
|
+
|
|
248
|
+
This is a wrapper function for the following API: `Datasets - Get Datasources In Group <https://learn.microsoft.com/rest/api/power-bi/datasets/get-datasources-in-group>`_.
|
|
249
|
+
|
|
250
|
+
Parameters
|
|
251
|
+
----------
|
|
252
|
+
dataset : str | uuid.UUID
|
|
253
|
+
Name or ID of the semantic model.
|
|
254
|
+
workspace : str | uuid.UUID, default=None
|
|
255
|
+
The workspace name or ID.
|
|
256
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
257
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
258
|
+
expand_details : bool, default=True
|
|
259
|
+
If True, expands the connection details for each data source.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
pandas.DataFrame
|
|
264
|
+
DataFrame containing the data sources for the specified semantic model.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
268
|
+
dataset_id = resolve_dataset_id(dataset, workspace_id)
|
|
269
|
+
|
|
270
|
+
if expand_details:
|
|
271
|
+
columns = {
|
|
272
|
+
"Datasource Type": "str",
|
|
273
|
+
"Connection Server": "str",
|
|
274
|
+
"Connection Database": "str",
|
|
275
|
+
"Connection Path": "str",
|
|
276
|
+
"Connection Account": "str",
|
|
277
|
+
"Connection Domain": "str",
|
|
278
|
+
"Connection Kind": "str",
|
|
279
|
+
"Connection Email Address": "str",
|
|
280
|
+
"Connection URL": "str",
|
|
281
|
+
"Connection Class Info": "str",
|
|
282
|
+
"Connection Login Server": "str",
|
|
283
|
+
"Datasource Id": "str",
|
|
284
|
+
"Gateway Id": "str",
|
|
285
|
+
}
|
|
286
|
+
else:
|
|
287
|
+
columns = {
|
|
288
|
+
"Datasource Type": "str",
|
|
289
|
+
"Connection Details": "str",
|
|
290
|
+
"Datasource Id": "str",
|
|
291
|
+
"Gateway Id": "str",
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
df = _create_dataframe(columns)
|
|
295
|
+
|
|
296
|
+
response = _base_api(
|
|
297
|
+
request=f"/v1.0/myorg/groups/{workspace_id}/datasets/{dataset_id}/datasources",
|
|
298
|
+
client="fabric_sp",
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
dfs = []
|
|
302
|
+
for item in response.json().get("value", []):
|
|
303
|
+
ds_type = item.get("datasourceType")
|
|
304
|
+
conn_details = item.get("connectionDetails", {})
|
|
305
|
+
ds_id = item.get("datasourceId")
|
|
306
|
+
gateway_id = item.get("gatewayId")
|
|
307
|
+
if expand_details:
|
|
308
|
+
new_data = {
|
|
309
|
+
"Datasource Type": ds_type,
|
|
310
|
+
"Connection Server": conn_details.get("server"),
|
|
311
|
+
"Connection Database": conn_details.get("database"),
|
|
312
|
+
"Connection Path": conn_details.get("path"),
|
|
313
|
+
"Connection Account": conn_details.get("account"),
|
|
314
|
+
"Connection Domain": conn_details.get("domain"),
|
|
315
|
+
"Connection Kind": conn_details.get("kind"),
|
|
316
|
+
"Connection Email Address": conn_details.get("emailAddress"),
|
|
317
|
+
"Connection URL": conn_details.get("url"),
|
|
318
|
+
"Connection Class Info": conn_details.get("classInfo"),
|
|
319
|
+
"Connection Login Server": conn_details.get("loginServer"),
|
|
320
|
+
"Datasource Id": ds_id,
|
|
321
|
+
"Gateway Id": gateway_id,
|
|
322
|
+
}
|
|
323
|
+
dfs.append(pd.DataFrame(new_data, index=[0]))
|
|
324
|
+
else:
|
|
325
|
+
new_data = {
|
|
326
|
+
"Datasource Type": ds_type,
|
|
327
|
+
"Connection Details": conn_details,
|
|
328
|
+
"Datasource Id": ds_id,
|
|
329
|
+
"Gateway Id": gateway_id,
|
|
330
|
+
}
|
|
331
|
+
dfs.append(pd.DataFrame([new_data]))
|
|
332
|
+
|
|
333
|
+
if dfs:
|
|
334
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
335
|
+
|
|
336
|
+
return df
|
sempy_labs/_spark.py
CHANGED
|
@@ -8,8 +8,10 @@ from sempy_labs._helper_functions import (
|
|
|
8
8
|
_create_dataframe,
|
|
9
9
|
)
|
|
10
10
|
from uuid import UUID
|
|
11
|
+
from sempy._utils._log import log
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
@log
|
|
13
15
|
def list_custom_pools(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
14
16
|
"""
|
|
15
17
|
Lists all `custom pools <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
|
|
@@ -73,6 +75,7 @@ def list_custom_pools(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
73
75
|
return df
|
|
74
76
|
|
|
75
77
|
|
|
78
|
+
@log
|
|
76
79
|
def create_custom_pool(
|
|
77
80
|
pool_name: str,
|
|
78
81
|
node_size: str,
|
|
@@ -145,6 +148,7 @@ def create_custom_pool(
|
|
|
145
148
|
)
|
|
146
149
|
|
|
147
150
|
|
|
151
|
+
@log
|
|
148
152
|
def update_custom_pool(
|
|
149
153
|
pool_name: str,
|
|
150
154
|
node_size: Optional[str] = None,
|
|
@@ -251,6 +255,7 @@ def update_custom_pool(
|
|
|
251
255
|
)
|
|
252
256
|
|
|
253
257
|
|
|
258
|
+
@log
|
|
254
259
|
def delete_custom_pool(pool_name: str, workspace: Optional[str | UUID] = None):
|
|
255
260
|
"""
|
|
256
261
|
Deletes a `custom pool <https://learn.microsoft.com/fabric/data-engineering/create-custom-spark-pools>`_ within a workspace.
|
|
@@ -286,6 +291,7 @@ def delete_custom_pool(pool_name: str, workspace: Optional[str | UUID] = None):
|
|
|
286
291
|
)
|
|
287
292
|
|
|
288
293
|
|
|
294
|
+
@log
|
|
289
295
|
def get_spark_settings(
|
|
290
296
|
workspace: Optional[str | UUID] = None, return_dataframe: bool = True
|
|
291
297
|
) -> pd.DataFrame | dict:
|
|
@@ -362,6 +368,7 @@ def get_spark_settings(
|
|
|
362
368
|
return response.json()
|
|
363
369
|
|
|
364
370
|
|
|
371
|
+
@log
|
|
365
372
|
def update_spark_settings(
|
|
366
373
|
automatic_log_enabled: Optional[bool] = None,
|
|
367
374
|
high_concurrency_enabled: Optional[bool] = None,
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from typing import Optional, Literal
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sempy_labs._helper_functions import (
|
|
5
|
+
_base_api,
|
|
6
|
+
_create_dataframe,
|
|
7
|
+
resolve_workspace_name_and_id,
|
|
8
|
+
resolve_item_name_and_id,
|
|
9
|
+
_update_dataframe_datatypes,
|
|
10
|
+
resolve_workspace_id,
|
|
11
|
+
)
|
|
12
|
+
import sempy_labs._icons as icons
|
|
13
|
+
from sempy._utils._log import log
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@log
|
|
17
|
+
def list_sql_endpoints(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
18
|
+
"""
|
|
19
|
+
Shows the SQL endpoints within a workspace.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
workspace : str | uuid.UUID, default=None
|
|
24
|
+
The Fabric workspace name or ID.
|
|
25
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
26
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
pandas.DataFrame
|
|
31
|
+
A pandas dataframe showing the SQL endpoints within a workspace.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
columns = {
|
|
35
|
+
"SQL Endpoint Id": "string",
|
|
36
|
+
"SQL Endpoint Name": "string",
|
|
37
|
+
"Description": "string",
|
|
38
|
+
}
|
|
39
|
+
df = _create_dataframe(columns=columns)
|
|
40
|
+
|
|
41
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
42
|
+
|
|
43
|
+
responses = _base_api(
|
|
44
|
+
request=f"/v1/workspaces/{workspace_id}/sqlEndpoints", uses_pagination=True
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
dfs = []
|
|
48
|
+
for r in responses:
|
|
49
|
+
for v in r.get("value", []):
|
|
50
|
+
|
|
51
|
+
new_data = {
|
|
52
|
+
"SQL Endpoint Id": v.get("id"),
|
|
53
|
+
"SQL Endpoint Name": v.get("displayName"),
|
|
54
|
+
"Description": v.get("description"),
|
|
55
|
+
}
|
|
56
|
+
dfs.append(pd.DataFrame(new_data, index=[0]))
|
|
57
|
+
|
|
58
|
+
if dfs:
|
|
59
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
60
|
+
|
|
61
|
+
return df
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@log
|
|
65
|
+
def refresh_sql_endpoint_metadata(
|
|
66
|
+
item: str | UUID,
|
|
67
|
+
type: Literal["Lakehouse", "MirroredDatabase"],
|
|
68
|
+
workspace: Optional[str | UUID] = None,
|
|
69
|
+
tables: dict[str, list[str]] = None,
|
|
70
|
+
) -> pd.DataFrame:
|
|
71
|
+
"""
|
|
72
|
+
Refreshes the metadata of a SQL endpoint.
|
|
73
|
+
|
|
74
|
+
This is a wrapper function for the following API: `Items - Refresh Sql Endpoint Metadata <https://learn.microsoft.com/rest/api/fabric/sqlendpoint/items/refresh-sql-endpoint-metadata>`_.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
item : str | uuid.UUID
|
|
79
|
+
The name or ID of the item (Lakehouse or MirroredDatabase).
|
|
80
|
+
type : Literal['Lakehouse', 'MirroredDatabase']
|
|
81
|
+
The type of the item. Must be 'Lakehouse' or 'MirroredDatabase'.
|
|
82
|
+
workspace : str | uuid.UUID, default=None
|
|
83
|
+
The Fabric workspace name or ID.
|
|
84
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
85
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
86
|
+
tables : dict[str, list[str]], default=None
|
|
87
|
+
A dictionary where the keys are schema names and the values are lists of table names.
|
|
88
|
+
If empty, all table metadata will be refreshed.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
{
|
|
92
|
+
"dbo": ["DimDate", "DimGeography"],
|
|
93
|
+
"sls": ["FactSales", "FactBudget"],
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
pandas.DataFrame
|
|
99
|
+
A pandas dataframe showing the status of the metadata refresh operation.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
103
|
+
|
|
104
|
+
(item_name, item_id) = resolve_item_name_and_id(
|
|
105
|
+
item=item, type=type, workspace=workspace
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if type == "Lakehouse":
|
|
109
|
+
response = _base_api(
|
|
110
|
+
request=f"/v1/workspaces/{workspace_id}/lakehouses/{item_id}",
|
|
111
|
+
client="fabric_sp",
|
|
112
|
+
)
|
|
113
|
+
sql_endpoint_id = (
|
|
114
|
+
response.json()
|
|
115
|
+
.get("properties", {})
|
|
116
|
+
.get("sqlEndpointProperties", {})
|
|
117
|
+
.get("id")
|
|
118
|
+
)
|
|
119
|
+
elif type == "MirroredDatabase":
|
|
120
|
+
response = _base_api(
|
|
121
|
+
request=f"/v1/workspaces/{workspace_id}/mirroredDatabases/{item_id}",
|
|
122
|
+
client="fabric_sp",
|
|
123
|
+
)
|
|
124
|
+
sql_endpoint_id = (
|
|
125
|
+
response.json()
|
|
126
|
+
.get("properties", {})
|
|
127
|
+
.get("sqlEndpointProperties", {})
|
|
128
|
+
.get("id")
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
raise ValueError("Invalid type. Must be 'Lakehouse' or 'MirroredDatabase'.")
|
|
132
|
+
|
|
133
|
+
payload = {}
|
|
134
|
+
if tables:
|
|
135
|
+
payload = {
|
|
136
|
+
"tableDefinitions": [
|
|
137
|
+
{"schema": schema, "tableNames": tables}
|
|
138
|
+
for schema, tables in tables.items()
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
result = _base_api(
|
|
143
|
+
request=f"v1/workspaces/{workspace_id}/sqlEndpoints/{sql_endpoint_id}/refreshMetadata?preview=true",
|
|
144
|
+
method="post",
|
|
145
|
+
status_codes=[200, 202],
|
|
146
|
+
lro_return_json=True,
|
|
147
|
+
payload=payload,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
columns = {
|
|
151
|
+
"Table Name": "string",
|
|
152
|
+
"Status": "string",
|
|
153
|
+
"Start Time": "datetime",
|
|
154
|
+
"End Time": "datetime",
|
|
155
|
+
"Last Successful Sync Time": "datetime",
|
|
156
|
+
"Error Code": "string",
|
|
157
|
+
"Error Message": "string",
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if result:
|
|
161
|
+
df = pd.json_normalize(result)
|
|
162
|
+
|
|
163
|
+
# Extract error code and message, set to None if no error
|
|
164
|
+
df["Error Code"] = df.get("error.errorCode", None)
|
|
165
|
+
df["Error Message"] = df.get("error.message", None)
|
|
166
|
+
|
|
167
|
+
# Friendly column renaming
|
|
168
|
+
df.rename(
|
|
169
|
+
columns={
|
|
170
|
+
"tableName": "Table Name",
|
|
171
|
+
"startDateTime": "Start Time",
|
|
172
|
+
"endDateTime": "End Time",
|
|
173
|
+
"status": "Status",
|
|
174
|
+
"lastSuccessfulSyncDateTime": "Last Successful Sync Time",
|
|
175
|
+
},
|
|
176
|
+
inplace=True,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Drop the original 'error' column if present
|
|
180
|
+
df.drop(columns=[col for col in ["error"] if col in df.columns], inplace=True)
|
|
181
|
+
|
|
182
|
+
# Optional: Reorder columns
|
|
183
|
+
column_order = [
|
|
184
|
+
"Table Name",
|
|
185
|
+
"Status",
|
|
186
|
+
"Start Time",
|
|
187
|
+
"End Time",
|
|
188
|
+
"Last Successful Sync Time",
|
|
189
|
+
"Error Code",
|
|
190
|
+
"Error Message",
|
|
191
|
+
]
|
|
192
|
+
df = df[column_order]
|
|
193
|
+
|
|
194
|
+
printout = f"{icons.green_dot} The metadata of the SQL endpoint for the '{item_name}' {type.lower()} within the '{workspace_name}' workspace has been refreshed"
|
|
195
|
+
if tables:
|
|
196
|
+
print(f"{printout} for the following tables: {tables}.")
|
|
197
|
+
else:
|
|
198
|
+
print(f"{printout} for all tables.")
|
|
199
|
+
else:
|
|
200
|
+
# If the target item has no tables to refresh the metadata for
|
|
201
|
+
df = pd.DataFrame(columns=columns.keys())
|
|
202
|
+
print(
|
|
203
|
+
f"{icons.yellow_dot} The SQL endpoint '{item_name}' {type.lower()} within the '{workspace_name}' workspace has no tables to refresh..."
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
_update_dataframe_datatypes(df, columns)
|
|
207
|
+
|
|
208
|
+
return df
|
sempy_labs/_sqldatabase.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from sempy_labs._helper_functions import (
|
|
2
|
-
|
|
2
|
+
resolve_workspace_id,
|
|
3
3
|
_base_api,
|
|
4
4
|
_create_dataframe,
|
|
5
5
|
_update_dataframe_datatypes,
|
|
@@ -9,8 +9,10 @@ from sempy_labs._helper_functions import (
|
|
|
9
9
|
import pandas as pd
|
|
10
10
|
from typing import Optional
|
|
11
11
|
from uuid import UUID
|
|
12
|
+
from sempy._utils._log import log
|
|
12
13
|
|
|
13
14
|
|
|
15
|
+
@log
|
|
14
16
|
def create_sql_database(
|
|
15
17
|
name: str, description: Optional[str] = None, workspace: Optional[str | UUID] = None
|
|
16
18
|
):
|
|
@@ -36,6 +38,7 @@ def create_sql_database(
|
|
|
36
38
|
)
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
@log
|
|
39
42
|
def delete_sql_database(
|
|
40
43
|
sql_database: str | UUID, workspace: Optional[str | UUID] = None
|
|
41
44
|
):
|
|
@@ -57,6 +60,7 @@ def delete_sql_database(
|
|
|
57
60
|
delete_item(item=sql_database, type="SQLDatabase", workspace=workspace)
|
|
58
61
|
|
|
59
62
|
|
|
63
|
+
@log
|
|
60
64
|
def list_sql_databases(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
61
65
|
"""
|
|
62
66
|
Lists all SQL databases in the Fabric workspace.
|
|
@@ -78,7 +82,7 @@ def list_sql_databases(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
78
82
|
A pandas dataframe showing a list of SQL databases in the Fabric workspace.
|
|
79
83
|
"""
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
82
86
|
|
|
83
87
|
columns = {
|
|
84
88
|
"SQL Database Name": "string",
|
|
@@ -96,6 +100,7 @@ def list_sql_databases(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
96
100
|
client="fabric_sp",
|
|
97
101
|
)
|
|
98
102
|
|
|
103
|
+
dfs = []
|
|
99
104
|
for r in responses:
|
|
100
105
|
for v in r.get("value", []):
|
|
101
106
|
prop = v.get("properties", {})
|
|
@@ -108,13 +113,16 @@ def list_sql_databases(workspace: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
108
113
|
"Server FQDN": prop.get("serverFqdn"),
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
|
|
116
|
+
dfs.append(pd.DataFrame(new_data, index=[0]))
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
if dfs:
|
|
119
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
120
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
114
121
|
|
|
115
122
|
return df
|
|
116
123
|
|
|
117
124
|
|
|
125
|
+
@log
|
|
118
126
|
def get_sql_database_tables(
|
|
119
127
|
sql_database: str | UUID, workspace: Optional[str | UUID] = None
|
|
120
128
|
) -> pd.DataFrame:
|
|
@@ -150,6 +158,7 @@ def get_sql_database_tables(
|
|
|
150
158
|
return df
|
|
151
159
|
|
|
152
160
|
|
|
161
|
+
@log
|
|
153
162
|
def get_sql_database_columns(
|
|
154
163
|
sql_database: str | UUID, workspace: Optional[str | UUID] = None
|
|
155
164
|
) -> pd.DataFrame:
|