semantic-link-labs 0.8.9__py3-none-any.whl → 0.8.11__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.8.9.dist-info → semantic_link_labs-0.8.11.dist-info}/METADATA +5 -2
- {semantic_link_labs-0.8.9.dist-info → semantic_link_labs-0.8.11.dist-info}/RECORD +76 -75
- sempy_labs/__init__.py +14 -2
- sempy_labs/_authentication.py +31 -2
- sempy_labs/_clear_cache.py +39 -37
- sempy_labs/_connections.py +13 -13
- sempy_labs/_data_pipelines.py +20 -20
- sempy_labs/_dataflows.py +27 -28
- sempy_labs/_dax.py +41 -47
- sempy_labs/_environments.py +26 -23
- sempy_labs/_eventhouses.py +16 -15
- sempy_labs/_eventstreams.py +16 -15
- sempy_labs/_external_data_shares.py +18 -20
- sempy_labs/_gateways.py +57 -11
- sempy_labs/_generate_semantic_model.py +100 -71
- sempy_labs/_git.py +134 -67
- sempy_labs/_helper_functions.py +199 -145
- sempy_labs/_job_scheduler.py +92 -0
- sempy_labs/_kql_databases.py +16 -15
- sempy_labs/_kql_querysets.py +16 -15
- sempy_labs/_list_functions.py +281 -120
- sempy_labs/_managed_private_endpoints.py +19 -17
- sempy_labs/_mirrored_databases.py +51 -48
- sempy_labs/_mirrored_warehouses.py +5 -4
- sempy_labs/_ml_experiments.py +16 -15
- sempy_labs/_ml_models.py +15 -14
- sempy_labs/_model_bpa.py +27 -25
- sempy_labs/_model_bpa_bulk.py +3 -3
- sempy_labs/_model_dependencies.py +60 -28
- sempy_labs/_notebooks.py +73 -39
- sempy_labs/_one_lake_integration.py +23 -26
- sempy_labs/_query_scale_out.py +67 -64
- sempy_labs/_refresh_semantic_model.py +47 -42
- sempy_labs/_spark.py +33 -32
- sempy_labs/_sql.py +12 -9
- sempy_labs/_translations.py +10 -7
- sempy_labs/_vertipaq.py +34 -31
- sempy_labs/_warehouses.py +22 -21
- sempy_labs/_workspace_identity.py +11 -10
- sempy_labs/_workspaces.py +40 -33
- sempy_labs/admin/__init__.py +4 -0
- sempy_labs/admin/_basic_functions.py +44 -12
- sempy_labs/admin/_external_data_share.py +3 -3
- sempy_labs/admin/_items.py +4 -4
- sempy_labs/admin/_scanner.py +7 -5
- sempy_labs/directlake/_directlake_schema_compare.py +18 -14
- sempy_labs/directlake/_directlake_schema_sync.py +18 -12
- sempy_labs/directlake/_dl_helper.py +36 -32
- sempy_labs/directlake/_generate_shared_expression.py +10 -9
- sempy_labs/directlake/_get_directlake_lakehouse.py +16 -13
- sempy_labs/directlake/_get_shared_expression.py +4 -3
- sempy_labs/directlake/_guardrails.py +12 -6
- sempy_labs/directlake/_list_directlake_model_calc_tables.py +15 -9
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +16 -10
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +35 -31
- sempy_labs/directlake/_update_directlake_partition_entity.py +34 -31
- sempy_labs/directlake/_warm_cache.py +87 -65
- sempy_labs/lakehouse/_get_lakehouse_columns.py +10 -8
- sempy_labs/lakehouse/_get_lakehouse_tables.py +10 -9
- sempy_labs/lakehouse/_lakehouse.py +17 -13
- sempy_labs/lakehouse/_shortcuts.py +42 -23
- sempy_labs/migration/_create_pqt_file.py +16 -11
- sempy_labs/migration/_refresh_calc_tables.py +16 -10
- sempy_labs/report/_download_report.py +9 -8
- sempy_labs/report/_generate_report.py +40 -44
- sempy_labs/report/_paginated.py +9 -9
- sempy_labs/report/_report_bpa.py +13 -9
- sempy_labs/report/_report_functions.py +80 -91
- sempy_labs/report/_report_helper.py +8 -4
- sempy_labs/report/_report_list_functions.py +24 -13
- sempy_labs/report/_report_rebind.py +17 -16
- sempy_labs/report/_reportwrapper.py +41 -33
- sempy_labs/tom/_model.py +117 -38
- {semantic_link_labs-0.8.9.dist-info → semantic_link_labs-0.8.11.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.8.9.dist-info → semantic_link_labs-0.8.11.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.8.9.dist-info → semantic_link_labs-0.8.11.dist-info}/top_level.txt +0 -0
sempy_labs/_model_bpa.py
CHANGED
|
@@ -10,9 +10,10 @@ from sempy_labs._helper_functions import (
|
|
|
10
10
|
create_relationship_name,
|
|
11
11
|
save_as_delta_table,
|
|
12
12
|
resolve_workspace_capacity,
|
|
13
|
-
|
|
13
|
+
resolve_dataset_name_and_id,
|
|
14
14
|
get_language_codes,
|
|
15
15
|
_get_max_run_id,
|
|
16
|
+
resolve_workspace_name_and_id,
|
|
16
17
|
)
|
|
17
18
|
from sempy_labs.lakehouse import get_lakehouse_tables, lakehouse_attached
|
|
18
19
|
from sempy_labs.tom import connect_semantic_model
|
|
@@ -23,11 +24,12 @@ import sempy_labs._icons as icons
|
|
|
23
24
|
from pyspark.sql.functions import col, flatten
|
|
24
25
|
from pyspark.sql.types import StructType, StructField, StringType
|
|
25
26
|
import os
|
|
27
|
+
from uuid import UUID
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
@log
|
|
29
31
|
def run_model_bpa(
|
|
30
|
-
dataset: str,
|
|
32
|
+
dataset: str | UUID,
|
|
31
33
|
rules: Optional[pd.DataFrame] = None,
|
|
32
34
|
workspace: Optional[str] = None,
|
|
33
35
|
export: bool = False,
|
|
@@ -41,12 +43,12 @@ def run_model_bpa(
|
|
|
41
43
|
|
|
42
44
|
Parameters
|
|
43
45
|
----------
|
|
44
|
-
dataset : str
|
|
45
|
-
Name of the semantic model.
|
|
46
|
+
dataset : str | uuid.UUID
|
|
47
|
+
Name or ID of the semantic model.
|
|
46
48
|
rules : pandas.DataFrame, default=None
|
|
47
49
|
A pandas dataframe containing rules to be evaluated.
|
|
48
|
-
workspace : str, default=None
|
|
49
|
-
The Fabric workspace name.
|
|
50
|
+
workspace : str | uuid.UUID, default=None
|
|
51
|
+
The Fabric workspace name or ID.
|
|
50
52
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
51
53
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
52
54
|
export : bool, default=False
|
|
@@ -105,28 +107,27 @@ def run_model_bpa(
|
|
|
105
107
|
if language is not None:
|
|
106
108
|
language = map_language(language, language_list)
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
111
|
+
(dataset_name, dataset_id) = resolve_dataset_name_and_id(
|
|
112
|
+
dataset, workspace=workspace_id
|
|
113
|
+
)
|
|
109
114
|
|
|
110
115
|
if language is not None and language not in language_list:
|
|
111
116
|
print(
|
|
112
117
|
f"{icons.yellow_dot} The '{language}' language code is not in our predefined language list. Please file an issue and let us know which language code you are using: https://github.com/microsoft/semantic-link-labs/issues/new?assignees=&labels=&projects=&template=bug_report.md&title=."
|
|
113
118
|
)
|
|
114
119
|
|
|
115
|
-
if extended:
|
|
116
|
-
icons.sll_tags.append("ModelBPAExtended")
|
|
117
|
-
with connect_semantic_model(
|
|
118
|
-
dataset=dataset, workspace=workspace, readonly=False
|
|
119
|
-
) as tom:
|
|
120
|
-
tom.set_vertipaq_annotations()
|
|
121
|
-
|
|
122
120
|
with connect_semantic_model(
|
|
123
|
-
dataset=
|
|
121
|
+
dataset=dataset_id, workspace=workspace_id, readonly=True
|
|
124
122
|
) as tom:
|
|
125
123
|
|
|
124
|
+
if extended:
|
|
125
|
+
tom.set_vertipaq_annotations()
|
|
126
|
+
|
|
126
127
|
# Do not run BPA for models with no tables
|
|
127
128
|
if tom.model.Tables.Count == 0:
|
|
128
129
|
print(
|
|
129
|
-
f"{icons.warning} The '{
|
|
130
|
+
f"{icons.warning} The '{dataset_name}' semantic model within the '{workspace_name}' workspace has no tables and therefore there are no valid BPA results."
|
|
130
131
|
)
|
|
131
132
|
finalDF = pd.DataFrame(
|
|
132
133
|
columns=[
|
|
@@ -140,7 +141,9 @@ def run_model_bpa(
|
|
|
140
141
|
]
|
|
141
142
|
)
|
|
142
143
|
else:
|
|
143
|
-
dep = get_model_calc_dependencies(
|
|
144
|
+
dep = get_model_calc_dependencies(
|
|
145
|
+
dataset=dataset_id, workspace=workspace_id
|
|
146
|
+
)
|
|
144
147
|
|
|
145
148
|
def translate_using_po(rule_file):
|
|
146
149
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -386,20 +389,19 @@ def run_model_bpa(
|
|
|
386
389
|
runId = max_run_id + 1
|
|
387
390
|
|
|
388
391
|
now = datetime.datetime.now()
|
|
389
|
-
dfD = fabric.list_datasets(workspace=
|
|
390
|
-
dfD_filt = dfD[dfD["Dataset
|
|
392
|
+
dfD = fabric.list_datasets(workspace=workspace_id, mode="rest")
|
|
393
|
+
dfD_filt = dfD[dfD["Dataset Id"] == dataset_id]
|
|
391
394
|
configured_by = dfD_filt["Configured By"].iloc[0]
|
|
392
|
-
capacity_id, capacity_name = resolve_workspace_capacity(workspace=
|
|
395
|
+
capacity_id, capacity_name = resolve_workspace_capacity(workspace=workspace_id)
|
|
393
396
|
dfExport["Capacity Name"] = capacity_name
|
|
394
397
|
dfExport["Capacity Id"] = capacity_id
|
|
395
|
-
dfExport["Workspace Name"] =
|
|
396
|
-
dfExport["Workspace Id"] =
|
|
397
|
-
dfExport["Dataset Name"] =
|
|
398
|
-
dfExport["Dataset Id"] =
|
|
398
|
+
dfExport["Workspace Name"] = workspace_name
|
|
399
|
+
dfExport["Workspace Id"] = workspace_id
|
|
400
|
+
dfExport["Dataset Name"] = dataset_name
|
|
401
|
+
dfExport["Dataset Id"] = dataset_id
|
|
399
402
|
dfExport["Configured By"] = configured_by
|
|
400
403
|
dfExport["Timestamp"] = now
|
|
401
404
|
dfExport["RunId"] = runId
|
|
402
|
-
dfExport["Configured By"] = configured_by
|
|
403
405
|
dfExport["RunId"] = dfExport["RunId"].astype("int")
|
|
404
406
|
|
|
405
407
|
dfExport = dfExport[list(icons.bpa_schema.keys())]
|
sempy_labs/_model_bpa_bulk.py
CHANGED
|
@@ -119,16 +119,16 @@ def run_model_bpa_bulk(
|
|
|
119
119
|
dfD_filt = dfD[~dfD["Dataset Name"].isin(skip_models)]
|
|
120
120
|
|
|
121
121
|
if len(dfD_filt) > 0:
|
|
122
|
-
for
|
|
122
|
+
for _, r2 in dfD_filt.iterrows():
|
|
123
|
+
dataset_id = r2["Dataset Id"]
|
|
123
124
|
dataset_name = r2["Dataset Name"]
|
|
124
125
|
config_by = r2["Configured By"]
|
|
125
|
-
dataset_id = r2["Dataset Id"]
|
|
126
126
|
print(
|
|
127
127
|
f"{icons.in_progress} Collecting Model BPA stats for the '{dataset_name}' semantic model within the '{wksp}' workspace."
|
|
128
128
|
)
|
|
129
129
|
try:
|
|
130
130
|
bpa_df = run_model_bpa(
|
|
131
|
-
dataset=
|
|
131
|
+
dataset=dataset_id,
|
|
132
132
|
workspace=wksp,
|
|
133
133
|
language=language,
|
|
134
134
|
return_dataframe=True,
|
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
import sempy.fabric as fabric
|
|
2
2
|
import pandas as pd
|
|
3
|
-
from sempy_labs._helper_functions import
|
|
3
|
+
from sempy_labs._helper_functions import (
|
|
4
|
+
format_dax_object_name,
|
|
5
|
+
resolve_dataset_name_and_id,
|
|
6
|
+
resolve_workspace_name_and_id,
|
|
7
|
+
)
|
|
4
8
|
import sempy_labs._icons as icons
|
|
5
9
|
from typing import Any, Dict, Optional
|
|
6
10
|
from anytree import Node, RenderTree
|
|
7
11
|
from sempy._utils._log import log
|
|
12
|
+
from uuid import UUID
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
@log
|
|
11
16
|
def get_measure_dependencies(
|
|
12
|
-
dataset: str, workspace: Optional[str] = None
|
|
17
|
+
dataset: str | UUID, workspace: Optional[str | UUID] = None
|
|
13
18
|
) -> pd.DataFrame:
|
|
14
19
|
"""
|
|
15
20
|
Shows all dependencies for all measures in a semantic model.
|
|
16
21
|
|
|
17
22
|
Parameters
|
|
18
23
|
----------
|
|
19
|
-
dataset : str
|
|
20
|
-
Name of the semantic model.
|
|
21
|
-
workspace : str, default=None
|
|
22
|
-
The Fabric workspace name.
|
|
24
|
+
dataset : str | uuid.UUID
|
|
25
|
+
Name or ID of the semantic model.
|
|
26
|
+
workspace : str | uuid.UUID, default=None
|
|
27
|
+
The Fabric workspace name or ID.
|
|
23
28
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
24
29
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
25
30
|
|
|
@@ -29,8 +34,6 @@ def get_measure_dependencies(
|
|
|
29
34
|
Shows all dependencies for all measures in the semantic model.
|
|
30
35
|
"""
|
|
31
36
|
|
|
32
|
-
workspace = fabric.resolve_workspace_name(workspace)
|
|
33
|
-
|
|
34
37
|
dep = fabric.evaluate_dax(
|
|
35
38
|
dataset=dataset,
|
|
36
39
|
workspace=workspace,
|
|
@@ -139,17 +142,18 @@ def get_measure_dependencies(
|
|
|
139
142
|
|
|
140
143
|
@log
|
|
141
144
|
def get_model_calc_dependencies(
|
|
142
|
-
dataset: str
|
|
145
|
+
dataset: str | UUID,
|
|
146
|
+
workspace: Optional[str] = None,
|
|
143
147
|
) -> pd.DataFrame:
|
|
144
148
|
"""
|
|
145
149
|
Shows all dependencies for all objects in a semantic model.
|
|
146
150
|
|
|
147
151
|
Parameters
|
|
148
152
|
----------
|
|
149
|
-
dataset : str
|
|
150
|
-
Name of the semantic model.
|
|
151
|
-
workspace : str, default=None
|
|
152
|
-
The Fabric workspace name.
|
|
153
|
+
dataset : str | uuid.UUID
|
|
154
|
+
Name or ID of the semantic model.
|
|
155
|
+
workspace : str | uuid.UUID, default=None
|
|
156
|
+
The Fabric workspace name or ID.
|
|
153
157
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
154
158
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
155
159
|
|
|
@@ -159,7 +163,6 @@ def get_model_calc_dependencies(
|
|
|
159
163
|
Shows all dependencies for all objects in the semantic model.
|
|
160
164
|
"""
|
|
161
165
|
|
|
162
|
-
workspace = fabric.resolve_workspace_name(workspace)
|
|
163
166
|
dep = fabric.evaluate_dax(
|
|
164
167
|
dataset=dataset,
|
|
165
168
|
workspace=workspace,
|
|
@@ -187,12 +190,24 @@ def get_model_calc_dependencies(
|
|
|
187
190
|
dep["Referenced Table"], dep["Referenced Object"]
|
|
188
191
|
)
|
|
189
192
|
dep["Parent Node"] = dep["Object Name"]
|
|
193
|
+
|
|
190
194
|
# Initialize dependency DataFrame with 'Done' status
|
|
191
195
|
df = dep.copy()
|
|
192
196
|
objs = {"Measure", "Calc Column", "Calculation Item", "Calc Table"}
|
|
193
197
|
df["Done"] = (
|
|
194
198
|
df["Referenced Object Type"].apply(lambda x: x not in objs).astype(bool)
|
|
195
199
|
)
|
|
200
|
+
|
|
201
|
+
# Set to track visited dependencies to prevent circular references
|
|
202
|
+
visited = set(
|
|
203
|
+
zip(
|
|
204
|
+
df["Full Object Name"],
|
|
205
|
+
df["Referenced Full Object Name"],
|
|
206
|
+
df["Object Type"],
|
|
207
|
+
df["Referenced Object Type"],
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
|
|
196
211
|
# Expand dependencies iteratively
|
|
197
212
|
while not df["Done"].all():
|
|
198
213
|
incomplete_rows = df[df["Done"] == False]
|
|
@@ -206,11 +221,24 @@ def get_model_calc_dependencies(
|
|
|
206
221
|
# Expand dependencies and update 'Done' status as needed
|
|
207
222
|
new_rows = []
|
|
208
223
|
for _, dependency in dep_filt.iterrows():
|
|
224
|
+
# Check if the dependency has already been visited
|
|
225
|
+
dependency_pair = (
|
|
226
|
+
row["Full Object Name"],
|
|
227
|
+
dependency["Referenced Full Object Name"],
|
|
228
|
+
row["Object Type"],
|
|
229
|
+
dependency["Referenced Object Type"],
|
|
230
|
+
)
|
|
231
|
+
if dependency_pair in visited:
|
|
232
|
+
continue # Skip already visited dependencies
|
|
233
|
+
|
|
234
|
+
visited.add(dependency_pair) # Mark as visited
|
|
235
|
+
|
|
209
236
|
is_done = dependency["Referenced Object Type"] not in objs
|
|
210
237
|
new_row = {
|
|
211
238
|
"Table Name": row["Table Name"],
|
|
212
239
|
"Object Name": row["Object Name"],
|
|
213
240
|
"Object Type": row["Object Type"],
|
|
241
|
+
"Expression": row["Expression"],
|
|
214
242
|
"Referenced Table": dependency["Referenced Table"],
|
|
215
243
|
"Referenced Object": dependency["Referenced Object"],
|
|
216
244
|
"Referenced Object Type": dependency["Referenced Object Type"],
|
|
@@ -222,7 +250,14 @@ def get_model_calc_dependencies(
|
|
|
222
250
|
"Parent Node": row["Referenced Object"],
|
|
223
251
|
}
|
|
224
252
|
new_rows.append(new_row)
|
|
225
|
-
|
|
253
|
+
|
|
254
|
+
if new_rows:
|
|
255
|
+
new_rows_df = pd.DataFrame(new_rows)
|
|
256
|
+
new_rows_df = new_rows_df.dropna(
|
|
257
|
+
axis=1, how="all"
|
|
258
|
+
) # Drop empty columns
|
|
259
|
+
df = pd.concat([df, new_rows_df], ignore_index=True)
|
|
260
|
+
|
|
226
261
|
df.loc[df.index == row.name, "Done"] = True
|
|
227
262
|
# Finalize DataFrame and yield result
|
|
228
263
|
df = df.drop(columns=["Done"])
|
|
@@ -232,39 +267,36 @@ def get_model_calc_dependencies(
|
|
|
232
267
|
|
|
233
268
|
@log
|
|
234
269
|
def measure_dependency_tree(
|
|
235
|
-
dataset: str, measure_name: str, workspace: Optional[str] = None
|
|
270
|
+
dataset: str | UUID, measure_name: str, workspace: Optional[str | UUID] = None
|
|
236
271
|
):
|
|
237
272
|
"""
|
|
238
273
|
Prints a measure dependency tree of all dependent objects for a measure in a semantic model.
|
|
239
274
|
|
|
240
275
|
Parameters
|
|
241
276
|
----------
|
|
242
|
-
dataset : str
|
|
243
|
-
Name of the semantic model.
|
|
277
|
+
dataset : str | uuid.UUID
|
|
278
|
+
Name or ID of the semantic model.
|
|
244
279
|
measure_name : str
|
|
245
280
|
Name of the measure.
|
|
246
|
-
workspace : str, default=None
|
|
247
|
-
The Fabric workspace name.
|
|
281
|
+
workspace : str | uuid.UUID, default=None
|
|
282
|
+
The Fabric workspace name or ID.
|
|
248
283
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
249
284
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
250
|
-
|
|
251
|
-
Returns
|
|
252
|
-
-------
|
|
253
|
-
|
|
254
285
|
"""
|
|
255
286
|
|
|
256
|
-
|
|
287
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
288
|
+
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
257
289
|
|
|
258
|
-
dfM = fabric.list_measures(dataset=
|
|
290
|
+
dfM = fabric.list_measures(dataset=dataset_id, workspace=workspace_id)
|
|
259
291
|
dfM_filt = dfM[dfM["Measure Name"] == measure_name]
|
|
260
292
|
|
|
261
293
|
if len(dfM_filt) == 0:
|
|
262
294
|
print(
|
|
263
|
-
f"{icons.red_dot} The '{measure_name}' measure does not exist in the '{
|
|
295
|
+
f"{icons.red_dot} The '{measure_name}' measure does not exist in the '{dataset_name}' semantic model in the '{workspace_name}' workspace."
|
|
264
296
|
)
|
|
265
297
|
return
|
|
266
298
|
|
|
267
|
-
md = get_measure_dependencies(
|
|
299
|
+
md = get_measure_dependencies(dataset_id, workspace_id)
|
|
268
300
|
df_filt = md[md["Object Name"] == measure_name]
|
|
269
301
|
|
|
270
302
|
# Create a dictionary to hold references to nodes
|
sempy_labs/_notebooks.py
CHANGED
|
@@ -10,10 +10,49 @@ from sempy_labs._helper_functions import (
|
|
|
10
10
|
_decode_b64,
|
|
11
11
|
)
|
|
12
12
|
from sempy.fabric.exceptions import FabricHTTPException
|
|
13
|
+
import os
|
|
14
|
+
from uuid import UUID
|
|
15
|
+
|
|
16
|
+
_notebook_prefix = "notebook-content."
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_notebook_definition_base(
|
|
20
|
+
notebook_name: str, workspace: Optional[str | UUID] = None
|
|
21
|
+
) -> pd.DataFrame:
|
|
22
|
+
|
|
23
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
24
|
+
item_id = fabric.resolve_item_id(
|
|
25
|
+
item_name=notebook_name, type="Notebook", workspace=workspace_id
|
|
26
|
+
)
|
|
27
|
+
client = fabric.FabricRestClient()
|
|
28
|
+
response = client.post(
|
|
29
|
+
f"v1/workspaces/{workspace_id}/notebooks/{item_id}/getDefinition",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
result = lro(client, response).json()
|
|
33
|
+
|
|
34
|
+
return pd.json_normalize(result["definition"]["parts"])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _get_notebook_type(
|
|
38
|
+
notebook_name: str, workspace: Optional[str | UUID] = None
|
|
39
|
+
) -> str:
|
|
40
|
+
|
|
41
|
+
df_items = _get_notebook_definition_base(
|
|
42
|
+
notebook_name=notebook_name, workspace=workspace
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
file_path = df_items[df_items["path"].str.startswith(_notebook_prefix)][
|
|
46
|
+
"path"
|
|
47
|
+
].iloc[0]
|
|
48
|
+
|
|
49
|
+
_, file_extension = os.path.splitext(file_path)
|
|
50
|
+
|
|
51
|
+
return file_extension[1:]
|
|
13
52
|
|
|
14
53
|
|
|
15
54
|
def get_notebook_definition(
|
|
16
|
-
notebook_name: str, workspace: Optional[str] = None, decode: bool = True
|
|
55
|
+
notebook_name: str, workspace: Optional[str | UUID] = None, decode: bool = True
|
|
17
56
|
) -> str:
|
|
18
57
|
"""
|
|
19
58
|
Obtains the notebook definition.
|
|
@@ -24,8 +63,8 @@ def get_notebook_definition(
|
|
|
24
63
|
----------
|
|
25
64
|
notebook_name : str
|
|
26
65
|
The name of the notebook.
|
|
27
|
-
workspace : str, default=None
|
|
28
|
-
The name of the workspace.
|
|
66
|
+
workspace : str | uuid.UUID, default=None
|
|
67
|
+
The name or ID of the workspace.
|
|
29
68
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
30
69
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
31
70
|
decode : bool, default=True
|
|
@@ -38,18 +77,10 @@ def get_notebook_definition(
|
|
|
38
77
|
The notebook definition.
|
|
39
78
|
"""
|
|
40
79
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
item_name=notebook_name, type="Notebook", workspace=workspace
|
|
44
|
-
)
|
|
45
|
-
client = fabric.FabricRestClient()
|
|
46
|
-
response = client.post(
|
|
47
|
-
f"v1/workspaces/{workspace_id}/notebooks/{item_id}/getDefinition",
|
|
80
|
+
df_items = _get_notebook_definition_base(
|
|
81
|
+
notebook_name=notebook_name, workspace=workspace
|
|
48
82
|
)
|
|
49
|
-
|
|
50
|
-
result = lro(client, response).json()
|
|
51
|
-
df_items = pd.json_normalize(result["definition"]["parts"])
|
|
52
|
-
df_items_filt = df_items[df_items["path"] == "notebook-content.py"]
|
|
83
|
+
df_items_filt = df_items[df_items["path"].str.startswith(_notebook_prefix)]
|
|
53
84
|
payload = df_items_filt["payload"].iloc[0]
|
|
54
85
|
|
|
55
86
|
if decode:
|
|
@@ -64,7 +95,7 @@ def import_notebook_from_web(
|
|
|
64
95
|
notebook_name: str,
|
|
65
96
|
url: str,
|
|
66
97
|
description: Optional[str] = None,
|
|
67
|
-
workspace: Optional[str] = None,
|
|
98
|
+
workspace: Optional[str | UUID] = None,
|
|
68
99
|
overwrite: bool = False,
|
|
69
100
|
):
|
|
70
101
|
"""
|
|
@@ -82,16 +113,15 @@ def import_notebook_from_web(
|
|
|
82
113
|
description : str, default=None
|
|
83
114
|
The description of the notebook.
|
|
84
115
|
Defaults to None which does not place a description.
|
|
85
|
-
workspace : str, default=None
|
|
86
|
-
The name of the workspace.
|
|
116
|
+
workspace : str | uuid.UUID, default=None
|
|
117
|
+
The name or ID of the workspace.
|
|
87
118
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
88
119
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
89
120
|
overwrite : bool, default=False
|
|
90
121
|
If set to True, overwrites the existing notebook in the workspace if it exists.
|
|
91
122
|
"""
|
|
92
123
|
|
|
93
|
-
|
|
94
|
-
workspace = fabric.resolve_workspace_name(workspace)
|
|
124
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
95
125
|
|
|
96
126
|
# Fix links to go to the raw github file
|
|
97
127
|
starting_text = "https://github.com/"
|
|
@@ -111,24 +141,26 @@ def import_notebook_from_web(
|
|
|
111
141
|
create_notebook(
|
|
112
142
|
name=notebook_name,
|
|
113
143
|
notebook_content=response.content,
|
|
114
|
-
workspace=
|
|
144
|
+
workspace=workspace_id,
|
|
115
145
|
description=description,
|
|
116
146
|
)
|
|
117
147
|
elif len(dfI_filt) > 0 and overwrite:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
148
|
+
print(f"{icons.info} Overwrite of notebooks is currently not supported.")
|
|
149
|
+
# update_notebook_definition(
|
|
150
|
+
# name=notebook_name, notebook_content=response.content, workspace=workspace
|
|
151
|
+
# )
|
|
121
152
|
else:
|
|
122
153
|
raise ValueError(
|
|
123
|
-
f"{icons.red_dot} The '{notebook_name}' already exists within the '{
|
|
154
|
+
f"{icons.red_dot} The '{notebook_name}' already exists within the '{workspace_name}' workspace and 'overwrite' is set to False."
|
|
124
155
|
)
|
|
125
156
|
|
|
126
157
|
|
|
127
158
|
def create_notebook(
|
|
128
159
|
name: str,
|
|
129
160
|
notebook_content: str,
|
|
161
|
+
type: str = "py",
|
|
130
162
|
description: Optional[str] = None,
|
|
131
|
-
workspace: Optional[str] = None,
|
|
163
|
+
workspace: Optional[str | UUID] = None,
|
|
132
164
|
):
|
|
133
165
|
"""
|
|
134
166
|
Creates a new notebook with a definition within a workspace.
|
|
@@ -139,16 +171,18 @@ def create_notebook(
|
|
|
139
171
|
The name of the notebook to be created.
|
|
140
172
|
notebook_content : str
|
|
141
173
|
The Jupyter notebook content (not in Base64 format).
|
|
174
|
+
type : str, default="py"
|
|
175
|
+
The notebook type.
|
|
142
176
|
description : str, default=None
|
|
143
177
|
The description of the notebook.
|
|
144
178
|
Defaults to None which does not place a description.
|
|
145
|
-
workspace : str, default=None
|
|
146
|
-
The name of the workspace.
|
|
179
|
+
workspace : str | uuid.UUID, default=None
|
|
180
|
+
The name or ID of the workspace.
|
|
147
181
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
148
182
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
149
183
|
"""
|
|
150
184
|
|
|
151
|
-
(
|
|
185
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
152
186
|
client = fabric.FabricRestClient()
|
|
153
187
|
notebook_payload = base64.b64encode(notebook_content)
|
|
154
188
|
|
|
@@ -158,7 +192,7 @@ def create_notebook(
|
|
|
158
192
|
"format": "ipynb",
|
|
159
193
|
"parts": [
|
|
160
194
|
{
|
|
161
|
-
"path": "
|
|
195
|
+
"path": f"{_notebook_prefix}.{type}",
|
|
162
196
|
"payload": notebook_payload,
|
|
163
197
|
"payloadType": "InlineBase64",
|
|
164
198
|
}
|
|
@@ -173,12 +207,12 @@ def create_notebook(
|
|
|
173
207
|
lro(client, response, status_codes=[201, 202])
|
|
174
208
|
|
|
175
209
|
print(
|
|
176
|
-
f"{icons.green_dot} The '{name}' notebook was created within the '{
|
|
210
|
+
f"{icons.green_dot} The '{name}' notebook was created within the '{workspace_name}' workspace."
|
|
177
211
|
)
|
|
178
212
|
|
|
179
213
|
|
|
180
214
|
def update_notebook_definition(
|
|
181
|
-
name: str, notebook_content: str, workspace: Optional[str] = None
|
|
215
|
+
name: str, notebook_content: str, workspace: Optional[str | UUID] = None
|
|
182
216
|
):
|
|
183
217
|
"""
|
|
184
218
|
Updates an existing notebook with a new definition.
|
|
@@ -189,26 +223,26 @@ def update_notebook_definition(
|
|
|
189
223
|
The name of the notebook to be updated.
|
|
190
224
|
notebook_content : str
|
|
191
225
|
The Jupyter notebook content (not in Base64 format).
|
|
192
|
-
workspace : str, default=None
|
|
193
|
-
The name of the workspace.
|
|
226
|
+
workspace : str | uuid.UUID, default=None
|
|
227
|
+
The name or ID of the workspace.
|
|
194
228
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
195
229
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
196
230
|
"""
|
|
197
231
|
|
|
198
|
-
(
|
|
232
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
199
233
|
client = fabric.FabricRestClient()
|
|
200
234
|
notebook_payload = base64.b64encode(notebook_content)
|
|
201
235
|
notebook_id = fabric.resolve_item_id(
|
|
202
|
-
item_name=name, type="Notebook", workspace=
|
|
236
|
+
item_name=name, type="Notebook", workspace=workspace_id
|
|
203
237
|
)
|
|
204
238
|
|
|
239
|
+
type = _get_notebook_type(notebook_name=name, workspace=workspace_id)
|
|
240
|
+
|
|
205
241
|
request_body = {
|
|
206
|
-
"displayName": name,
|
|
207
242
|
"definition": {
|
|
208
|
-
"format": "ipynb",
|
|
209
243
|
"parts": [
|
|
210
244
|
{
|
|
211
|
-
"path": "
|
|
245
|
+
"path": f"{_notebook_prefix}.{type}",
|
|
212
246
|
"payload": notebook_payload,
|
|
213
247
|
"payloadType": "InlineBase64",
|
|
214
248
|
}
|
|
@@ -224,5 +258,5 @@ def update_notebook_definition(
|
|
|
224
258
|
lro(client, response, return_status_code=True)
|
|
225
259
|
|
|
226
260
|
print(
|
|
227
|
-
f"{icons.green_dot} The '{name}' notebook was updated within the '{
|
|
261
|
+
f"{icons.green_dot} The '{name}' notebook was updated within the '{workspace_name}' workspace."
|
|
228
262
|
)
|