semantic-link-labs 0.7.2__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.
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.3.dist-info}/METADATA +3 -2
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.3.dist-info}/RECORD +34 -27
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.3.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +60 -3
- sempy_labs/_bpa_translation/_translations_sv-SE.po +914 -0
- sempy_labs/_clear_cache.py +298 -3
- sempy_labs/_dataflows.py +130 -0
- sempy_labs/_deployment_pipelines.py +171 -0
- sempy_labs/_generate_semantic_model.py +148 -27
- sempy_labs/_git.py +380 -0
- sempy_labs/_helper_functions.py +57 -0
- sempy_labs/_list_functions.py +144 -121
- sempy_labs/_model_bpa.py +85 -83
- sempy_labs/_model_bpa_bulk.py +3 -1
- sempy_labs/_model_bpa_rules.py +788 -800
- sempy_labs/_sql.py +96 -0
- sempy_labs/_translations.py +0 -1
- sempy_labs/_workspace_identity.py +66 -0
- sempy_labs/directlake/__init__.py +2 -0
- sempy_labs/directlake/_directlake_schema_compare.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 +91 -52
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.3.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.7.2.dist-info → semantic_link_labs-0.7.3.dist-info}/top_level.txt +0 -0
sempy_labs/_list_functions.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import sempy.fabric as fabric
|
|
2
2
|
from sempy_labs._helper_functions import (
|
|
3
3
|
resolve_workspace_name_and_id,
|
|
4
|
-
resolve_lakehouse_name,
|
|
5
4
|
create_relationship_name,
|
|
6
5
|
resolve_lakehouse_id,
|
|
7
6
|
resolve_dataset_id,
|
|
@@ -86,7 +85,9 @@ def get_object_level_security(
|
|
|
86
85
|
return df
|
|
87
86
|
|
|
88
87
|
|
|
89
|
-
def list_tables(
|
|
88
|
+
def list_tables(
|
|
89
|
+
dataset: str, workspace: Optional[str] = None, extended: Optional[bool] = False
|
|
90
|
+
) -> pd.DataFrame:
|
|
90
91
|
"""
|
|
91
92
|
Shows a semantic model's tables and their properties.
|
|
92
93
|
|
|
@@ -98,6 +99,8 @@ def list_tables(dataset: str, workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
98
99
|
The Fabric workspace name.
|
|
99
100
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
100
101
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
102
|
+
extended : bool, default=False
|
|
103
|
+
Adds additional columns including Vertipaq statistics.
|
|
101
104
|
|
|
102
105
|
Returns
|
|
103
106
|
-------
|
|
@@ -105,18 +108,136 @@ def list_tables(dataset: str, workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
105
108
|
A pandas dataframe showing the semantic model's tables and their properties.
|
|
106
109
|
"""
|
|
107
110
|
|
|
111
|
+
from sempy_labs.tom import connect_semantic_model
|
|
112
|
+
|
|
108
113
|
workspace = fabric.resolve_workspace_name(workspace)
|
|
109
114
|
|
|
110
|
-
df =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
df = pd.DataFrame(
|
|
116
|
+
columns=[
|
|
117
|
+
"Name",
|
|
118
|
+
"Description",
|
|
119
|
+
"Hidden",
|
|
120
|
+
"Data Category",
|
|
121
|
+
"Type",
|
|
122
|
+
"Refresh Policy",
|
|
123
|
+
"Source Expression",
|
|
124
|
+
]
|
|
114
125
|
)
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
with connect_semantic_model(
|
|
128
|
+
dataset=dataset, workspace=workspace, readonly=True
|
|
129
|
+
) as tom:
|
|
130
|
+
if extended:
|
|
131
|
+
dict_df = fabric.evaluate_dax(
|
|
132
|
+
dataset=dataset,
|
|
133
|
+
workspace=workspace,
|
|
134
|
+
dax_string="""
|
|
135
|
+
EVALUATE SELECTCOLUMNS(FILTER(INFO.STORAGETABLECOLUMNS(), [COLUMN_TYPE] = "BASIC_DATA"),[DIMENSION_NAME],[DICTIONARY_SIZE])
|
|
136
|
+
""",
|
|
137
|
+
)
|
|
138
|
+
dict_sum = dict_df.groupby("[DIMENSION_NAME]")["[DICTIONARY_SIZE]"].sum()
|
|
139
|
+
data = fabric.evaluate_dax(
|
|
140
|
+
dataset=dataset,
|
|
141
|
+
workspace=workspace,
|
|
142
|
+
dax_string="""EVALUATE SELECTCOLUMNS(INFO.STORAGETABLECOLUMNSEGMENTS(),[TABLE_ID],[DIMENSION_NAME],[USED_SIZE])""",
|
|
143
|
+
)
|
|
144
|
+
data_sum = (
|
|
145
|
+
data[
|
|
146
|
+
~data["[TABLE_ID]"].str.startswith("R$")
|
|
147
|
+
& ~data["[TABLE_ID]"].str.startswith("U$")
|
|
148
|
+
& ~data["[TABLE_ID]"].str.startswith("H$")
|
|
149
|
+
]
|
|
150
|
+
.groupby("[DIMENSION_NAME]")["[USED_SIZE]"]
|
|
151
|
+
.sum()
|
|
152
|
+
)
|
|
153
|
+
hier_sum = (
|
|
154
|
+
data[data["[TABLE_ID]"].str.startswith("H$")]
|
|
155
|
+
.groupby("[DIMENSION_NAME]")["[USED_SIZE]"]
|
|
156
|
+
.sum()
|
|
157
|
+
)
|
|
158
|
+
rel_sum = (
|
|
159
|
+
data[data["[TABLE_ID]"].str.startswith("R$")]
|
|
160
|
+
.groupby("[DIMENSION_NAME]")["[USED_SIZE]"]
|
|
161
|
+
.sum()
|
|
162
|
+
)
|
|
163
|
+
uh_sum = (
|
|
164
|
+
data[data["[TABLE_ID]"].str.startswith("U$")]
|
|
165
|
+
.groupby("[DIMENSION_NAME]")["[USED_SIZE]"]
|
|
166
|
+
.sum()
|
|
167
|
+
)
|
|
168
|
+
rc = fabric.evaluate_dax(
|
|
169
|
+
dataset=dataset,
|
|
170
|
+
workspace=workspace,
|
|
171
|
+
dax_string="""
|
|
172
|
+
SELECT [DIMENSION_NAME],[DIMENSION_CARDINALITY] FROM $SYSTEM.MDSCHEMA_DIMENSIONS
|
|
173
|
+
""",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
rows = []
|
|
177
|
+
for t in tom.model.Tables:
|
|
178
|
+
t_name = t.Name
|
|
179
|
+
t_type = (
|
|
180
|
+
"Calculation Group"
|
|
181
|
+
if t.CalculationGroup
|
|
182
|
+
else (
|
|
183
|
+
"Calculated Table"
|
|
184
|
+
if tom.is_calculated_table(table_name=t.Name)
|
|
185
|
+
else "Table"
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
ref = bool(t.RefreshPolicy)
|
|
189
|
+
ref_se = t.RefreshPolicy.SourceExpression if ref else None
|
|
190
|
+
|
|
191
|
+
new_data = {
|
|
192
|
+
"Name": t_name,
|
|
193
|
+
"Description": t.Description,
|
|
194
|
+
"Hidden": t.IsHidden,
|
|
195
|
+
"Data Category": t.DataCategory,
|
|
196
|
+
"Type": t_type,
|
|
197
|
+
"Refresh Policy": ref,
|
|
198
|
+
"Source Expression": ref_se,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if extended:
|
|
202
|
+
dict_size = dict_sum.get(t_name, 0)
|
|
203
|
+
data_size = data_sum.get(t_name, 0)
|
|
204
|
+
h_size = hier_sum.get(t_name, 0)
|
|
205
|
+
r_size = rel_sum.get(t_name, 0)
|
|
206
|
+
u_size = uh_sum.get(t_name, 0)
|
|
207
|
+
total_size = data_size + dict_size + h_size + r_size + u_size
|
|
208
|
+
|
|
209
|
+
new_data.update(
|
|
210
|
+
{
|
|
211
|
+
"Row Count": (
|
|
212
|
+
rc[rc["DIMENSION_NAME"] == t_name][
|
|
213
|
+
"DIMENSION_CARDINALITY"
|
|
214
|
+
].iloc[0]
|
|
215
|
+
if not rc.empty
|
|
216
|
+
else 0
|
|
217
|
+
),
|
|
218
|
+
"Total Size": total_size,
|
|
219
|
+
"Dictionary Size": dict_size,
|
|
220
|
+
"Data Size": data_size,
|
|
221
|
+
"Hierarchy Size": h_size,
|
|
222
|
+
"Relationship Size": r_size,
|
|
223
|
+
"User Hierarchy Size": u_size,
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
rows.append(new_data)
|
|
228
|
+
|
|
229
|
+
int_cols = [
|
|
230
|
+
"Row Count",
|
|
231
|
+
"Total Size",
|
|
232
|
+
"Dictionary Size",
|
|
233
|
+
"Data Size",
|
|
234
|
+
"Hierarchy Size",
|
|
235
|
+
"Relationship Size",
|
|
236
|
+
"User Hierarchy Size",
|
|
237
|
+
]
|
|
238
|
+
df[int_cols] = df[int_cols].astype(int)
|
|
239
|
+
|
|
240
|
+
df = pd.DataFrame(rows)
|
|
120
241
|
|
|
121
242
|
return df
|
|
122
243
|
|
|
@@ -880,14 +1001,10 @@ def list_eventstreams(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
880
1001
|
|
|
881
1002
|
for r in responses:
|
|
882
1003
|
for v in r.get("value", []):
|
|
883
|
-
model_id = v.get("id")
|
|
884
|
-
modelName = v.get("displayName")
|
|
885
|
-
desc = v.get("description")
|
|
886
|
-
|
|
887
1004
|
new_data = {
|
|
888
|
-
"Eventstream Name":
|
|
889
|
-
"Eventstream ID":
|
|
890
|
-
"Description":
|
|
1005
|
+
"Eventstream Name": v.get("displayName"),
|
|
1006
|
+
"Eventstream ID": v.get("id"),
|
|
1007
|
+
"Description": v.get("description"),
|
|
891
1008
|
}
|
|
892
1009
|
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
893
1010
|
|
|
@@ -1030,10 +1147,6 @@ def create_warehouse(
|
|
|
1030
1147
|
The Fabric workspace name.
|
|
1031
1148
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1032
1149
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1033
|
-
|
|
1034
|
-
Returns
|
|
1035
|
-
-------
|
|
1036
|
-
|
|
1037
1150
|
"""
|
|
1038
1151
|
|
|
1039
1152
|
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
@@ -1045,11 +1158,11 @@ def create_warehouse(
|
|
|
1045
1158
|
|
|
1046
1159
|
client = fabric.FabricRestClient()
|
|
1047
1160
|
response = client.post(
|
|
1048
|
-
f"/v1/workspaces/{workspace_id}/warehouses/", json=request_body
|
|
1161
|
+
f"/v1/workspaces/{workspace_id}/warehouses/", json=request_body
|
|
1049
1162
|
)
|
|
1050
1163
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1164
|
+
lro(client, response, status_codes=[201, 202])
|
|
1165
|
+
|
|
1053
1166
|
print(
|
|
1054
1167
|
f"{icons.green_dot} The '{warehouse}' warehouse has been created within the '{workspace}' workspace."
|
|
1055
1168
|
)
|
|
@@ -1216,44 +1329,6 @@ def list_relationships(
|
|
|
1216
1329
|
return dfR
|
|
1217
1330
|
|
|
1218
1331
|
|
|
1219
|
-
def list_dataflow_storage_accounts() -> pd.DataFrame:
|
|
1220
|
-
"""
|
|
1221
|
-
Shows the accessible dataflow storage accounts.
|
|
1222
|
-
|
|
1223
|
-
Parameters
|
|
1224
|
-
----------
|
|
1225
|
-
|
|
1226
|
-
Returns
|
|
1227
|
-
-------
|
|
1228
|
-
pandas.DataFrame
|
|
1229
|
-
A pandas dataframe showing the accessible dataflow storage accounts.
|
|
1230
|
-
"""
|
|
1231
|
-
|
|
1232
|
-
df = pd.DataFrame(
|
|
1233
|
-
columns=[
|
|
1234
|
-
"Dataflow Storage Account ID",
|
|
1235
|
-
"Dataflow Storage Account Name",
|
|
1236
|
-
"Enabled",
|
|
1237
|
-
]
|
|
1238
|
-
)
|
|
1239
|
-
client = fabric.PowerBIRestClient()
|
|
1240
|
-
response = client.get("/v1.0/myorg/dataflowStorageAccounts")
|
|
1241
|
-
if response.status_code != 200:
|
|
1242
|
-
raise FabricHTTPException(response)
|
|
1243
|
-
|
|
1244
|
-
for v in response.json().get("value", []):
|
|
1245
|
-
new_data = {
|
|
1246
|
-
"Dataflow Storage Account ID": v.get("id"),
|
|
1247
|
-
"Dataflow Storage Account Name": v.get("name"),
|
|
1248
|
-
"Enabled": v.get("isEnabled"),
|
|
1249
|
-
}
|
|
1250
|
-
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
|
|
1251
|
-
|
|
1252
|
-
df["Enabled"] = df["Enabled"].astype(bool)
|
|
1253
|
-
|
|
1254
|
-
return df
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
1332
|
def list_kpis(dataset: str, workspace: Optional[str] = None) -> pd.DataFrame:
|
|
1258
1333
|
"""
|
|
1259
1334
|
Shows a semantic model's KPIs and their properties.
|
|
@@ -1749,9 +1824,6 @@ def create_custom_pool(
|
|
|
1749
1824
|
The name of the Fabric workspace.
|
|
1750
1825
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1751
1826
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1752
|
-
|
|
1753
|
-
Returns
|
|
1754
|
-
-------
|
|
1755
1827
|
"""
|
|
1756
1828
|
|
|
1757
1829
|
# https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/create-workspace-custom-pool
|
|
@@ -1775,10 +1847,10 @@ def create_custom_pool(
|
|
|
1775
1847
|
|
|
1776
1848
|
client = fabric.FabricRestClient()
|
|
1777
1849
|
response = client.post(
|
|
1778
|
-
f"/v1/workspaces/{workspace_id}/spark/pools", json=request_body
|
|
1850
|
+
f"/v1/workspaces/{workspace_id}/spark/pools", json=request_body
|
|
1779
1851
|
)
|
|
1780
1852
|
|
|
1781
|
-
if response.status_code !=
|
|
1853
|
+
if response.status_code != 201:
|
|
1782
1854
|
raise FabricHTTPException(response)
|
|
1783
1855
|
print(
|
|
1784
1856
|
f"{icons.green_dot} The '{pool_name}' spark pool has been created within the '{workspace}' workspace."
|
|
@@ -1832,9 +1904,6 @@ def update_custom_pool(
|
|
|
1832
1904
|
The name of the Fabric workspace.
|
|
1833
1905
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1834
1906
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1835
|
-
|
|
1836
|
-
Returns
|
|
1837
|
-
-------
|
|
1838
1907
|
"""
|
|
1839
1908
|
|
|
1840
1909
|
# https://learn.microsoft.com/en-us/rest/api/fabric/spark/custom-pools/update-workspace-custom-pool?tabs=HTTP
|
|
@@ -1907,9 +1976,6 @@ def delete_custom_pool(pool_name: str, workspace: Optional[str] = None):
|
|
|
1907
1976
|
The name of the Fabric workspace.
|
|
1908
1977
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1909
1978
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1910
|
-
|
|
1911
|
-
Returns
|
|
1912
|
-
-------
|
|
1913
1979
|
"""
|
|
1914
1980
|
|
|
1915
1981
|
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
@@ -1945,15 +2011,16 @@ def assign_workspace_to_capacity(capacity_name: str, workspace: Optional[str] =
|
|
|
1945
2011
|
The name of the Fabric workspace.
|
|
1946
2012
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1947
2013
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1948
|
-
|
|
1949
|
-
Returns
|
|
1950
|
-
-------
|
|
1951
2014
|
"""
|
|
1952
2015
|
|
|
1953
2016
|
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
1954
2017
|
|
|
1955
2018
|
dfC = fabric.list_capacities()
|
|
1956
2019
|
dfC_filt = dfC[dfC["Display Name"] == capacity_name]
|
|
2020
|
+
|
|
2021
|
+
if len(dfC_filt) == 0:
|
|
2022
|
+
raise ValueError(f"{icons.red_dot} The '{capacity_name}' capacity does not exist.")
|
|
2023
|
+
|
|
1957
2024
|
capacity_id = dfC_filt["Id"].iloc[0]
|
|
1958
2025
|
|
|
1959
2026
|
request_body = {"capacityId": capacity_id}
|
|
@@ -1962,7 +2029,6 @@ def assign_workspace_to_capacity(capacity_name: str, workspace: Optional[str] =
|
|
|
1962
2029
|
response = client.post(
|
|
1963
2030
|
f"/v1/workspaces/{workspace_id}/assignToCapacity",
|
|
1964
2031
|
json=request_body,
|
|
1965
|
-
lro_wait=True,
|
|
1966
2032
|
)
|
|
1967
2033
|
|
|
1968
2034
|
if response.status_code not in [200, 202]:
|
|
@@ -1982,9 +2048,6 @@ def unassign_workspace_from_capacity(workspace: Optional[str] = None):
|
|
|
1982
2048
|
The name of the Fabric workspace.
|
|
1983
2049
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
1984
2050
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
1985
|
-
|
|
1986
|
-
Returns
|
|
1987
|
-
-------
|
|
1988
2051
|
"""
|
|
1989
2052
|
|
|
1990
2053
|
# https://learn.microsoft.com/en-us/rest/api/fabric/core/workspaces/unassign-from-capacity?tabs=HTTP
|
|
@@ -1992,7 +2055,7 @@ def unassign_workspace_from_capacity(workspace: Optional[str] = None):
|
|
|
1992
2055
|
|
|
1993
2056
|
client = fabric.FabricRestClient()
|
|
1994
2057
|
response = client.post(
|
|
1995
|
-
f"/v1/workspaces/{workspace_id}/unassignFromCapacity"
|
|
2058
|
+
f"/v1/workspaces/{workspace_id}/unassignFromCapacity"
|
|
1996
2059
|
)
|
|
1997
2060
|
|
|
1998
2061
|
if response.status_code not in [200, 202]:
|
|
@@ -2357,46 +2420,6 @@ def list_workspace_users(workspace: Optional[str] = None) -> pd.DataFrame:
|
|
|
2357
2420
|
return df
|
|
2358
2421
|
|
|
2359
2422
|
|
|
2360
|
-
def assign_workspace_to_dataflow_storage(
|
|
2361
|
-
dataflow_storage_account: str, workspace: Optional[str] = None
|
|
2362
|
-
):
|
|
2363
|
-
"""
|
|
2364
|
-
Assigns a dataflow storage account to a workspace.
|
|
2365
|
-
|
|
2366
|
-
Parameters
|
|
2367
|
-
----------
|
|
2368
|
-
dataflow_storage_account : str
|
|
2369
|
-
The name of the dataflow storage account.
|
|
2370
|
-
workspace : str, default=None
|
|
2371
|
-
The name of the workspace.
|
|
2372
|
-
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
2373
|
-
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
2374
|
-
|
|
2375
|
-
Returns
|
|
2376
|
-
-------
|
|
2377
|
-
"""
|
|
2378
|
-
|
|
2379
|
-
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
2380
|
-
|
|
2381
|
-
df = list_dataflow_storage_accounts()
|
|
2382
|
-
df_filt = df[df["Dataflow Storage Account Name"] == dataflow_storage_account]
|
|
2383
|
-
dataflow_storage_id = df_filt["Dataflow Storage Account ID"].iloc[0]
|
|
2384
|
-
|
|
2385
|
-
client = fabric.PowerBIRestClient()
|
|
2386
|
-
|
|
2387
|
-
request_body = {"dataflowStorageId": dataflow_storage_id}
|
|
2388
|
-
|
|
2389
|
-
response = client.post(
|
|
2390
|
-
f"/v1.0/myorg/groups/{workspace_id}/AssignToDataflowStorage", json=request_body
|
|
2391
|
-
)
|
|
2392
|
-
|
|
2393
|
-
if response.status_code != 200:
|
|
2394
|
-
raise FabricHTTPException(response)
|
|
2395
|
-
print(
|
|
2396
|
-
f"{icons.green_dot} The '{dataflow_storage_account}' dataflow storage account has been assigned to the '{workspace}' workspacce."
|
|
2397
|
-
)
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
2423
|
def list_capacities() -> pd.DataFrame:
|
|
2401
2424
|
"""
|
|
2402
2425
|
Shows the capacities and their properties.
|
sempy_labs/_model_bpa.py
CHANGED
|
@@ -21,7 +21,6 @@ from sempy._utils._log import log
|
|
|
21
21
|
import sempy_labs._icons as icons
|
|
22
22
|
from pyspark.sql.functions import col, flatten
|
|
23
23
|
from pyspark.sql.types import StructType, StructField, StringType
|
|
24
|
-
import polib
|
|
25
24
|
import os
|
|
26
25
|
|
|
27
26
|
|
|
@@ -64,8 +63,8 @@ def run_model_bpa(
|
|
|
64
63
|
pandas.DataFrame
|
|
65
64
|
A pandas dataframe in HTML format showing semantic model objects which violated the best practice analyzer rules.
|
|
66
65
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
|
|
67
|
+
import polib
|
|
69
68
|
|
|
70
69
|
if "extend" in kwargs:
|
|
71
70
|
print(
|
|
@@ -108,6 +107,7 @@ def run_model_bpa(
|
|
|
108
107
|
"zu-ZA",
|
|
109
108
|
"am-ET",
|
|
110
109
|
"ar-AE",
|
|
110
|
+
"sv-SE",
|
|
111
111
|
]
|
|
112
112
|
|
|
113
113
|
# Map languages to the closest language (first 2 letters matching)
|
|
@@ -162,86 +162,86 @@ def run_model_bpa(
|
|
|
162
162
|
entry.msgstr
|
|
163
163
|
)
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
rules_temp = rule_file.copy()
|
|
167
|
-
rules_temp = rules_temp.drop(["Expression", "URL", "Severity"], axis=1)
|
|
168
|
-
|
|
169
|
-
schema = StructType(
|
|
170
|
-
[
|
|
171
|
-
StructField("Category", StringType(), True),
|
|
172
|
-
StructField("Scope", StringType(), True),
|
|
173
|
-
StructField("Rule Name", StringType(), True),
|
|
174
|
-
StructField("Description", StringType(), True),
|
|
175
|
-
]
|
|
176
|
-
)
|
|
165
|
+
translated = False
|
|
177
166
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
167
|
+
# Translations
|
|
168
|
+
if language is not None and rules is None and language in language_list:
|
|
169
|
+
rules = model_bpa_rules(dependencies=dep)
|
|
170
|
+
translate_using_po(rules)
|
|
171
|
+
translated = True
|
|
172
|
+
if rules is None:
|
|
173
|
+
rules = model_bpa_rules(dependencies=dep)
|
|
174
|
+
if language is not None and not translated:
|
|
175
|
+
|
|
176
|
+
def translate_using_spark(rule_file):
|
|
177
|
+
|
|
178
|
+
from synapse.ml.services import Translate
|
|
179
|
+
|
|
180
|
+
rules_temp = rule_file.copy()
|
|
181
|
+
rules_temp = rules_temp.drop(["Expression", "URL", "Severity"], axis=1)
|
|
182
|
+
|
|
183
|
+
schema = StructType(
|
|
184
|
+
[
|
|
185
|
+
StructField("Category", StringType(), True),
|
|
186
|
+
StructField("Scope", StringType(), True),
|
|
187
|
+
StructField("Rule Name", StringType(), True),
|
|
188
|
+
StructField("Description", StringType(), True),
|
|
189
|
+
]
|
|
189
190
|
)
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
translate.transform(dfRules)
|
|
203
|
-
.withColumn(
|
|
204
|
-
"translation", flatten(col("translation.translations"))
|
|
205
|
-
)
|
|
206
|
-
.withColumn("translation", col("translation.text"))
|
|
207
|
-
.select("Rule Name", clm, "translation")
|
|
192
|
+
spark = SparkSession.builder.getOrCreate()
|
|
193
|
+
dfRules = spark.createDataFrame(rules_temp, schema)
|
|
194
|
+
|
|
195
|
+
columns = ["Category", "Rule Name", "Description"]
|
|
196
|
+
for clm in columns:
|
|
197
|
+
translate = (
|
|
198
|
+
Translate()
|
|
199
|
+
.setTextCol(clm)
|
|
200
|
+
.setToLanguage(language)
|
|
201
|
+
.setOutputCol("translation")
|
|
202
|
+
.setConcurrency(5)
|
|
208
203
|
)
|
|
209
204
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
if clm == "Rule Name":
|
|
206
|
+
transDF = (
|
|
207
|
+
translate.transform(dfRules)
|
|
208
|
+
.withColumn(
|
|
209
|
+
"translation", flatten(col("translation.translations"))
|
|
210
|
+
)
|
|
211
|
+
.withColumn("translation", col("translation.text"))
|
|
212
|
+
.select(clm, "translation")
|
|
213
|
+
)
|
|
214
|
+
else:
|
|
215
|
+
transDF = (
|
|
216
|
+
translate.transform(dfRules)
|
|
217
|
+
.withColumn(
|
|
218
|
+
"translation", flatten(col("translation.translations"))
|
|
219
|
+
)
|
|
220
|
+
.withColumn("translation", col("translation.text"))
|
|
221
|
+
.select("Rule Name", clm, "translation")
|
|
222
|
+
)
|
|
217
223
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
+
df_panda = transDF.toPandas()
|
|
225
|
+
rule_file = pd.merge(
|
|
226
|
+
rule_file,
|
|
227
|
+
df_panda[["Rule Name", "translation"]],
|
|
228
|
+
on="Rule Name",
|
|
229
|
+
how="left",
|
|
230
|
+
)
|
|
224
231
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
rule_file = rule_file.rename(
|
|
233
|
+
columns={"translation": f"{clm}Translated"}
|
|
234
|
+
)
|
|
235
|
+
rule_file[f"{clm}Translated"] = rule_file[f"{clm}Translated"].apply(
|
|
236
|
+
lambda x: x[0] if x is not None else None
|
|
237
|
+
)
|
|
228
238
|
|
|
229
|
-
|
|
239
|
+
for clm in columns:
|
|
240
|
+
rule_file = rule_file.drop([clm], axis=1)
|
|
241
|
+
rule_file = rule_file.rename(columns={f"{clm}Translated": clm})
|
|
230
242
|
|
|
231
|
-
|
|
243
|
+
return rule_file
|
|
232
244
|
|
|
233
|
-
# Translations
|
|
234
|
-
if language is not None and rules is None and language in language_list:
|
|
235
|
-
rules = model_bpa_rules(
|
|
236
|
-
dataset=dataset, workspace=workspace, dependencies=dep
|
|
237
|
-
)
|
|
238
|
-
translate_using_po(rules)
|
|
239
|
-
translated = True
|
|
240
|
-
if rules is None:
|
|
241
|
-
rules = model_bpa_rules(
|
|
242
|
-
dataset=dataset, workspace=workspace, dependencies=dep
|
|
243
|
-
)
|
|
244
|
-
if language is not None and not translated:
|
|
245
245
|
rules = translate_using_spark(rules)
|
|
246
246
|
|
|
247
247
|
rules["Severity"].replace("Warning", icons.warning, inplace=True)
|
|
@@ -302,26 +302,28 @@ def run_model_bpa(
|
|
|
302
302
|
|
|
303
303
|
if scope == "Model":
|
|
304
304
|
x = []
|
|
305
|
-
if expr(func):
|
|
305
|
+
if expr(func, tom):
|
|
306
306
|
x = ["Model"]
|
|
307
307
|
elif scope == "Measure":
|
|
308
|
-
x = [nm(obj) for obj in tom.all_measures() if expr(obj)]
|
|
308
|
+
x = [nm(obj) for obj in tom.all_measures() if expr(obj, tom)]
|
|
309
309
|
elif scope == "Column":
|
|
310
|
-
x = [nm(obj) for obj in tom.all_columns() if expr(obj)]
|
|
310
|
+
x = [nm(obj) for obj in tom.all_columns() if expr(obj, tom)]
|
|
311
311
|
elif scope == "Partition":
|
|
312
|
-
x = [nm(obj) for obj in tom.all_partitions() if expr(obj)]
|
|
312
|
+
x = [nm(obj) for obj in tom.all_partitions() if expr(obj, tom)]
|
|
313
313
|
elif scope == "Hierarchy":
|
|
314
|
-
x = [nm(obj) for obj in tom.all_hierarchies() if expr(obj)]
|
|
314
|
+
x = [nm(obj) for obj in tom.all_hierarchies() if expr(obj, tom)]
|
|
315
315
|
elif scope == "Table":
|
|
316
|
-
x = [nm(obj) for obj in tom.model.Tables if expr(obj)]
|
|
316
|
+
x = [nm(obj) for obj in tom.model.Tables if expr(obj, tom)]
|
|
317
317
|
elif scope == "Relationship":
|
|
318
|
-
x = [nm(obj) for obj in tom.model.Relationships if expr(obj)]
|
|
318
|
+
x = [nm(obj) for obj in tom.model.Relationships if expr(obj, tom)]
|
|
319
319
|
elif scope == "Role":
|
|
320
|
-
x = [nm(obj) for obj in tom.model.Roles if expr(obj)]
|
|
320
|
+
x = [nm(obj) for obj in tom.model.Roles if expr(obj, tom)]
|
|
321
321
|
elif scope == "Row Level Security":
|
|
322
|
-
x = [nm(obj) for obj in tom.all_rls() if expr(obj)]
|
|
322
|
+
x = [nm(obj) for obj in tom.all_rls() if expr(obj, tom)]
|
|
323
323
|
elif scope == "Calculation Item":
|
|
324
|
-
x = [
|
|
324
|
+
x = [
|
|
325
|
+
nm(obj) for obj in tom.all_calculation_items() if expr(obj, tom)
|
|
326
|
+
]
|
|
325
327
|
|
|
326
328
|
if len(x) > 0:
|
|
327
329
|
new_data = {"Object Name": x, "Scope": scope, "Rule Name": ruleName}
|
sempy_labs/_model_bpa_bulk.py
CHANGED
|
@@ -229,7 +229,9 @@ def create_model_bpa_semantic_model(
|
|
|
229
229
|
expr = get_shared_expression(lakehouse=lakehouse, workspace=lakehouse_workspace)
|
|
230
230
|
|
|
231
231
|
# Create blank model
|
|
232
|
-
create_blank_semantic_model(
|
|
232
|
+
create_blank_semantic_model(
|
|
233
|
+
dataset=dataset, workspace=lakehouse_workspace, overwrite=True
|
|
234
|
+
)
|
|
233
235
|
|
|
234
236
|
@retry(
|
|
235
237
|
sleep_time=1,
|