semantic-link-labs 0.7.1__py3-none-any.whl → 0.7.3__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 (35) hide show
  1. {semantic_link_labs-0.7.1.dist-info → semantic_link_labs-0.7.3.dist-info}/METADATA +3 -2
  2. {semantic_link_labs-0.7.1.dist-info → semantic_link_labs-0.7.3.dist-info}/RECORD +35 -28
  3. {semantic_link_labs-0.7.1.dist-info → semantic_link_labs-0.7.3.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +60 -3
  5. sempy_labs/_bpa_translation/_translations_sv-SE.po +914 -0
  6. sempy_labs/_clear_cache.py +298 -3
  7. sempy_labs/_dataflows.py +130 -0
  8. sempy_labs/_deployment_pipelines.py +171 -0
  9. sempy_labs/_generate_semantic_model.py +148 -27
  10. sempy_labs/_git.py +380 -0
  11. sempy_labs/_helper_functions.py +57 -0
  12. sempy_labs/_list_functions.py +144 -121
  13. sempy_labs/_model_bpa.py +85 -83
  14. sempy_labs/_model_bpa_bulk.py +3 -1
  15. sempy_labs/_model_bpa_rules.py +788 -800
  16. sempy_labs/_query_scale_out.py +15 -3
  17. sempy_labs/_sql.py +96 -0
  18. sempy_labs/_translations.py +0 -1
  19. sempy_labs/_workspace_identity.py +66 -0
  20. sempy_labs/directlake/__init__.py +2 -0
  21. sempy_labs/directlake/_directlake_schema_compare.py +1 -2
  22. sempy_labs/directlake/_dl_helper.py +4 -7
  23. sempy_labs/directlake/_generate_shared_expression.py +85 -0
  24. sempy_labs/directlake/_show_unsupported_directlake_objects.py +1 -2
  25. sempy_labs/lakehouse/_get_lakehouse_tables.py +7 -3
  26. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +5 -0
  27. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +5 -0
  28. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +6 -2
  29. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +6 -5
  30. sempy_labs/migration/_migration_validation.py +6 -0
  31. sempy_labs/report/_report_functions.py +21 -42
  32. sempy_labs/report/_report_rebind.py +5 -0
  33. sempy_labs/tom/_model.py +91 -52
  34. {semantic_link_labs-0.7.1.dist-info → semantic_link_labs-0.7.3.dist-info}/LICENSE +0 -0
  35. {semantic_link_labs-0.7.1.dist-info → semantic_link_labs-0.7.3.dist-info}/top_level.txt +0 -0
@@ -13,12 +13,14 @@ from sempy_labs._helper_functions import (
13
13
  )
14
14
  from sempy_labs.lakehouse._lakehouse import lakehouse_attached
15
15
  import sempy_labs._icons as icons
16
+ from sempy_labs._refresh_semantic_model import refresh_semantic_model
16
17
 
17
18
 
18
19
  def create_blank_semantic_model(
19
20
  dataset: str,
20
21
  compatibility_level: int = 1605,
21
22
  workspace: Optional[str] = None,
23
+ overwrite: Optional[bool] = True,
22
24
  ):
23
25
  """
24
26
  Creates a new blank semantic model (no tables/columns etc.).
@@ -33,34 +35,42 @@ def create_blank_semantic_model(
33
35
  The Fabric workspace name.
34
36
  Defaults to None which resolves to the workspace of the attached lakehouse
35
37
  or if no lakehouse attached, resolves to the workspace of the notebook.
38
+ overwrite : bool, default=False
39
+ If set to True, overwrites the existing semantic model in the workspace if it exists.
36
40
  """
37
41
 
38
42
  workspace = fabric.resolve_workspace_name(workspace)
43
+ dfD = fabric.list_datasets(workspace=workspace, mode="rest")
44
+ dfD_filt = dfD[dfD["Dataset Name"] == dataset]
39
45
 
40
- min_compat = 1500
46
+ if len(dfD_filt) > 0 and not overwrite:
47
+ raise ValueError(
48
+ f"{icons.warning} The '{dataset}' semantic model already exists within the '{workspace}' workspace. The 'overwrite' parameter is set to False so the blank new semantic model was not created."
49
+ )
41
50
 
51
+ min_compat = 1500
42
52
  if compatibility_level < min_compat:
43
53
  raise ValueError(
44
54
  f"{icons.red_dot} Compatiblity level must be at least {min_compat}."
45
55
  )
46
56
 
47
57
  tmsl = f"""
48
- {{
49
- "createOrReplace": {{
50
- "object": {{
51
- "database": '{dataset}'
52
- }},
53
- "database": {{
54
- "name": '{dataset}',
55
- "compatibilityLevel": {compatibility_level},
56
- "model": {{
57
- "culture": "en-US",
58
- "defaultPowerBIDataSourceVersion": "powerBI_V3"
58
+ {{
59
+ "createOrReplace": {{
60
+ "object": {{
61
+ "database": '{dataset}'
62
+ }},
63
+ "database": {{
64
+ "name": '{dataset}',
65
+ "compatibilityLevel": {compatibility_level},
66
+ "model": {{
67
+ "culture": "en-US",
68
+ "defaultPowerBIDataSourceVersion": "powerBI_V3"
69
+ }}
70
+ }}
59
71
  }}
60
- }}
61
72
  }}
62
- }}
63
- """
73
+ """
64
74
 
65
75
  fabric.execute_tmsl(script=tmsl, workspace=workspace)
66
76
 
@@ -89,12 +99,12 @@ def create_semantic_model_from_bim(
89
99
 
90
100
  (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
91
101
 
92
- dfI = fabric.list_items(workspace=workspace, type="SemanticModel")
93
- dfI_filt = dfI[(dfI["Display Name"] == dataset)]
102
+ dfI = fabric.list_datasets(workspace=workspace, mode="rest")
103
+ dfI_filt = dfI[(dfI["Dataset Name"] == dataset)]
94
104
 
95
105
  if len(dfI_filt) > 0:
96
106
  raise ValueError(
97
- f"{icons.red_dot} '{dataset}' already exists as a semantic model in the '{workspace}' workspace."
107
+ f"{icons.red_dot} The '{dataset}' semantic model already exists as a semantic model in the '{workspace}' workspace."
98
108
  )
99
109
 
100
110
  client = fabric.FabricRestClient()
@@ -133,12 +143,77 @@ def create_semantic_model_from_bim(
133
143
  )
134
144
 
135
145
 
146
+ def update_semantic_model_from_bim(
147
+ dataset: str, bim_file: dict, workspace: Optional[str] = None
148
+ ):
149
+ """
150
+ Updates a semantic model definition based on a Model.bim file.
151
+
152
+ Parameters
153
+ ----------
154
+ dataset : str
155
+ Name of the semantic model.
156
+ bim_file : dict
157
+ The model.bim file.
158
+ workspace : str, default=None
159
+ The Fabric workspace name.
160
+ Defaults to None which resolves to the workspace of the attached lakehouse
161
+ or if no lakehouse attached, resolves to the workspace of the notebook.
162
+ """
163
+
164
+ (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
165
+
166
+ dfD = fabric.list_datasets(workspace=workspace, mode="rest")
167
+ dfD_filt = dfD[dfD["Dataset Name"] == dataset]
168
+ if len(dfD_filt) == 0:
169
+ raise ValueError(
170
+ f"{icons.red_dot} The '{dataset}' semantic model within the '{workspace}' workspace does not exist."
171
+ )
172
+ dataset_id = dfD_filt["Dataset Id"].iloc[0]
173
+
174
+ client = fabric.FabricRestClient()
175
+ defPBIDataset = {"version": "1.0", "settings": {}}
176
+
177
+ payloadPBIDefinition = _conv_b64(defPBIDataset)
178
+ payloadBim = _conv_b64(bim_file)
179
+
180
+ request_body = {
181
+ "displayName": dataset,
182
+ "definition": {
183
+ "parts": [
184
+ {
185
+ "path": "model.bim",
186
+ "payload": payloadBim,
187
+ "payloadType": "InlineBase64",
188
+ },
189
+ {
190
+ "path": "definition.pbidataset",
191
+ "payload": payloadPBIDefinition,
192
+ "payloadType": "InlineBase64",
193
+ },
194
+ ]
195
+ },
196
+ }
197
+
198
+ response = client.post(
199
+ f"/v1/workspaces/{workspace_id}/semanticModels/{dataset_id}/updateDefinition",
200
+ json=request_body,
201
+ )
202
+
203
+ lro(client, response, status_codes=[200, 202])
204
+
205
+ print(
206
+ f"{icons.green_dot} The '{dataset}' semantic model has been updated within the '{workspace}' workspace."
207
+ )
208
+
209
+
136
210
  def deploy_semantic_model(
137
211
  source_dataset: str,
138
212
  source_workspace: Optional[str] = None,
139
213
  target_dataset: Optional[str] = None,
140
214
  target_workspace: Optional[str] = None,
141
215
  refresh_target_dataset: Optional[bool] = True,
216
+ overwrite: Optional[bool] = False,
142
217
  ):
143
218
  """
144
219
  Deploys a semantic model based on an existing semantic model.
@@ -159,14 +234,10 @@ def deploy_semantic_model(
159
234
  or if no lakehouse attached, resolves to the workspace of the notebook.
160
235
  refresh_target_dataset : bool, default=True
161
236
  If set to True, this will initiate a full refresh of the target semantic model in the target workspace.
162
-
163
- Returns
164
- -------
165
-
237
+ overwrite : bool, default=False
238
+ If set to True, overwrites the existing semantic model in the workspace if it exists.
166
239
  """
167
240
 
168
- from sempy_labs import refresh_semantic_model
169
-
170
241
  source_workspace = fabric.resolve_workspace_name(source_workspace)
171
242
 
172
243
  if target_workspace is None:
@@ -181,11 +252,28 @@ def deploy_semantic_model(
181
252
  f"parameters have the same value. At least one of these must be different. Please update the parameters."
182
253
  )
183
254
 
255
+ dfD = fabric.list_datasets(workspace=target_workspace, mode="rest")
256
+ dfD_filt = dfD[dfD["Dataset Name"] == target_dataset]
257
+ if len(dfD_filt) > 0 and not overwrite:
258
+ raise ValueError(
259
+ f"{icons.warning} The '{target_dataset}' semantic model already exists within the '{target_workspace}' workspace. The 'overwrite' parameter is set to False so the source semantic model was not deployed to the target destination."
260
+ )
261
+
184
262
  bim = get_semantic_model_bim(dataset=source_dataset, workspace=source_workspace)
185
263
 
186
- create_semantic_model_from_bim(
187
- dataset=target_dataset, bim_file=bim, workspace=target_workspace
188
- )
264
+ # Create the semantic model if the model does not exist
265
+ if len(dfD_filt) == 0:
266
+ create_semantic_model_from_bim(
267
+ dataset=target_dataset,
268
+ bim_file=bim,
269
+ workspace=target_workspace,
270
+ overwrite=overwrite,
271
+ )
272
+ # Update the semantic model if the model exists
273
+ else:
274
+ update_semantic_model_from_bim(
275
+ dataset=target_dataset, bim_file=bim, workspace=target_workspace
276
+ )
189
277
 
190
278
  if refresh_target_dataset:
191
279
  refresh_semantic_model(dataset=target_dataset, workspace=target_workspace)
@@ -257,3 +345,36 @@ def get_semantic_model_bim(
257
345
  )
258
346
 
259
347
  return bimJson
348
+
349
+
350
+ def get_semantic_model_size(dataset: str, workspace: Optional[str] = None):
351
+
352
+ workspace = fabric.resolve_workspace_name(workspace)
353
+
354
+ dict = fabric.evaluate_dax(
355
+ dataset=dataset,
356
+ workspace=workspace,
357
+ dax_string="""
358
+ EVALUATE SELECTCOLUMNS(FILTER(INFO.STORAGETABLECOLUMNS(), [COLUMN_TYPE] = "BASIC_DATA"),[DICTIONARY_SIZE])
359
+ """,
360
+ )
361
+
362
+ used_size = fabric.evaluate_dax(
363
+ dataset=dataset,
364
+ workspace=workspace,
365
+ dax_string="""
366
+ EVALUATE SELECTCOLUMNS(INFO.STORAGETABLECOLUMNSEGMENTS(),[USED_SIZE])
367
+ """,
368
+ )
369
+ dict_size = dict["[DICTIONARY_SIZE]"].sum()
370
+ used_size = used_size["[USED_SIZE]"].sum()
371
+ model_size = dict_size + used_size
372
+ # Calculate proper bytes size by dividing by 1024 and multiplying by 1000 - per 1000
373
+ if model_size >= 10**9:
374
+ result = model_size / (1024**3) * 10**9
375
+ elif model_size >= 10**6:
376
+ result = model_size / (1024**2) * 10**6
377
+ elif model_size >= 10**3:
378
+ result = model_size / (1024) * 10**3
379
+
380
+ return result
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
+ )
@@ -12,6 +12,7 @@ from uuid import UUID
12
12
  import sempy_labs._icons as icons
13
13
  from sempy.fabric.exceptions import FabricHTTPException
14
14
  import urllib.parse
15
+ from azure.core.credentials import TokenCredential, AccessToken
15
16
 
16
17
 
17
18
  def create_abfss_path(
@@ -853,3 +854,59 @@ def pagination(client, response):
853
854
  continuation_uri = response_json.get("continuationUri")
854
855
 
855
856
  return responses
857
+
858
+
859
+ def resolve_deployment_pipeline_id(deployment_pipeline: str) -> UUID:
860
+
861
+ from sempy_labs._deployment_pipelines import list_deployment_pipelines
862
+
863
+ dfP = list_deployment_pipelines()
864
+ dfP_filt = dfP[dfP["Deployment Pipeline Name"] == deployment_pipeline]
865
+ if len(dfP_filt) == 0:
866
+ raise ValueError(
867
+ f"{icons.red_dot} The '{deployment_pipeline}' deployment pipeline is not valid."
868
+ )
869
+ deployment_pipeline_id = dfP_filt["Deployment Pipeline Id"].iloc[0]
870
+
871
+ return deployment_pipeline_id
872
+
873
+
874
+ class FabricTokenCredential(TokenCredential):
875
+
876
+ def get_token(
877
+ self,
878
+ scopes: str,
879
+ claims: Optional[str] = None,
880
+ tenant_id: Optional[str] = None,
881
+ enable_cae: Optional[bool] = False,
882
+ **kwargs: any,
883
+ ) -> AccessToken:
884
+
885
+ from notebookutils import mssparkutils
886
+ token = mssparkutils.credentials.getToken(scopes)
887
+ access_token = AccessToken(token, 0)
888
+
889
+ return access_token
890
+
891
+
892
+ def get_adls_client(account_name):
893
+
894
+ from azure.storage.filedatalake import DataLakeServiceClient
895
+
896
+ account_url = f"https://{account_name}.dfs.core.windows.net"
897
+
898
+ service_client = DataLakeServiceClient(
899
+ account_url, credential=FabricTokenCredential()
900
+ )
901
+
902
+ return service_client
903
+
904
+
905
+ def resolve_warehouse_id(warehouse: str, workspace: Optional[str]):
906
+
907
+ workspace = fabric.resolve_workspace_name(workspace)
908
+ warehouse_id = fabric.resolve_item_id(
909
+ item_name=warehouse, type="Warehouse", workspace=workspace
910
+ )
911
+
912
+ return warehouse_id