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.
- {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/METADATA +19 -4
- {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/RECORD +75 -50
- {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +109 -31
- sempy_labs/_bpa_translation/{_translations_am-ET.po → _model/_translations_am-ET.po} +22 -0
- sempy_labs/_bpa_translation/{_translations_ar-AE.po → _model/_translations_ar-AE.po} +24 -0
- sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +938 -0
- sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +934 -0
- sempy_labs/_bpa_translation/{_translations_cs-CZ.po → _model/_translations_cs-CZ.po} +179 -157
- sempy_labs/_bpa_translation/{_translations_da-DK.po → _model/_translations_da-DK.po} +24 -0
- sempy_labs/_bpa_translation/{_translations_de-DE.po → _model/_translations_de-DE.po} +77 -52
- sempy_labs/_bpa_translation/{_translations_el-GR.po → _model/_translations_el-GR.po} +25 -0
- sempy_labs/_bpa_translation/{_translations_es-ES.po → _model/_translations_es-ES.po} +67 -43
- sempy_labs/_bpa_translation/{_translations_fa-IR.po → _model/_translations_fa-IR.po} +24 -0
- sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +915 -0
- sempy_labs/_bpa_translation/{_translations_fr-FR.po → _model/_translations_fr-FR.po} +83 -57
- sempy_labs/_bpa_translation/{_translations_ga-IE.po → _model/_translations_ga-IE.po} +25 -0
- sempy_labs/_bpa_translation/{_translations_he-IL.po → _model/_translations_he-IL.po} +23 -0
- sempy_labs/_bpa_translation/{_translations_hi-IN.po → _model/_translations_hi-IN.po} +24 -0
- sempy_labs/_bpa_translation/{_translations_hu-HU.po → _model/_translations_hu-HU.po} +25 -0
- sempy_labs/_bpa_translation/_model/_translations_id-ID.po +918 -0
- sempy_labs/_bpa_translation/{_translations_is-IS.po → _model/_translations_is-IS.po} +25 -0
- sempy_labs/_bpa_translation/{_translations_it-IT.po → _model/_translations_it-IT.po} +25 -0
- sempy_labs/_bpa_translation/{_translations_ja-JP.po → _model/_translations_ja-JP.po} +21 -0
- sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +823 -0
- sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +937 -0
- sempy_labs/_bpa_translation/{_translations_nl-NL.po → _model/_translations_nl-NL.po} +80 -56
- sempy_labs/_bpa_translation/{_translations_pl-PL.po → _model/_translations_pl-PL.po} +101 -76
- sempy_labs/_bpa_translation/{_translations_pt-BR.po → _model/_translations_pt-BR.po} +25 -0
- sempy_labs/_bpa_translation/{_translations_pt-PT.po → _model/_translations_pt-PT.po} +25 -0
- sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +939 -0
- sempy_labs/_bpa_translation/{_translations_ru-RU.po → _model/_translations_ru-RU.po} +25 -0
- sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +925 -0
- sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +922 -0
- sempy_labs/_bpa_translation/{_translations_ta-IN.po → _model/_translations_ta-IN.po} +26 -0
- sempy_labs/_bpa_translation/{_translations_te-IN.po → _model/_translations_te-IN.po} +24 -0
- sempy_labs/_bpa_translation/{_translations_th-TH.po → _model/_translations_th-TH.po} +24 -0
- sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +925 -0
- sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +933 -0
- sempy_labs/_bpa_translation/{_translations_zh-CN.po → _model/_translations_zh-CN.po} +116 -97
- sempy_labs/_bpa_translation/{_translations_zu-ZA.po → _model/_translations_zu-ZA.po} +25 -0
- sempy_labs/_capacities.py +577 -0
- sempy_labs/_capacity_migration.py +624 -0
- sempy_labs/_clear_cache.py +8 -8
- sempy_labs/_connections.py +140 -0
- sempy_labs/_environments.py +156 -0
- sempy_labs/_git.py +20 -21
- sempy_labs/_helper_functions.py +151 -10
- sempy_labs/_icons.py +62 -0
- sempy_labs/_list_functions.py +232 -887
- sempy_labs/_model_bpa.py +8 -32
- sempy_labs/_notebooks.py +143 -0
- sempy_labs/_query_scale_out.py +30 -8
- sempy_labs/_spark.py +460 -0
- sempy_labs/_sql.py +88 -19
- sempy_labs/_translations.py +3 -0
- sempy_labs/_vertipaq.py +162 -99
- sempy_labs/_workspaces.py +294 -0
- sempy_labs/admin/__init__.py +53 -0
- sempy_labs/admin/_basic_functions.py +806 -0
- sempy_labs/admin/_domains.py +411 -0
- sempy_labs/directlake/_directlake_schema_sync.py +1 -2
- sempy_labs/directlake/_generate_shared_expression.py +11 -14
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +14 -24
- sempy_labs/report/__init__.py +9 -6
- sempy_labs/report/_report_bpa.py +359 -0
- sempy_labs/report/_report_bpa_rules.py +113 -0
- sempy_labs/report/_report_helper.py +254 -0
- sempy_labs/report/_report_list_functions.py +95 -0
- sempy_labs/report/_report_rebind.py +0 -4
- sempy_labs/report/_reportwrapper.py +2039 -0
- sempy_labs/tom/_model.py +83 -5
- {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.7.3.dist-info → semantic_link_labs-0.8.0.dist-info}/top_level.txt +0 -0
- /sempy_labs/_bpa_translation/{_translations_sv-SE.po → _model/_translations_sv-SE.po} +0 -0
sempy_labs/_connections.py
CHANGED
|
@@ -1,6 +1,146 @@
|
|
|
1
1
|
import sempy.fabric as fabric
|
|
2
2
|
import pandas as pd
|
|
3
3
|
from sempy.fabric.exceptions import FabricHTTPException
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from sempy_labs._helper_functions import pagination
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def list_connections() -> pd.DataFrame:
|
|
9
|
+
"""
|
|
10
|
+
Lists all available connections.
|
|
11
|
+
|
|
12
|
+
Returns
|
|
13
|
+
-------
|
|
14
|
+
pandas.DataFrame
|
|
15
|
+
A pandas dataframe showing all available connections.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
client = fabric.FabricRestClient()
|
|
19
|
+
response = client.get("/v1/connections")
|
|
20
|
+
|
|
21
|
+
if response.status_code != 200:
|
|
22
|
+
raise FabricHTTPException(response)
|
|
23
|
+
|
|
24
|
+
df = pd.DataFrame(
|
|
25
|
+
columns=[
|
|
26
|
+
"Connection Id",
|
|
27
|
+
"Connection Name",
|
|
28
|
+
"Gateway Id",
|
|
29
|
+
"Connectivity Type",
|
|
30
|
+
"Connection Path",
|
|
31
|
+
"Connection Type",
|
|
32
|
+
"Privacy Level",
|
|
33
|
+
"Credential Type",
|
|
34
|
+
"Single Sign on Type",
|
|
35
|
+
"Connection Encyrption",
|
|
36
|
+
"Skip Test Connection",
|
|
37
|
+
]
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
for i in response.json().get("value", []):
|
|
41
|
+
connection_details = i.get("connectionDetails", {})
|
|
42
|
+
credential_details = i.get("credentialDetails", {})
|
|
43
|
+
|
|
44
|
+
new_data = {
|
|
45
|
+
"Connection Id": i.get("id"),
|
|
46
|
+
"Connection Name": i.get("displayName"),
|
|
47
|
+
"Gateway Id": i.get("gatewayId"),
|
|
48
|
+
"Connectivity Type": i.get("connectivityType"),
|
|
49
|
+
"Connection Path": connection_details.get("path"),
|
|
50
|
+
"Connection Type": connection_details.get("type"),
|
|
51
|
+
"Privacy Level": i.get("privacyLevel"),
|
|
52
|
+
"Credential Type": (
|
|
53
|
+
credential_details.get("credentialType") if credential_details else None
|
|
54
|
+
),
|
|
55
|
+
"Single Sign On Type": (
|
|
56
|
+
credential_details.get("singleSignOnType")
|
|
57
|
+
if credential_details
|
|
58
|
+
else None
|
|
59
|
+
),
|
|
60
|
+
"Connection Encryption": (
|
|
61
|
+
credential_details.get("connectionEncryption")
|
|
62
|
+
if credential_details
|
|
63
|
+
else None
|
|
64
|
+
),
|
|
65
|
+
"Skip Test Connection": (
|
|
66
|
+
credential_details.get("skipTestConnection")
|
|
67
|
+
if credential_details
|
|
68
|
+
else None
|
|
69
|
+
),
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
73
|
+
bool_cols = ["Skip Test Connection"]
|
|
74
|
+
df[bool_cols] = df[bool_cols].astype(bool)
|
|
75
|
+
|
|
76
|
+
return df
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def list_item_connections(
|
|
80
|
+
item_name: str, item_type: str, workspace: Optional[str] = None
|
|
81
|
+
) -> pd.DataFrame:
|
|
82
|
+
"""
|
|
83
|
+
Shows the list of connections that the specified item is connected to.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
item_name : str
|
|
88
|
+
The item name.
|
|
89
|
+
item_type : str
|
|
90
|
+
The `item type <https://learn.microsoft.com/rest/api/fabric/core/items/update-item?tabs=HTTP#itemtype>`_.
|
|
91
|
+
workspace : str, default=None
|
|
92
|
+
The Fabric workspace name.
|
|
93
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
94
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
pandas.DataFrame
|
|
99
|
+
A pandas dataframe showing the list of connections that the specified item is connected to.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/items/list-item-connections?tabs=HTTP
|
|
103
|
+
|
|
104
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
105
|
+
workspace_id = fabric.resolve_workspace_id(workspace)
|
|
106
|
+
item_type = item_type[0].upper() + item_type[1:]
|
|
107
|
+
item_id = fabric.resolve_item_id(
|
|
108
|
+
item_name=item_name, type=item_type, workspace=workspace
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
client = fabric.FabricRestClient()
|
|
112
|
+
response = client.post(f"/v1/workspaces/{workspace_id}/items/{item_id}/connections")
|
|
113
|
+
|
|
114
|
+
df = pd.DataFrame(
|
|
115
|
+
columns=[
|
|
116
|
+
"Connection Name",
|
|
117
|
+
"Connection Id",
|
|
118
|
+
"Connectivity Type",
|
|
119
|
+
"Connection Type",
|
|
120
|
+
"Connection Path",
|
|
121
|
+
"Gateway Id",
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if response.status_code != 200:
|
|
126
|
+
raise FabricHTTPException(response)
|
|
127
|
+
|
|
128
|
+
responses = pagination(client, response)
|
|
129
|
+
|
|
130
|
+
for r in responses:
|
|
131
|
+
for v in r.get("value", []):
|
|
132
|
+
new_data = {
|
|
133
|
+
"Connection Name": v.get("displayName"),
|
|
134
|
+
"Connection Id": v.get("id"),
|
|
135
|
+
"Connectivity Type": v.get("connectivityType"),
|
|
136
|
+
"Connection Type": v.get("connectionDetails", {}).get("type"),
|
|
137
|
+
"Connection Path": v.get("connectionDetails", {}).get("path"),
|
|
138
|
+
"Gateway Id": v.get("gatewayId"),
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
142
|
+
|
|
143
|
+
return df
|
|
4
144
|
|
|
5
145
|
|
|
6
146
|
def create_connection_cloud(
|
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
lro,
|
|
8
|
+
pagination,
|
|
9
|
+
)
|
|
10
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create_environment(
|
|
14
|
+
environment: str, description: Optional[str] = None, workspace: Optional[str] = None
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Creates a Fabric environment.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
environment: str
|
|
22
|
+
Name of the environment.
|
|
23
|
+
description : str, default=None
|
|
24
|
+
A description of the environment.
|
|
25
|
+
workspace : str, default=None
|
|
26
|
+
The Fabric workspace name.
|
|
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
|
+
|
|
31
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
32
|
+
|
|
33
|
+
request_body = {"displayName": environment}
|
|
34
|
+
|
|
35
|
+
if description:
|
|
36
|
+
request_body["description"] = description
|
|
37
|
+
|
|
38
|
+
client = fabric.FabricRestClient()
|
|
39
|
+
response = client.post(
|
|
40
|
+
f"/v1/workspaces/{workspace_id}/environments", json=request_body
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
lro(client, response, status_codes=[201, 202])
|
|
44
|
+
|
|
45
|
+
print(
|
|
46
|
+
f"{icons.green_dot} The '{environment}' environment has been created within the '{workspace}' workspace."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def list_environments(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
51
|
+
"""
|
|
52
|
+
Shows the environments within a workspace.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
workspace : str, default=None
|
|
57
|
+
The Fabric workspace name.
|
|
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
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
pandas.DataFrame
|
|
64
|
+
A pandas dataframe showing the environments within a workspace.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
df = pd.DataFrame(columns=["Environment Name", "Environment Id", "Description"])
|
|
68
|
+
|
|
69
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
70
|
+
|
|
71
|
+
client = fabric.FabricRestClient()
|
|
72
|
+
response = client.get(f"/v1/workspaces/{workspace_id}/environments")
|
|
73
|
+
if response.status_code != 200:
|
|
74
|
+
raise FabricHTTPException(response)
|
|
75
|
+
|
|
76
|
+
responses = pagination(client, response)
|
|
77
|
+
|
|
78
|
+
for r in responses:
|
|
79
|
+
for v in r.get("value", []):
|
|
80
|
+
new_data = {
|
|
81
|
+
"Environment Name": v.get("displayName"),
|
|
82
|
+
"Environment Id": v.get("id"),
|
|
83
|
+
"Description": v.get("description"),
|
|
84
|
+
}
|
|
85
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
86
|
+
|
|
87
|
+
return df
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def delete_environment(environment: str, workspace: Optional[str] = None):
|
|
91
|
+
"""
|
|
92
|
+
Deletes a Fabric environment.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
environment: str
|
|
97
|
+
Name of the environment.
|
|
98
|
+
workspace : str, default=None
|
|
99
|
+
The Fabric workspace name.
|
|
100
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
101
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
from sempy_labs._helper_functions import resolve_environment_id
|
|
105
|
+
|
|
106
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
107
|
+
environment_id = resolve_environment_id(
|
|
108
|
+
environment=environment, workspace=workspace
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
client = fabric.FabricRestClient()
|
|
112
|
+
response = client.delete(
|
|
113
|
+
f"/v1/workspaces/{workspace_id}/environments/{environment_id}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if response.status_code != 200:
|
|
117
|
+
raise FabricHTTPException(response)
|
|
118
|
+
|
|
119
|
+
print(
|
|
120
|
+
f"{icons.green_dot} The '{environment}' environment within the '{workspace}' workspace has been deleted."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def publish_environment(environment: str, workspace: Optional[str] = None):
|
|
125
|
+
"""
|
|
126
|
+
Publishes a Fabric environment.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
environment: str
|
|
131
|
+
Name of the environment.
|
|
132
|
+
workspace : str, default=None
|
|
133
|
+
The Fabric workspace name.
|
|
134
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
135
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/environment/spark-libraries/publish-environment?tabs=HTTP
|
|
139
|
+
|
|
140
|
+
from sempy_labs._helper_functions import resolve_environment_id
|
|
141
|
+
|
|
142
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
143
|
+
environment_id = resolve_environment_id(
|
|
144
|
+
environment=environment, workspace=workspace
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
client = fabric.FabricRestClient()
|
|
148
|
+
response = client.post(
|
|
149
|
+
f"/v1/workspaces/{workspace_id}/environments/{environment_id}/staging/publish"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
lro(client, response)
|
|
153
|
+
|
|
154
|
+
print(
|
|
155
|
+
f"{icons.green_dot} The '{environment}' environment within the '{workspace}' workspace has been published."
|
|
156
|
+
)
|
sempy_labs/_git.py
CHANGED
|
@@ -132,19 +132,18 @@ def get_git_status(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
132
132
|
client = fabric.FabricRestClient()
|
|
133
133
|
response = client.get(f"/v1/workspaces/{workspace_id}/git/status")
|
|
134
134
|
|
|
135
|
-
if response not in [200, 202]:
|
|
135
|
+
if response.status_code not in [200, 202]:
|
|
136
136
|
raise FabricHTTPException(response)
|
|
137
137
|
|
|
138
138
|
result = lro(client, response).json()
|
|
139
139
|
|
|
140
|
-
for
|
|
141
|
-
changes = v.get("changes", [])
|
|
140
|
+
for changes in result.get("changes", []):
|
|
142
141
|
item_metadata = changes.get("itemMetadata", {})
|
|
143
142
|
item_identifier = item_metadata.get("itemIdentifier", {})
|
|
144
143
|
|
|
145
144
|
new_data = {
|
|
146
|
-
"Workspace Head":
|
|
147
|
-
"Remote Commit Hash":
|
|
145
|
+
"Workspace Head": result.get("workspaceHead"),
|
|
146
|
+
"Remote Commit Hash": result.get("remoteCommitHash"),
|
|
148
147
|
"Object ID": item_identifier.get("objectId"),
|
|
149
148
|
"Logical ID": item_identifier.get("logicalId"),
|
|
150
149
|
"Item Type": item_metadata.get("itemType"),
|
|
@@ -199,21 +198,21 @@ def get_git_connection(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
199
198
|
if response.status_code != 200:
|
|
200
199
|
raise FabricHTTPException(response)
|
|
201
200
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
201
|
+
r = response.json()
|
|
202
|
+
provider_details = r.get("gitProviderDetails", {})
|
|
203
|
+
sync_details = r.get("gitSyncDetails", {})
|
|
204
|
+
new_data = {
|
|
205
|
+
"Organization Name": provider_details.get("organizationName"),
|
|
206
|
+
"Project Name": provider_details.get("projectName"),
|
|
207
|
+
"Git Provider Type": provider_details.get("gitProviderType"),
|
|
208
|
+
"Repository Name": provider_details.get("repositoryName"),
|
|
209
|
+
"Branch Name": provider_details.get("branchName"),
|
|
210
|
+
"Directory Name": provider_details.get("directoryName"),
|
|
211
|
+
"Workspace Head": sync_details.get("head"),
|
|
212
|
+
"Last Sync Time": sync_details.get("lastSyncTime"),
|
|
213
|
+
"Git Connection State": r.get("gitConnectionState"),
|
|
214
|
+
}
|
|
215
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
217
216
|
|
|
218
217
|
return df
|
|
219
218
|
|
|
@@ -237,7 +236,7 @@ def initialize_git_connection(workspace: Optional[str] = None):
|
|
|
237
236
|
client = fabric.FabricRestClient()
|
|
238
237
|
response = client.post(f"/v1/workspaces/{workspace_id}/git/initializeConnection")
|
|
239
238
|
|
|
240
|
-
if response not in [200, 202]:
|
|
239
|
+
if response.status_code not in [200, 202]:
|
|
241
240
|
raise FabricHTTPException(response)
|
|
242
241
|
|
|
243
242
|
lro(client, response)
|
sempy_labs/_helper_functions.py
CHANGED
|
@@ -2,15 +2,14 @@ import sempy.fabric as fabric
|
|
|
2
2
|
import re
|
|
3
3
|
import json
|
|
4
4
|
import base64
|
|
5
|
+
import time
|
|
6
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
5
7
|
import pandas as pd
|
|
6
8
|
from functools import wraps
|
|
7
9
|
import datetime
|
|
8
|
-
import time
|
|
9
|
-
from pyspark.sql import SparkSession
|
|
10
10
|
from typing import Optional, Tuple, List
|
|
11
11
|
from uuid import UUID
|
|
12
12
|
import sempy_labs._icons as icons
|
|
13
|
-
from sempy.fabric.exceptions import FabricHTTPException
|
|
14
13
|
import urllib.parse
|
|
15
14
|
from azure.core.credentials import TokenCredential, AccessToken
|
|
16
15
|
|
|
@@ -392,6 +391,7 @@ def save_as_delta_table(
|
|
|
392
391
|
delta_table_name: str,
|
|
393
392
|
write_mode: str,
|
|
394
393
|
merge_schema: Optional[bool] = False,
|
|
394
|
+
schema: Optional[dict] = None,
|
|
395
395
|
lakehouse: Optional[str] = None,
|
|
396
396
|
workspace: Optional[str] = None,
|
|
397
397
|
):
|
|
@@ -408,6 +408,8 @@ def save_as_delta_table(
|
|
|
408
408
|
The write mode for the save operation. Options: 'append', 'overwrite'.
|
|
409
409
|
merge_schema : bool, default=False
|
|
410
410
|
Merges the schemas of the dataframe to the delta table.
|
|
411
|
+
schema : dict, default=None
|
|
412
|
+
A dictionary showing the schema of the columns and their data types.
|
|
411
413
|
lakehouse : str, default=None
|
|
412
414
|
The Fabric lakehouse used by the Direct Lake semantic model.
|
|
413
415
|
Defaults to None which resolves to the lakehouse attached to the notebook.
|
|
@@ -415,13 +417,22 @@ def save_as_delta_table(
|
|
|
415
417
|
The Fabric workspace name.
|
|
416
418
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
417
419
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
418
|
-
|
|
419
|
-
Returns
|
|
420
|
-
-------
|
|
421
|
-
UUID
|
|
422
|
-
The ID of the Power BI report.
|
|
423
420
|
"""
|
|
424
421
|
|
|
422
|
+
from pyspark.sql import SparkSession
|
|
423
|
+
from pyspark.sql.types import (
|
|
424
|
+
StringType,
|
|
425
|
+
IntegerType,
|
|
426
|
+
FloatType,
|
|
427
|
+
DateType,
|
|
428
|
+
StructType,
|
|
429
|
+
StructField,
|
|
430
|
+
BooleanType,
|
|
431
|
+
LongType,
|
|
432
|
+
DoubleType,
|
|
433
|
+
TimestampType,
|
|
434
|
+
)
|
|
435
|
+
|
|
425
436
|
if workspace is None:
|
|
426
437
|
workspace_id = fabric.get_workspace_id()
|
|
427
438
|
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
@@ -450,9 +461,32 @@ def save_as_delta_table(
|
|
|
450
461
|
)
|
|
451
462
|
|
|
452
463
|
dataframe.columns = dataframe.columns.str.replace(" ", "_")
|
|
453
|
-
|
|
454
464
|
spark = SparkSession.builder.getOrCreate()
|
|
455
|
-
|
|
465
|
+
|
|
466
|
+
type_mapping = {
|
|
467
|
+
"string": StringType(),
|
|
468
|
+
"str": StringType(),
|
|
469
|
+
"integer": IntegerType(),
|
|
470
|
+
"int": IntegerType(),
|
|
471
|
+
"float": FloatType(),
|
|
472
|
+
"date": DateType(),
|
|
473
|
+
"bool": BooleanType(),
|
|
474
|
+
"boolean": BooleanType(),
|
|
475
|
+
"long": LongType(),
|
|
476
|
+
"double": DoubleType(),
|
|
477
|
+
"timestamp": TimestampType(),
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if schema is None:
|
|
481
|
+
spark_df = spark.createDataFrame(dataframe)
|
|
482
|
+
else:
|
|
483
|
+
schema_map = StructType(
|
|
484
|
+
[
|
|
485
|
+
StructField(column_name, type_mapping[data_type], True)
|
|
486
|
+
for column_name, data_type in schema.items()
|
|
487
|
+
]
|
|
488
|
+
)
|
|
489
|
+
spark_df = spark.createDataFrame(dataframe, schema_map)
|
|
456
490
|
|
|
457
491
|
filePath = create_abfss_path(
|
|
458
492
|
lakehouse_id=lakehouse_id,
|
|
@@ -781,6 +815,37 @@ def resolve_capacity_name(capacity_id: Optional[UUID] = None) -> str:
|
|
|
781
815
|
return dfC_filt["Display Name"].iloc[0]
|
|
782
816
|
|
|
783
817
|
|
|
818
|
+
def resolve_capacity_id(capacity_name: Optional[str] = None) -> UUID:
|
|
819
|
+
"""
|
|
820
|
+
Obtains the capacity Id for a given capacity name.
|
|
821
|
+
|
|
822
|
+
Parameters
|
|
823
|
+
----------
|
|
824
|
+
capacity_name : str, default=None
|
|
825
|
+
The capacity name.
|
|
826
|
+
Defaults to None which resolves to the capacity id of the workspace of the attached lakehouse
|
|
827
|
+
or if no lakehouse attached, resolves to the capacity name of the workspace of the notebook.
|
|
828
|
+
|
|
829
|
+
Returns
|
|
830
|
+
-------
|
|
831
|
+
UUID
|
|
832
|
+
The capacity Id.
|
|
833
|
+
"""
|
|
834
|
+
|
|
835
|
+
if capacity_name is None:
|
|
836
|
+
return get_capacity_id()
|
|
837
|
+
|
|
838
|
+
dfC = fabric.list_capacities()
|
|
839
|
+
dfC_filt = dfC[dfC["Display Name"] == capacity_name]
|
|
840
|
+
|
|
841
|
+
if len(dfC_filt) == 0:
|
|
842
|
+
raise ValueError(
|
|
843
|
+
f"{icons.red_dot} The '{capacity_name}' capacity does not exist."
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
return dfC_filt["Id"].iloc[0]
|
|
847
|
+
|
|
848
|
+
|
|
784
849
|
def retry(sleep_time: int, timeout_error_message: str):
|
|
785
850
|
def decorator(func):
|
|
786
851
|
@wraps(func)
|
|
@@ -883,6 +948,7 @@ class FabricTokenCredential(TokenCredential):
|
|
|
883
948
|
) -> AccessToken:
|
|
884
949
|
|
|
885
950
|
from notebookutils import mssparkutils
|
|
951
|
+
|
|
886
952
|
token = mssparkutils.credentials.getToken(scopes)
|
|
887
953
|
access_token = AccessToken(token, 0)
|
|
888
954
|
|
|
@@ -910,3 +976,78 @@ def resolve_warehouse_id(warehouse: str, workspace: Optional[str]):
|
|
|
910
976
|
)
|
|
911
977
|
|
|
912
978
|
return warehouse_id
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
def get_language_codes(languages: str | List[str]):
|
|
982
|
+
|
|
983
|
+
if isinstance(languages, str):
|
|
984
|
+
languages = [languages]
|
|
985
|
+
|
|
986
|
+
for i, lang in enumerate(languages):
|
|
987
|
+
for k, v in icons.language_map.items():
|
|
988
|
+
if v == lang.capitalize():
|
|
989
|
+
languages[i] = k
|
|
990
|
+
break
|
|
991
|
+
|
|
992
|
+
return languages
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
def get_azure_token_credentials(
|
|
996
|
+
key_vault_uri: str,
|
|
997
|
+
key_vault_tenant_id: str,
|
|
998
|
+
key_vault_client_id: str,
|
|
999
|
+
key_vault_client_secret: str,
|
|
1000
|
+
) -> Tuple[str, str, dict]:
|
|
1001
|
+
|
|
1002
|
+
from notebookutils import mssparkutils
|
|
1003
|
+
from azure.identity import ClientSecretCredential
|
|
1004
|
+
|
|
1005
|
+
tenant_id = mssparkutils.credentials.getSecret(key_vault_uri, key_vault_tenant_id)
|
|
1006
|
+
client_id = mssparkutils.credentials.getSecret(key_vault_uri, key_vault_client_id)
|
|
1007
|
+
client_secret = mssparkutils.credentials.getSecret(
|
|
1008
|
+
key_vault_uri, key_vault_client_secret
|
|
1009
|
+
)
|
|
1010
|
+
|
|
1011
|
+
credential = ClientSecretCredential(
|
|
1012
|
+
tenant_id=tenant_id, client_id=client_id, client_secret=client_secret
|
|
1013
|
+
)
|
|
1014
|
+
|
|
1015
|
+
token = credential.get_token("https://management.azure.com/.default").token
|
|
1016
|
+
|
|
1017
|
+
headers = {
|
|
1018
|
+
"Authorization": f"Bearer {token}",
|
|
1019
|
+
"Content-Type": "application/json",
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return token, credential, headers
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
def convert_to_alphanumeric_lowercase(input_string):
|
|
1026
|
+
|
|
1027
|
+
cleaned_string = re.sub(r"[^a-zA-Z0-9]", "", input_string)
|
|
1028
|
+
cleaned_string = cleaned_string.lower()
|
|
1029
|
+
|
|
1030
|
+
return cleaned_string
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
def resolve_environment_id(environment: str, workspace: Optional[str] = None) -> UUID:
|
|
1034
|
+
"""
|
|
1035
|
+
Obtains the environment Id for a given environment.
|
|
1036
|
+
|
|
1037
|
+
Parameters
|
|
1038
|
+
----------
|
|
1039
|
+
environment: str
|
|
1040
|
+
Name of the environment.
|
|
1041
|
+
"""
|
|
1042
|
+
from sempy_labs._environments import list_environments
|
|
1043
|
+
|
|
1044
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
1045
|
+
|
|
1046
|
+
dfE = list_environments(workspace=workspace)
|
|
1047
|
+
dfE_filt = dfE[dfE["Environment Name"] == environment]
|
|
1048
|
+
if len(dfE_filt) == 0:
|
|
1049
|
+
raise ValueError(
|
|
1050
|
+
f"{icons.red_dot} The '{environment}' environment does not exist within the '{workspace}' workspace."
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1053
|
+
return dfE_filt["Environment Id"].iloc[0]
|
sempy_labs/_icons.py
CHANGED
|
@@ -31,3 +31,65 @@ model_bpa_name = "ModelBPA"
|
|
|
31
31
|
report_bpa_name = "ReportBPA"
|
|
32
32
|
severity_mapping = {warning: "Warning", error: "Error", info: "Info"}
|
|
33
33
|
special_characters = ['"', "/", '"', ":", "|", "<", ">", "*", "?", "'", "!"]
|
|
34
|
+
|
|
35
|
+
language_map = {
|
|
36
|
+
"it-IT": "Italian",
|
|
37
|
+
"es-ES": "Spanish",
|
|
38
|
+
"he-IL": "Hebrew",
|
|
39
|
+
"pt-PT": "Portuguese",
|
|
40
|
+
"zh-CN": "Chinese",
|
|
41
|
+
"fr-FR": "French",
|
|
42
|
+
"da-DK": "Danish",
|
|
43
|
+
"cs-CZ": "Czech",
|
|
44
|
+
"de-DE": "German",
|
|
45
|
+
"el-GR": "Greek",
|
|
46
|
+
"fa-IR": "Persian",
|
|
47
|
+
"ga-IE": "Irish",
|
|
48
|
+
"hi-IN": "Hindi",
|
|
49
|
+
"hu-HU": "Hungarian",
|
|
50
|
+
"is-IS": "Icelandic",
|
|
51
|
+
"ja-JP": "Japanese",
|
|
52
|
+
"nl-NL": "Dutch",
|
|
53
|
+
"pl-PL": "Polish",
|
|
54
|
+
"pt-BR": "Portuguese",
|
|
55
|
+
"ru-RU": "Russian",
|
|
56
|
+
"te-IN": "Telugu",
|
|
57
|
+
"ta-IN": "Tamil",
|
|
58
|
+
"th-TH": "Thai",
|
|
59
|
+
"zu-ZA": "Zulu",
|
|
60
|
+
"am-ET": "Amharic",
|
|
61
|
+
"ar-AE": "Arabic",
|
|
62
|
+
"sv-SE": "Swedish",
|
|
63
|
+
"ko-KR": "Korean",
|
|
64
|
+
"id-ID": "Indonesian",
|
|
65
|
+
"mt-MT": "Maltese",
|
|
66
|
+
"ro-RO": "Romanian",
|
|
67
|
+
"sk-SK": "Slovak",
|
|
68
|
+
"sl-SL": "Slovenian",
|
|
69
|
+
"tr-TR": "Turkish",
|
|
70
|
+
"uk-UA": "Ukrainian",
|
|
71
|
+
"bg-BG": "Bulgarian",
|
|
72
|
+
"ca-ES": "Catalan",
|
|
73
|
+
"fi-FI": "Finnish",
|
|
74
|
+
}
|
|
75
|
+
workspace_roles = ["Admin", "Member", "Viewer", "Contributor"]
|
|
76
|
+
principal_types = ["App", "Group", "None", "User"]
|
|
77
|
+
azure_api_version = "2023-11-01"
|
|
78
|
+
migrate_capacity_suffix = "fsku"
|
|
79
|
+
sku_mapping = {
|
|
80
|
+
"A1": "F8",
|
|
81
|
+
"EM1": "F8",
|
|
82
|
+
"A2": "F16",
|
|
83
|
+
"EM2": "F16",
|
|
84
|
+
"A3": "F32",
|
|
85
|
+
"EM3": "F32",
|
|
86
|
+
"A4": "F64",
|
|
87
|
+
"P1": "F64",
|
|
88
|
+
"A5": "F128",
|
|
89
|
+
"P2": "F128",
|
|
90
|
+
"A6": "F256",
|
|
91
|
+
"P3": "F256",
|
|
92
|
+
"A7": "F512",
|
|
93
|
+
"P4": "F512",
|
|
94
|
+
"P5": "F1024",
|
|
95
|
+
}
|