semantic-link-labs 0.4.1__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.4.1.dist-info/LICENSE +21 -0
- semantic_link_labs-0.4.1.dist-info/METADATA +22 -0
- semantic_link_labs-0.4.1.dist-info/RECORD +52 -0
- semantic_link_labs-0.4.1.dist-info/WHEEL +5 -0
- semantic_link_labs-0.4.1.dist-info/top_level.txt +1 -0
- sempy_labs/__init__.py +154 -0
- sempy_labs/_ai.py +496 -0
- sempy_labs/_clear_cache.py +39 -0
- sempy_labs/_connections.py +234 -0
- sempy_labs/_dax.py +70 -0
- sempy_labs/_generate_semantic_model.py +280 -0
- sempy_labs/_helper_functions.py +506 -0
- sempy_labs/_icons.py +4 -0
- sempy_labs/_list_functions.py +1372 -0
- sempy_labs/_model_auto_build.py +143 -0
- sempy_labs/_model_bpa.py +1354 -0
- sempy_labs/_model_dependencies.py +341 -0
- sempy_labs/_one_lake_integration.py +155 -0
- sempy_labs/_query_scale_out.py +447 -0
- sempy_labs/_refresh_semantic_model.py +184 -0
- sempy_labs/_tom.py +3766 -0
- sempy_labs/_translations.py +378 -0
- sempy_labs/_vertipaq.py +893 -0
- sempy_labs/directlake/__init__.py +45 -0
- sempy_labs/directlake/_directlake_schema_compare.py +110 -0
- sempy_labs/directlake/_directlake_schema_sync.py +128 -0
- sempy_labs/directlake/_fallback.py +62 -0
- sempy_labs/directlake/_get_directlake_lakehouse.py +69 -0
- sempy_labs/directlake/_get_shared_expression.py +59 -0
- sempy_labs/directlake/_guardrails.py +84 -0
- sempy_labs/directlake/_list_directlake_model_calc_tables.py +54 -0
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +89 -0
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +81 -0
- sempy_labs/directlake/_update_directlake_partition_entity.py +64 -0
- sempy_labs/directlake/_warm_cache.py +210 -0
- sempy_labs/lakehouse/__init__.py +24 -0
- sempy_labs/lakehouse/_get_lakehouse_columns.py +81 -0
- sempy_labs/lakehouse/_get_lakehouse_tables.py +250 -0
- sempy_labs/lakehouse/_lakehouse.py +85 -0
- sempy_labs/lakehouse/_shortcuts.py +296 -0
- sempy_labs/migration/__init__.py +29 -0
- sempy_labs/migration/_create_pqt_file.py +239 -0
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +429 -0
- sempy_labs/migration/_migrate_calctables_to_semantic_model.py +150 -0
- sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +524 -0
- sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +165 -0
- sempy_labs/migration/_migration_validation.py +227 -0
- sempy_labs/migration/_refresh_calc_tables.py +129 -0
- sempy_labs/report/__init__.py +35 -0
- sempy_labs/report/_generate_report.py +253 -0
- sempy_labs/report/_report_functions.py +855 -0
- sempy_labs/report/_report_rebind.py +131 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import sempy
|
|
2
|
+
import sempy.fabric as fabric
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sempy_labs._helper_functions import format_dax_object_name
|
|
5
|
+
from typing import List, Optional, Union
|
|
6
|
+
from anytree import Node, RenderTree
|
|
7
|
+
from sempy._utils._log import log
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_measure_dependencies(dataset: str, workspace: Optional[str] = None):
|
|
11
|
+
"""
|
|
12
|
+
Shows all dependencies for all measures in a semantic model.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
dataset : str
|
|
17
|
+
Name of the semantic model.
|
|
18
|
+
workspace : str, default=None
|
|
19
|
+
The Fabric workspace name.
|
|
20
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
21
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
pandas.DataFrame
|
|
26
|
+
Shows all dependencies for all measures in the semantic model.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
if workspace == None:
|
|
30
|
+
workspace_id = fabric.get_workspace_id()
|
|
31
|
+
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
32
|
+
|
|
33
|
+
dep = fabric.evaluate_dax(
|
|
34
|
+
dataset=dataset,
|
|
35
|
+
workspace=workspace,
|
|
36
|
+
dax_string="""
|
|
37
|
+
SELECT
|
|
38
|
+
[TABLE] AS [Table Name]
|
|
39
|
+
,[OBJECT] AS [Object Name]
|
|
40
|
+
,[OBJECT_TYPE] AS [Object Type]
|
|
41
|
+
,[REFERENCED_TABLE] AS [Referenced Table]
|
|
42
|
+
,[REFERENCED_OBJECT] AS [Referenced Object]
|
|
43
|
+
,[REFERENCED_OBJECT_TYPE] AS [Referenced Object Type]
|
|
44
|
+
FROM $SYSTEM.DISCOVER_CALC_DEPENDENCY
|
|
45
|
+
WHERE [OBJECT_TYPE] = 'MEASURE'
|
|
46
|
+
""",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
dep["Object Type"] = dep["Object Type"].str.capitalize()
|
|
50
|
+
dep["Referenced Object Type"] = dep["Referenced Object Type"].str.capitalize()
|
|
51
|
+
|
|
52
|
+
dep["Full Object Name"] = format_dax_object_name(
|
|
53
|
+
dep["Table Name"], dep["Object Name"]
|
|
54
|
+
)
|
|
55
|
+
dep["Referenced Full Object Name"] = format_dax_object_name(
|
|
56
|
+
dep["Referenced Table"], dep["Referenced Object"]
|
|
57
|
+
)
|
|
58
|
+
dep["Parent Node"] = dep["Object Name"]
|
|
59
|
+
|
|
60
|
+
df = dep
|
|
61
|
+
|
|
62
|
+
df["Done"] = df.apply(
|
|
63
|
+
lambda row: False if row["Referenced Object Type"] == "Measure" else True,
|
|
64
|
+
axis=1,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
while any(df["Done"] == False):
|
|
68
|
+
for i, r in df.iterrows():
|
|
69
|
+
rObjFull = r["Referenced Full Object Name"]
|
|
70
|
+
rObj = r["Referenced Object"]
|
|
71
|
+
if r["Done"] == False:
|
|
72
|
+
dep_filt = dep[dep["Full Object Name"] == rObjFull]
|
|
73
|
+
|
|
74
|
+
for index, dependency in dep_filt.iterrows():
|
|
75
|
+
d = True
|
|
76
|
+
if dependency[5] == "Measure":
|
|
77
|
+
d = False
|
|
78
|
+
df = pd.concat(
|
|
79
|
+
[
|
|
80
|
+
df,
|
|
81
|
+
pd.DataFrame(
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
"Table Name": r["Table Name"],
|
|
85
|
+
"Object Name": r["Object Name"],
|
|
86
|
+
"Object Type": r["Object Type"],
|
|
87
|
+
"Referenced Object": dependency[4],
|
|
88
|
+
"Referenced Table": dependency[3],
|
|
89
|
+
"Referenced Object Type": dependency[5],
|
|
90
|
+
"Done": d,
|
|
91
|
+
"Full Object Name": r["Full Object Name"],
|
|
92
|
+
"Referenced Full Object Name": dependency[
|
|
93
|
+
7
|
|
94
|
+
],
|
|
95
|
+
"Parent Node": rObj,
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
),
|
|
99
|
+
],
|
|
100
|
+
ignore_index=True,
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
df = pd.concat(
|
|
104
|
+
[
|
|
105
|
+
df,
|
|
106
|
+
pd.DataFrame(
|
|
107
|
+
[
|
|
108
|
+
{
|
|
109
|
+
"Table Name": r["Table Name"],
|
|
110
|
+
"Object Name": r["Object Name"],
|
|
111
|
+
"Object Type": r["Object Type"],
|
|
112
|
+
"Referenced Object": dependency[5],
|
|
113
|
+
"Referenced Table": dependency[4],
|
|
114
|
+
"Referenced Object Type": dependency[6],
|
|
115
|
+
"Done": d,
|
|
116
|
+
"Full Object Name": r["Full Object Name"],
|
|
117
|
+
"Referenced Full Object Name": dependency[
|
|
118
|
+
7
|
|
119
|
+
],
|
|
120
|
+
"Parent Node": rObj,
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
),
|
|
124
|
+
],
|
|
125
|
+
ignore_index=True,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
df.loc[i, "Done"] = True
|
|
129
|
+
|
|
130
|
+
df = df.drop(["Done", "Full Object Name", "Referenced Full Object Name"], axis=1)
|
|
131
|
+
|
|
132
|
+
return df
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_model_calc_dependencies(dataset: str, workspace: Optional[str] = None):
|
|
136
|
+
"""
|
|
137
|
+
Shows all dependencies for all objects in a semantic model.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
dataset : str
|
|
142
|
+
Name of the semantic model.
|
|
143
|
+
workspace : str, default=None
|
|
144
|
+
The Fabric workspace name.
|
|
145
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
146
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
pandas.DataFrame
|
|
151
|
+
Shows all dependencies for all objects in the semantic model.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
if workspace == None:
|
|
155
|
+
workspace_id = fabric.get_workspace_id()
|
|
156
|
+
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
157
|
+
|
|
158
|
+
dep = fabric.evaluate_dax(
|
|
159
|
+
dataset=dataset,
|
|
160
|
+
workspace=workspace,
|
|
161
|
+
dax_string="""
|
|
162
|
+
SELECT
|
|
163
|
+
[TABLE] AS [Table Name]
|
|
164
|
+
,[OBJECT] AS [Object Name]
|
|
165
|
+
,[OBJECT_TYPE] AS [Object Type]
|
|
166
|
+
,[EXPRESSION] AS [Expression]
|
|
167
|
+
,[REFERENCED_TABLE] AS [Referenced Table]
|
|
168
|
+
,[REFERENCED_OBJECT] AS [Referenced Object]
|
|
169
|
+
,[REFERENCED_OBJECT_TYPE] AS [Referenced Object Type]
|
|
170
|
+
FROM $SYSTEM.DISCOVER_CALC_DEPENDENCY
|
|
171
|
+
""",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
dep["Object Type"] = dep["Object Type"].str.replace("_", " ").str.title()
|
|
175
|
+
dep["Referenced Object Type"] = (
|
|
176
|
+
dep["Referenced Object Type"].str.replace("_", " ").str.title()
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
dep["Full Object Name"] = format_dax_object_name(
|
|
180
|
+
dep["Table Name"], dep["Object Name"]
|
|
181
|
+
)
|
|
182
|
+
dep["Referenced Full Object Name"] = format_dax_object_name(
|
|
183
|
+
dep["Referenced Table"], dep["Referenced Object"]
|
|
184
|
+
)
|
|
185
|
+
dep["Parent Node"] = dep["Object Name"]
|
|
186
|
+
|
|
187
|
+
df = dep
|
|
188
|
+
|
|
189
|
+
objs = ["Measure", "Calc Column", "Calculation Item", "Calc Table"]
|
|
190
|
+
|
|
191
|
+
df["Done"] = df.apply(
|
|
192
|
+
lambda row: False if row["Referenced Object Type"] in objs else True, axis=1
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
while any(df["Done"] == False):
|
|
196
|
+
for i, r in df.iterrows():
|
|
197
|
+
rObjFull = r["Referenced Full Object Name"]
|
|
198
|
+
rObj = r["Referenced Object"]
|
|
199
|
+
if r["Done"] == False:
|
|
200
|
+
dep_filt = dep[dep["Full Object Name"] == rObjFull]
|
|
201
|
+
|
|
202
|
+
for index, dependency in dep_filt.iterrows():
|
|
203
|
+
d = True
|
|
204
|
+
if dependency[5] in objs:
|
|
205
|
+
d = False
|
|
206
|
+
df = pd.concat(
|
|
207
|
+
[
|
|
208
|
+
df,
|
|
209
|
+
pd.DataFrame(
|
|
210
|
+
[
|
|
211
|
+
{
|
|
212
|
+
"Table Name": r["Table Name"],
|
|
213
|
+
"Object Name": r["Object Name"],
|
|
214
|
+
"Object Type": r["Object Type"],
|
|
215
|
+
"Referenced Object": dependency[4],
|
|
216
|
+
"Referenced Table": dependency[3],
|
|
217
|
+
"Referenced Object Type": dependency[5],
|
|
218
|
+
"Done": d,
|
|
219
|
+
"Full Object Name": r["Full Object Name"],
|
|
220
|
+
"Referenced Full Object Name": dependency[
|
|
221
|
+
7
|
|
222
|
+
],
|
|
223
|
+
"Parent Node": rObj,
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
),
|
|
227
|
+
],
|
|
228
|
+
ignore_index=True,
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
df = pd.concat(
|
|
232
|
+
[
|
|
233
|
+
df,
|
|
234
|
+
pd.DataFrame(
|
|
235
|
+
[
|
|
236
|
+
{
|
|
237
|
+
"Table Name": r["Table Name"],
|
|
238
|
+
"Object Name": r["Object Name"],
|
|
239
|
+
"Object Type": r["Object Type"],
|
|
240
|
+
"Referenced Object": dependency[5],
|
|
241
|
+
"Referenced Table": dependency[4],
|
|
242
|
+
"Referenced Object Type": dependency[6],
|
|
243
|
+
"Done": d,
|
|
244
|
+
"Full Object Name": r["Full Object Name"],
|
|
245
|
+
"Referenced Full Object Name": dependency[
|
|
246
|
+
7
|
|
247
|
+
],
|
|
248
|
+
"Parent Node": rObj,
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
),
|
|
252
|
+
],
|
|
253
|
+
ignore_index=True,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
df.loc[i, "Done"] = True
|
|
257
|
+
|
|
258
|
+
df = df.drop(["Done"], axis=1)
|
|
259
|
+
|
|
260
|
+
return df
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@log
|
|
264
|
+
def measure_dependency_tree(
|
|
265
|
+
dataset: str, measure_name: str, workspace: Optional[str] = None
|
|
266
|
+
):
|
|
267
|
+
"""
|
|
268
|
+
Prints a measure dependency tree of all dependent objects for a measure in a semantic model.
|
|
269
|
+
|
|
270
|
+
Parameters
|
|
271
|
+
----------
|
|
272
|
+
dataset : str
|
|
273
|
+
Name of the semantic model.
|
|
274
|
+
measure_name : str
|
|
275
|
+
Name of the measure.
|
|
276
|
+
workspace : str, default=None
|
|
277
|
+
The Fabric workspace name.
|
|
278
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
279
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
280
|
+
|
|
281
|
+
Returns
|
|
282
|
+
-------
|
|
283
|
+
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
if workspace == None:
|
|
287
|
+
workspace_id = fabric.get_workspace_id()
|
|
288
|
+
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
289
|
+
|
|
290
|
+
dfM = fabric.list_measures(dataset=dataset, workspace=workspace)
|
|
291
|
+
dfM_filt = dfM[dfM["Measure Name"] == measure_name]
|
|
292
|
+
|
|
293
|
+
if len(dfM_filt) == 0:
|
|
294
|
+
print(
|
|
295
|
+
f"The '{measure_name}' measure does not exist in the '{dataset}' semantic model in the '{workspace}' workspace."
|
|
296
|
+
)
|
|
297
|
+
return
|
|
298
|
+
|
|
299
|
+
md = get_measure_dependencies(dataset, workspace)
|
|
300
|
+
df_filt = md[md["Object Name"] == measure_name]
|
|
301
|
+
|
|
302
|
+
# Create a dictionary to hold references to nodes
|
|
303
|
+
node_dict = {}
|
|
304
|
+
measureIcon = "\u2211"
|
|
305
|
+
tableIcon = "\u229E"
|
|
306
|
+
columnIcon = "\u229F"
|
|
307
|
+
|
|
308
|
+
# Populate the tree
|
|
309
|
+
for _, row in df_filt.iterrows():
|
|
310
|
+
# measure_name = row['Object Name']
|
|
311
|
+
ref_obj_table_name = row["Referenced Table"]
|
|
312
|
+
ref_obj_name = row["Referenced Object"]
|
|
313
|
+
ref_obj_type = row["Referenced Object Type"]
|
|
314
|
+
parent_node_name = row["Parent Node"]
|
|
315
|
+
|
|
316
|
+
# Create or get the parent node
|
|
317
|
+
parent_node = node_dict.get(parent_node_name)
|
|
318
|
+
if parent_node is None:
|
|
319
|
+
parent_node = Node(parent_node_name)
|
|
320
|
+
node_dict[parent_node_name] = parent_node
|
|
321
|
+
parent_node.custom_property = measureIcon + " "
|
|
322
|
+
|
|
323
|
+
# Create the child node
|
|
324
|
+
child_node_name = ref_obj_name
|
|
325
|
+
child_node = Node(child_node_name, parent=parent_node)
|
|
326
|
+
if ref_obj_type == "Column":
|
|
327
|
+
child_node.custom_property = columnIcon + " '" + ref_obj_table_name + "'"
|
|
328
|
+
elif ref_obj_type == "Table":
|
|
329
|
+
child_node.custom_property = tableIcon + " "
|
|
330
|
+
elif ref_obj_type == "Measure":
|
|
331
|
+
child_node.custom_property = measureIcon + " "
|
|
332
|
+
|
|
333
|
+
# Update the dictionary with the child node
|
|
334
|
+
node_dict[child_node_name] = child_node
|
|
335
|
+
|
|
336
|
+
# Visualize the tree structure using RenderTree
|
|
337
|
+
for pre, _, node in RenderTree(node_dict[measure_name]):
|
|
338
|
+
if tableIcon in node.custom_property:
|
|
339
|
+
print(f"{pre}{node.custom_property}'{node.name}'")
|
|
340
|
+
else:
|
|
341
|
+
print(f"{pre}{node.custom_property}[{node.name}]")
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import sempy.fabric as fabric
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from sempy._utils._log import log
|
|
5
|
+
from sempy_labs._helper_functions import resolve_workspace_name_and_id
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@log
|
|
9
|
+
def export_model_to_onelake(
|
|
10
|
+
dataset: str,
|
|
11
|
+
workspace: Optional[str] = None,
|
|
12
|
+
destination_lakehouse: Optional[str] = None,
|
|
13
|
+
destination_workspace: Optional[str] = None,
|
|
14
|
+
):
|
|
15
|
+
"""
|
|
16
|
+
Exports a semantic model's tables to delta tables in the lakehouse. Creates shortcuts to the tables if a lakehouse is specified.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
dataset : str
|
|
21
|
+
Name of the semantic model.
|
|
22
|
+
workspace : str, default=None
|
|
23
|
+
The Fabric workspace name.
|
|
24
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
25
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
26
|
+
destination_lakehouse : str, default=None
|
|
27
|
+
The name of the Fabric lakehouse where shortcuts will be created to access the delta tables created by the export. If the lakehouse specified does not exist, one will be created with that name. If no lakehouse is specified, shortcuts will not be created.
|
|
28
|
+
destination_workspace : str, default=None
|
|
29
|
+
The name of the Fabric workspace in which the lakehouse resides.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
33
|
+
|
|
34
|
+
if destination_workspace == None:
|
|
35
|
+
destination_workspace = workspace
|
|
36
|
+
destination_workspace_id = workspace_id
|
|
37
|
+
else:
|
|
38
|
+
destination_workspace_id = fabric.resolve_workspace_id(destination_workspace)
|
|
39
|
+
|
|
40
|
+
dfD = fabric.list_datasets(workspace=workspace)
|
|
41
|
+
dfD_filt = dfD[dfD["Dataset Name"] == dataset]
|
|
42
|
+
|
|
43
|
+
if len(dfD_filt) == 0:
|
|
44
|
+
print(
|
|
45
|
+
f"The '{dataset}' semantic model does not exist in the '{workspace}' workspace."
|
|
46
|
+
)
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
tmsl = f"""
|
|
50
|
+
{{
|
|
51
|
+
'export': {{
|
|
52
|
+
'layout': 'delta',
|
|
53
|
+
'type': 'full',
|
|
54
|
+
'objects': [
|
|
55
|
+
{{
|
|
56
|
+
'database': '{dataset}'
|
|
57
|
+
}}
|
|
58
|
+
]
|
|
59
|
+
}}
|
|
60
|
+
}}
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Export model's tables as delta tables
|
|
64
|
+
try:
|
|
65
|
+
fabric.execute_tmsl(script=tmsl, workspace=workspace)
|
|
66
|
+
print(
|
|
67
|
+
f"The '{dataset}' semantic model's tables have been exported as delta tables to the '{workspace}' workspace.\n"
|
|
68
|
+
)
|
|
69
|
+
except:
|
|
70
|
+
print(
|
|
71
|
+
f"ERROR: The '{dataset}' semantic model's tables have not been exported as delta tables to the '{workspace}' workspace."
|
|
72
|
+
)
|
|
73
|
+
print(
|
|
74
|
+
f"Make sure you enable OneLake integration for the '{dataset}' semantic model. Follow the instructions here: https://learn.microsoft.com/power-bi/enterprise/onelake-integration-overview#enable-onelake-integration"
|
|
75
|
+
)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
# Create shortcuts if destination lakehouse is specified
|
|
79
|
+
if destination_lakehouse is not None:
|
|
80
|
+
# Destination...
|
|
81
|
+
dfI_Dest = fabric.list_items(workspace=destination_workspace, type="Lakehouse")
|
|
82
|
+
dfI_filt = dfI_Dest[(dfI_Dest["Display Name"] == destination_lakehouse)]
|
|
83
|
+
|
|
84
|
+
if len(dfI_filt) == 0:
|
|
85
|
+
print(
|
|
86
|
+
f"The '{destination_lakehouse}' lakehouse does not exist within the '{destination_workspace}' workspace."
|
|
87
|
+
)
|
|
88
|
+
# Create lakehouse
|
|
89
|
+
destination_lakehouse_id = fabric.create_lakehouse(
|
|
90
|
+
display_name=destination_lakehouse, workspace=destination_workspace
|
|
91
|
+
)
|
|
92
|
+
print(
|
|
93
|
+
f"The '{destination_lakehouse}' lakehouse has been created within the '{destination_workspace}' workspace.\n"
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
destination_lakehouse_id = dfI_filt["Id"].iloc[0]
|
|
97
|
+
|
|
98
|
+
# Source...
|
|
99
|
+
dfI_Source = fabric.list_items(workspace=workspace, type="SemanticModel")
|
|
100
|
+
dfI_filtSource = dfI_Source[(dfI_Source["Display Name"] == dataset)]
|
|
101
|
+
sourceLakehouseId = dfI_filtSource["Id"].iloc[0]
|
|
102
|
+
|
|
103
|
+
# Valid tables
|
|
104
|
+
dfP = fabric.list_partitions(
|
|
105
|
+
dataset=dataset,
|
|
106
|
+
workspace=workspace,
|
|
107
|
+
additional_xmla_properties=["Parent.SystemManaged"],
|
|
108
|
+
)
|
|
109
|
+
dfP_filt = dfP[
|
|
110
|
+
(dfP["Mode"] == "Import")
|
|
111
|
+
& (dfP["Source Type"] != "CalculationGroup")
|
|
112
|
+
& (dfP["Parent System Managed"] == False)
|
|
113
|
+
]
|
|
114
|
+
dfC = fabric.list_columns(dataset=dataset, workspace=workspace)
|
|
115
|
+
tmc = pd.DataFrame(dfP.groupby("Table Name")["Mode"].nunique()).reset_index()
|
|
116
|
+
oneMode = tmc[tmc["Mode"] == 1]
|
|
117
|
+
tableAll = dfP_filt[
|
|
118
|
+
dfP_filt["Table Name"].isin(dfC["Table Name"].values)
|
|
119
|
+
& (dfP_filt["Table Name"].isin(oneMode["Table Name"].values))
|
|
120
|
+
]
|
|
121
|
+
tables = tableAll["Table Name"].unique()
|
|
122
|
+
|
|
123
|
+
client = fabric.FabricRestClient()
|
|
124
|
+
|
|
125
|
+
print("Creating shortcuts...\n")
|
|
126
|
+
for tableName in tables:
|
|
127
|
+
tablePath = "Tables/" + tableName
|
|
128
|
+
shortcutName = tableName.replace(" ", "")
|
|
129
|
+
request_body = {
|
|
130
|
+
"path": "Tables",
|
|
131
|
+
"name": shortcutName,
|
|
132
|
+
"target": {
|
|
133
|
+
"oneLake": {
|
|
134
|
+
"workspaceId": workspace_id,
|
|
135
|
+
"itemId": sourceLakehouseId,
|
|
136
|
+
"path": tablePath,
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
response = client.post(
|
|
143
|
+
f"/v1/workspaces/{destination_workspace_id}/items/{destination_lakehouse_id}/shortcuts",
|
|
144
|
+
json=request_body,
|
|
145
|
+
)
|
|
146
|
+
if response.status_code == 201:
|
|
147
|
+
print(
|
|
148
|
+
f"\u2022 The shortcut '{shortcutName}' was created in the '{destination_lakehouse}' lakehouse within the '{destination_workspace}' workspace. It is based on the '{tableName}' table in the '{dataset}' semantic model within the '{workspace}' workspace.\n"
|
|
149
|
+
)
|
|
150
|
+
else:
|
|
151
|
+
print(response.status_code)
|
|
152
|
+
except:
|
|
153
|
+
print(
|
|
154
|
+
f"ERROR: Failed to create a shortcut for the '{tableName}' table."
|
|
155
|
+
)
|