semantic-link-labs 0.7.2__py3-none-any.whl → 0.7.4__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.2.dist-info → semantic_link_labs-0.7.4.dist-info}/METADATA +15 -3
- semantic_link_labs-0.7.4.dist-info/RECORD +134 -0
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.4.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +120 -24
- 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/_model/_translations_sv-SE.po +914 -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 +541 -0
- sempy_labs/_clear_cache.py +298 -3
- sempy_labs/_connections.py +138 -0
- sempy_labs/_dataflows.py +130 -0
- sempy_labs/_deployment_pipelines.py +171 -0
- sempy_labs/_environments.py +156 -0
- sempy_labs/_generate_semantic_model.py +148 -27
- sempy_labs/_git.py +380 -0
- sempy_labs/_helper_functions.py +203 -8
- sempy_labs/_icons.py +43 -0
- sempy_labs/_list_functions.py +170 -1012
- sempy_labs/_model_bpa.py +90 -112
- sempy_labs/_model_bpa_bulk.py +3 -1
- sempy_labs/_model_bpa_rules.py +788 -800
- sempy_labs/_notebooks.py +143 -0
- sempy_labs/_query_scale_out.py +28 -7
- sempy_labs/_spark.py +465 -0
- sempy_labs/_sql.py +120 -0
- sempy_labs/_translations.py +3 -1
- sempy_labs/_vertipaq.py +160 -99
- sempy_labs/_workspace_identity.py +66 -0
- sempy_labs/_workspaces.py +294 -0
- sempy_labs/directlake/__init__.py +2 -0
- sempy_labs/directlake/_directlake_schema_compare.py +1 -2
- sempy_labs/directlake/_directlake_schema_sync.py +1 -2
- sempy_labs/directlake/_dl_helper.py +4 -7
- sempy_labs/directlake/_generate_shared_expression.py +85 -0
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +1 -2
- sempy_labs/lakehouse/_get_lakehouse_tables.py +7 -3
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +5 -0
- sempy_labs/migration/_migrate_calctables_to_semantic_model.py +5 -0
- sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +6 -2
- sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +6 -5
- sempy_labs/migration/_migration_validation.py +6 -0
- sempy_labs/report/_report_functions.py +21 -42
- sempy_labs/report/_report_rebind.py +5 -0
- sempy_labs/tom/_model.py +95 -52
- semantic_link_labs-0.7.2.dist-info/RECORD +0 -111
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.4.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.4.dist-info}/top_level.txt +0 -0
sempy_labs/_git.py
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import sempy.fabric as fabric
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import sempy_labs._icons as icons
|
|
4
|
+
from typing import Optional, List
|
|
5
|
+
from sempy_labs._helper_functions import (
|
|
6
|
+
resolve_workspace_name_and_id,
|
|
7
|
+
lro,
|
|
8
|
+
)
|
|
9
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def connect_workspace_to_git(
|
|
13
|
+
organization_name: str,
|
|
14
|
+
project_name: str,
|
|
15
|
+
repository_name: str,
|
|
16
|
+
branch_name: str,
|
|
17
|
+
directory_name: str,
|
|
18
|
+
git_provider_type: str = "AzureDevOps",
|
|
19
|
+
workspace: Optional[str] = None,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Connects a workspace to a git repository.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
organization_name : str
|
|
27
|
+
The organization name.
|
|
28
|
+
project_name : str
|
|
29
|
+
The project name.
|
|
30
|
+
repository_name : str
|
|
31
|
+
The repository name.
|
|
32
|
+
branch_name : str
|
|
33
|
+
The branch name.
|
|
34
|
+
directory_name : str
|
|
35
|
+
The directory name.
|
|
36
|
+
git_provider_type : str, default="AzureDevOps"
|
|
37
|
+
A `Git provider type <https://learn.microsoft.com/rest/api/fabric/core/git/connect?tabs=HTTP#gitprovidertype>`_.
|
|
38
|
+
workspace : str, default=None
|
|
39
|
+
The Fabric workspace name.
|
|
40
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
41
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/connect?tabs=HTTP
|
|
45
|
+
|
|
46
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
47
|
+
|
|
48
|
+
request_body = {
|
|
49
|
+
"gitProviderDetails": {
|
|
50
|
+
"organizationName": organization_name,
|
|
51
|
+
"projectName": project_name,
|
|
52
|
+
"gitProviderType": git_provider_type,
|
|
53
|
+
"repositoryName": repository_name,
|
|
54
|
+
"branchName": branch_name,
|
|
55
|
+
"directoryName": directory_name,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
client = fabric.FabricRestClient()
|
|
60
|
+
response = client.post(
|
|
61
|
+
f"/v1/workspaces/{workspace_id}/git/connect", json=request_body
|
|
62
|
+
)
|
|
63
|
+
if response.status_code != 200:
|
|
64
|
+
raise FabricHTTPException(response)
|
|
65
|
+
|
|
66
|
+
print(
|
|
67
|
+
f"{icons.green_dot} The '{workspace}' workspace has been connected to the '{project_name}' Git project within the '{repository_name}' repository."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def disconnect_workspace_from_git(workspace: Optional[str] = None):
|
|
72
|
+
"""
|
|
73
|
+
Disconnects a workpsace from a git repository.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
workspace : str, default=None
|
|
78
|
+
The Fabric workspace name.
|
|
79
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
80
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/disconnect?tabs=HTTP
|
|
84
|
+
|
|
85
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
86
|
+
|
|
87
|
+
client = fabric.FabricRestClient()
|
|
88
|
+
response = client.post(f"/v1/workspaces/{workspace_id}/git/disconnect")
|
|
89
|
+
if response.status_code != 200:
|
|
90
|
+
raise FabricHTTPException(response)
|
|
91
|
+
|
|
92
|
+
print(
|
|
93
|
+
f"{icons.green_dot} The '{workspace}' workspace has been disconnected from Git."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_git_status(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
98
|
+
"""
|
|
99
|
+
Obtains the Git status of items in the workspace, that can be committed to Git.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
workspace : str, default=None
|
|
104
|
+
The Fabric workspace name.
|
|
105
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
106
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
pandas.DataFrame
|
|
111
|
+
A pandas dataframe showing the Git status of items in the workspace.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/get-status?tabs=HTTP
|
|
115
|
+
|
|
116
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
117
|
+
|
|
118
|
+
df = pd.DataFrame(
|
|
119
|
+
columns=[
|
|
120
|
+
"Workspace Head",
|
|
121
|
+
"Remote Commit Hash",
|
|
122
|
+
"Object ID",
|
|
123
|
+
"Logical ID",
|
|
124
|
+
"Item Type",
|
|
125
|
+
"Item Name",
|
|
126
|
+
"Workspace Change",
|
|
127
|
+
"Remote Change",
|
|
128
|
+
"Conflict Type",
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
client = fabric.FabricRestClient()
|
|
133
|
+
response = client.get(f"/v1/workspaces/{workspace_id}/git/status")
|
|
134
|
+
|
|
135
|
+
if response not in [200, 202]:
|
|
136
|
+
raise FabricHTTPException(response)
|
|
137
|
+
|
|
138
|
+
result = lro(client, response).json()
|
|
139
|
+
|
|
140
|
+
for v in result.get("value", []):
|
|
141
|
+
changes = v.get("changes", [])
|
|
142
|
+
item_metadata = changes.get("itemMetadata", {})
|
|
143
|
+
item_identifier = item_metadata.get("itemIdentifier", {})
|
|
144
|
+
|
|
145
|
+
new_data = {
|
|
146
|
+
"Workspace Head": v.get("workspaceHead"),
|
|
147
|
+
"Remote Commit Hash": v.get("remoteCommitHash"),
|
|
148
|
+
"Object ID": item_identifier.get("objectId"),
|
|
149
|
+
"Logical ID": item_identifier.get("logicalId"),
|
|
150
|
+
"Item Type": item_metadata.get("itemType"),
|
|
151
|
+
"Item Name": item_metadata.get("displayName"),
|
|
152
|
+
"Remote Change": changes.get("remoteChange"),
|
|
153
|
+
"Workspace Change": changes.get("workspaceChange"),
|
|
154
|
+
"Conflict Type": changes.get("conflictType"),
|
|
155
|
+
}
|
|
156
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
157
|
+
|
|
158
|
+
return df
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def get_git_connection(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
162
|
+
"""
|
|
163
|
+
Obtains the Git status of items in the workspace, that can be committed to Git.
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
workspace : str, default=None
|
|
168
|
+
The Fabric workspace name.
|
|
169
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
170
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
pandas.DataFrame
|
|
175
|
+
A pandas dataframe showing the Git status of items in the workspace.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/get-status?tabs=HTTP
|
|
179
|
+
|
|
180
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
181
|
+
|
|
182
|
+
df = pd.DataFrame(
|
|
183
|
+
columns=[
|
|
184
|
+
"Organization Name",
|
|
185
|
+
"Project Name",
|
|
186
|
+
"Git Provider Type",
|
|
187
|
+
"Repository Name",
|
|
188
|
+
"Branch Name",
|
|
189
|
+
"Directory Name",
|
|
190
|
+
"Workspace Head",
|
|
191
|
+
"Last Sync Time",
|
|
192
|
+
"Git Connection State",
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
client = fabric.FabricRestClient()
|
|
197
|
+
response = client.get(f"/v1/workspaces/{workspace_id}/git/connection")
|
|
198
|
+
|
|
199
|
+
if response.status_code != 200:
|
|
200
|
+
raise FabricHTTPException(response)
|
|
201
|
+
|
|
202
|
+
for v in response.json().get("value", []):
|
|
203
|
+
provider_details = v.get("gitProviderDetails", {})
|
|
204
|
+
sync_details = v.get("gitSyncDetails", {})
|
|
205
|
+
new_data = {
|
|
206
|
+
"Organization Name": provider_details.get("organizationName"),
|
|
207
|
+
"Project Name": provider_details.get("projectName"),
|
|
208
|
+
"Git Provider Type": provider_details.get("gitProviderType"),
|
|
209
|
+
"Repository Name": provider_details.get("repositoryName"),
|
|
210
|
+
"Branch Name": provider_details.get("branchName"),
|
|
211
|
+
"Directory Name": provider_details.get("directoryName"),
|
|
212
|
+
"Workspace Head": sync_details.get("head"),
|
|
213
|
+
"Last Sync Time": sync_details.get("lastSyncTime"),
|
|
214
|
+
"Git Conneciton State": v.get("gitConnectionState"),
|
|
215
|
+
}
|
|
216
|
+
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
217
|
+
|
|
218
|
+
return df
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def initialize_git_connection(workspace: Optional[str] = None):
|
|
222
|
+
"""
|
|
223
|
+
Initializes a connection for a workspace that is connected to Git.
|
|
224
|
+
|
|
225
|
+
Parameters
|
|
226
|
+
----------
|
|
227
|
+
workspace : str, default=None
|
|
228
|
+
The Fabric workspace name.
|
|
229
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
230
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/initialize-connection?tabs=HTTP
|
|
234
|
+
|
|
235
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
236
|
+
|
|
237
|
+
client = fabric.FabricRestClient()
|
|
238
|
+
response = client.post(f"/v1/workspaces/{workspace_id}/git/initializeConnection")
|
|
239
|
+
|
|
240
|
+
if response not in [200, 202]:
|
|
241
|
+
raise FabricHTTPException(response)
|
|
242
|
+
|
|
243
|
+
lro(client, response)
|
|
244
|
+
|
|
245
|
+
print(
|
|
246
|
+
f"{icons.green_dot} The '{workspace}' workspace git connection has been initialized."
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def commit_to_git(
|
|
251
|
+
comment: str, item_ids: str | List[str] = None, workspace: Optional[str] = None
|
|
252
|
+
):
|
|
253
|
+
"""
|
|
254
|
+
Commits all or a selection of items within a workspace to Git.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
comment : str
|
|
259
|
+
The Git commit comment.
|
|
260
|
+
item_ids : str | List[str], default=None
|
|
261
|
+
A list of item Ids to commit to Git.
|
|
262
|
+
Defaults to None which commits all items to Git.
|
|
263
|
+
workspace : str, default=None
|
|
264
|
+
The Fabric workspace name.
|
|
265
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
266
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/commit-to-git?tabs=HTTP
|
|
270
|
+
|
|
271
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
272
|
+
|
|
273
|
+
gs = get_git_status(workspace=workspace)
|
|
274
|
+
workspace_head = gs["Workspace Head"].iloc[0]
|
|
275
|
+
|
|
276
|
+
if item_ids is None:
|
|
277
|
+
commit_mode = "All"
|
|
278
|
+
else:
|
|
279
|
+
commit_mode = "Selective"
|
|
280
|
+
|
|
281
|
+
if isinstance(item_ids, str):
|
|
282
|
+
item_ids = [item_ids]
|
|
283
|
+
|
|
284
|
+
request_body = {
|
|
285
|
+
"mode": commit_mode,
|
|
286
|
+
"workspaceHead": workspace_head,
|
|
287
|
+
"comment": comment,
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if item_ids is not None:
|
|
291
|
+
request_body["items"] = [{"objectId": item_id} for item_id in item_ids]
|
|
292
|
+
|
|
293
|
+
client = fabric.FabricRestClient()
|
|
294
|
+
response = client.post(
|
|
295
|
+
f"/v1/workspaces/{workspace_id}/git/commitToGit",
|
|
296
|
+
json=request_body,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
if response.status_code not in [200, 202]:
|
|
300
|
+
raise FabricHTTPException(response)
|
|
301
|
+
|
|
302
|
+
lro(client, response)
|
|
303
|
+
|
|
304
|
+
if commit_mode == "All":
|
|
305
|
+
print(
|
|
306
|
+
f"{icons.green_dot} All items within the '{workspace}' workspace have been committed to Git."
|
|
307
|
+
)
|
|
308
|
+
else:
|
|
309
|
+
print(
|
|
310
|
+
f"{icons.green_dot} The {item_ids} items ithin the '{workspace}' workspace have been committed to Git."
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def update_from_git(
|
|
315
|
+
remote_commit_hash: str,
|
|
316
|
+
conflict_resolution_policy: str,
|
|
317
|
+
workspace_head: Optional[str] = None,
|
|
318
|
+
allow_override: Optional[bool] = False,
|
|
319
|
+
workspace: Optional[str] = None,
|
|
320
|
+
):
|
|
321
|
+
"""
|
|
322
|
+
Updates the workspace with commits pushed to the connected branch.
|
|
323
|
+
|
|
324
|
+
Parameters
|
|
325
|
+
----------
|
|
326
|
+
workspace_head : str
|
|
327
|
+
Full SHA hash that the workspace is synced to. This value may be null only after Initialize Connection.
|
|
328
|
+
In other cases, the system will validate that the given value is aligned with the head known to the system.
|
|
329
|
+
remove_commit_hash : str
|
|
330
|
+
Remote full SHA commit hash.
|
|
331
|
+
confilict_resolution_policy : str
|
|
332
|
+
The `conflict resolution policy <https://learn.microsoft.com/rest/api/fabric/core/git/update-from-git?tabs=HTTP#conflictresolutionpolicy>`_.
|
|
333
|
+
allow_override : bool, default=False
|
|
334
|
+
workspace : str, default=None
|
|
335
|
+
The Fabric workspace name.
|
|
336
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
337
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
# https://learn.microsoft.com/en-us/rest/api/fabric/core/git/update-from-git?tabs=HTTP
|
|
341
|
+
|
|
342
|
+
workspace, workspace_id = resolve_workspace_name_and_id(workspace)
|
|
343
|
+
|
|
344
|
+
conflict_resolution_policies = ["PreferWorkspace", "PreferRemote"]
|
|
345
|
+
if "remote" in conflict_resolution_policies.lower():
|
|
346
|
+
conflict_resolution_policies = "PreferRemote"
|
|
347
|
+
elif "workspace" in conflict_resolution_policies.lower():
|
|
348
|
+
conflict_resolution_policies = "PreferWorkspace"
|
|
349
|
+
|
|
350
|
+
if conflict_resolution_policy not in conflict_resolution_policies:
|
|
351
|
+
raise ValueError(
|
|
352
|
+
f"{icons.red_dot} Invalid conflict resolution policy. Valid options: {conflict_resolution_policies}."
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
request_body = {}
|
|
356
|
+
request_body["remoteCommitHash"] = remote_commit_hash
|
|
357
|
+
request_body["conflictResolution"] = {
|
|
358
|
+
"conflictResolutionType": "Workspace",
|
|
359
|
+
"conflictResolutionPolicy": conflict_resolution_policy,
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if workspace_head is not None:
|
|
363
|
+
request_body["workspaceHead"] = workspace_head
|
|
364
|
+
if allow_override is not None:
|
|
365
|
+
request_body["options"] = {"allowOverrideItems": allow_override}
|
|
366
|
+
|
|
367
|
+
client = fabric.FabricRestClient()
|
|
368
|
+
response = client.post(
|
|
369
|
+
f"/v1/workspaces/{workspace_id}/git/updateFromGit",
|
|
370
|
+
json=request_body,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
if response.status_code not in [200, 202]:
|
|
374
|
+
raise FabricHTTPException(response)
|
|
375
|
+
|
|
376
|
+
lro(client, response)
|
|
377
|
+
|
|
378
|
+
print(
|
|
379
|
+
f"{icons.green_dot} The '{workspace}' workspace has been updated with commits pushed to the connected branch."
|
|
380
|
+
)
|
sempy_labs/_helper_functions.py
CHANGED
|
@@ -6,12 +6,12 @@ import pandas as pd
|
|
|
6
6
|
from functools import wraps
|
|
7
7
|
import datetime
|
|
8
8
|
import time
|
|
9
|
-
from pyspark.sql import SparkSession
|
|
10
9
|
from typing import Optional, Tuple, List
|
|
11
10
|
from uuid import UUID
|
|
12
11
|
import sempy_labs._icons as icons
|
|
13
12
|
from sempy.fabric.exceptions import FabricHTTPException
|
|
14
13
|
import urllib.parse
|
|
14
|
+
from azure.core.credentials import TokenCredential, AccessToken
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def create_abfss_path(
|
|
@@ -391,6 +391,7 @@ def save_as_delta_table(
|
|
|
391
391
|
delta_table_name: str,
|
|
392
392
|
write_mode: str,
|
|
393
393
|
merge_schema: Optional[bool] = False,
|
|
394
|
+
schema: Optional[dict] = None,
|
|
394
395
|
lakehouse: Optional[str] = None,
|
|
395
396
|
workspace: Optional[str] = None,
|
|
396
397
|
):
|
|
@@ -407,6 +408,8 @@ def save_as_delta_table(
|
|
|
407
408
|
The write mode for the save operation. Options: 'append', 'overwrite'.
|
|
408
409
|
merge_schema : bool, default=False
|
|
409
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.
|
|
410
413
|
lakehouse : str, default=None
|
|
411
414
|
The Fabric lakehouse used by the Direct Lake semantic model.
|
|
412
415
|
Defaults to None which resolves to the lakehouse attached to the notebook.
|
|
@@ -414,13 +417,22 @@ def save_as_delta_table(
|
|
|
414
417
|
The Fabric workspace name.
|
|
415
418
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
416
419
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
417
|
-
|
|
418
|
-
Returns
|
|
419
|
-
-------
|
|
420
|
-
UUID
|
|
421
|
-
The ID of the Power BI report.
|
|
422
420
|
"""
|
|
423
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
|
+
|
|
424
436
|
if workspace is None:
|
|
425
437
|
workspace_id = fabric.get_workspace_id()
|
|
426
438
|
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
@@ -449,9 +461,32 @@ def save_as_delta_table(
|
|
|
449
461
|
)
|
|
450
462
|
|
|
451
463
|
dataframe.columns = dataframe.columns.str.replace(" ", "_")
|
|
452
|
-
|
|
453
464
|
spark = SparkSession.builder.getOrCreate()
|
|
454
|
-
|
|
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)
|
|
455
490
|
|
|
456
491
|
filePath = create_abfss_path(
|
|
457
492
|
lakehouse_id=lakehouse_id,
|
|
@@ -780,6 +815,37 @@ def resolve_capacity_name(capacity_id: Optional[UUID] = None) -> str:
|
|
|
780
815
|
return dfC_filt["Display Name"].iloc[0]
|
|
781
816
|
|
|
782
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
|
+
|
|
783
849
|
def retry(sleep_time: int, timeout_error_message: str):
|
|
784
850
|
def decorator(func):
|
|
785
851
|
@wraps(func)
|
|
@@ -853,3 +919,132 @@ def pagination(client, response):
|
|
|
853
919
|
continuation_uri = response_json.get("continuationUri")
|
|
854
920
|
|
|
855
921
|
return responses
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
def resolve_deployment_pipeline_id(deployment_pipeline: str) -> UUID:
|
|
925
|
+
|
|
926
|
+
from sempy_labs._deployment_pipelines import list_deployment_pipelines
|
|
927
|
+
|
|
928
|
+
dfP = list_deployment_pipelines()
|
|
929
|
+
dfP_filt = dfP[dfP["Deployment Pipeline Name"] == deployment_pipeline]
|
|
930
|
+
if len(dfP_filt) == 0:
|
|
931
|
+
raise ValueError(
|
|
932
|
+
f"{icons.red_dot} The '{deployment_pipeline}' deployment pipeline is not valid."
|
|
933
|
+
)
|
|
934
|
+
deployment_pipeline_id = dfP_filt["Deployment Pipeline Id"].iloc[0]
|
|
935
|
+
|
|
936
|
+
return deployment_pipeline_id
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
class FabricTokenCredential(TokenCredential):
|
|
940
|
+
|
|
941
|
+
def get_token(
|
|
942
|
+
self,
|
|
943
|
+
scopes: str,
|
|
944
|
+
claims: Optional[str] = None,
|
|
945
|
+
tenant_id: Optional[str] = None,
|
|
946
|
+
enable_cae: Optional[bool] = False,
|
|
947
|
+
**kwargs: any,
|
|
948
|
+
) -> AccessToken:
|
|
949
|
+
|
|
950
|
+
from notebookutils import mssparkutils
|
|
951
|
+
|
|
952
|
+
token = mssparkutils.credentials.getToken(scopes)
|
|
953
|
+
access_token = AccessToken(token, 0)
|
|
954
|
+
|
|
955
|
+
return access_token
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
def get_adls_client(account_name):
|
|
959
|
+
|
|
960
|
+
from azure.storage.filedatalake import DataLakeServiceClient
|
|
961
|
+
|
|
962
|
+
account_url = f"https://{account_name}.dfs.core.windows.net"
|
|
963
|
+
|
|
964
|
+
service_client = DataLakeServiceClient(
|
|
965
|
+
account_url, credential=FabricTokenCredential()
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
return service_client
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
def resolve_warehouse_id(warehouse: str, workspace: Optional[str]):
|
|
972
|
+
|
|
973
|
+
workspace = fabric.resolve_workspace_name(workspace)
|
|
974
|
+
warehouse_id = fabric.resolve_item_id(
|
|
975
|
+
item_name=warehouse, type="Warehouse", workspace=workspace
|
|
976
|
+
)
|
|
977
|
+
|
|
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 resolve_environment_id(environment: str, workspace: Optional[str] = None) -> UUID:
|
|
996
|
+
"""
|
|
997
|
+
Obtains the environment Id for a given environment.
|
|
998
|
+
|
|
999
|
+
Parameters
|
|
1000
|
+
----------
|
|
1001
|
+
environment: str
|
|
1002
|
+
Name of the environment.
|
|
1003
|
+
workspace : str, default=None
|
|
1004
|
+
The Fabric workspace name.
|
|
1005
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1006
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1007
|
+
"""
|
|
1008
|
+
|
|
1009
|
+
from sempy_labs._environments import list_environments
|
|
1010
|
+
|
|
1011
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
1012
|
+
|
|
1013
|
+
dfE = list_environments(workspace=workspace)
|
|
1014
|
+
dfE_filt = dfE[dfE["Environment Name"] == environment]
|
|
1015
|
+
if len(dfE_filt) == 0:
|
|
1016
|
+
raise ValueError(
|
|
1017
|
+
f"{icons.red_dot} The '{environment}' environment does not exist within the '{workspace}' workspace."
|
|
1018
|
+
)
|
|
1019
|
+
|
|
1020
|
+
return dfE_filt["Environment Id"].iloc[0]
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
def get_azure_token_credentials(
|
|
1024
|
+
key_vault_uri: str,
|
|
1025
|
+
key_vault_tenant_id: str,
|
|
1026
|
+
key_vault_client_id: str,
|
|
1027
|
+
key_vault_client_secret: str,
|
|
1028
|
+
) -> Tuple[str, str, dict]:
|
|
1029
|
+
|
|
1030
|
+
from notebookutils import mssparkutils
|
|
1031
|
+
from azure.identity import ClientSecretCredential
|
|
1032
|
+
|
|
1033
|
+
tenant_id = mssparkutils.credentials.getSecret(key_vault_uri, key_vault_tenant_id)
|
|
1034
|
+
client_id = mssparkutils.credentials.getSecret(key_vault_uri, key_vault_client_id)
|
|
1035
|
+
client_secret = mssparkutils.credentials.getSecret(
|
|
1036
|
+
key_vault_uri, key_vault_client_secret
|
|
1037
|
+
)
|
|
1038
|
+
|
|
1039
|
+
credential = ClientSecretCredential(
|
|
1040
|
+
tenant_id=tenant_id, client_id=client_id, client_secret=client_secret
|
|
1041
|
+
)
|
|
1042
|
+
|
|
1043
|
+
token = credential.get_token("https://management.azure.com/.default").token
|
|
1044
|
+
|
|
1045
|
+
headers = {
|
|
1046
|
+
"Authorization": f"Bearer {token}",
|
|
1047
|
+
"Content-Type": "application/json",
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
return token, credential, headers
|
sempy_labs/_icons.py
CHANGED
|
@@ -31,3 +31,46 @@ 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"]
|