semantic-link-labs 0.9.5__py3-none-any.whl → 0.9.7__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.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/METADATA +8 -5
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/RECORD +65 -61
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +19 -1
- sempy_labs/_ai.py +3 -1
- sempy_labs/_capacities.py +37 -2
- sempy_labs/_capacity_migration.py +11 -14
- sempy_labs/_connections.py +2 -4
- sempy_labs/_dataflows.py +2 -2
- sempy_labs/_dax_query_view.py +57 -0
- sempy_labs/_delta_analyzer.py +16 -14
- sempy_labs/_delta_analyzer_history.py +298 -0
- sempy_labs/_environments.py +8 -1
- sempy_labs/_eventhouses.py +5 -1
- sempy_labs/_external_data_shares.py +4 -10
- sempy_labs/_generate_semantic_model.py +2 -1
- sempy_labs/_graphQL.py +5 -1
- sempy_labs/_helper_functions.py +440 -63
- sempy_labs/_icons.py +6 -6
- sempy_labs/_kql_databases.py +5 -1
- sempy_labs/_list_functions.py +8 -38
- sempy_labs/_managed_private_endpoints.py +9 -2
- sempy_labs/_mirrored_databases.py +3 -1
- sempy_labs/_ml_experiments.py +1 -1
- sempy_labs/_model_bpa.py +2 -11
- sempy_labs/_model_bpa_bulk.py +33 -38
- sempy_labs/_model_bpa_rules.py +1 -1
- sempy_labs/_one_lake_integration.py +2 -1
- sempy_labs/_semantic_models.py +20 -0
- sempy_labs/_sql.py +6 -2
- sempy_labs/_sqldatabase.py +61 -100
- sempy_labs/_vertipaq.py +8 -11
- sempy_labs/_warehouses.py +14 -3
- sempy_labs/_workspace_identity.py +6 -0
- sempy_labs/_workspaces.py +42 -2
- sempy_labs/admin/_basic_functions.py +29 -2
- sempy_labs/admin/_reports.py +1 -1
- sempy_labs/admin/_scanner.py +2 -4
- sempy_labs/admin/_tenant.py +8 -3
- sempy_labs/directlake/_directlake_schema_compare.py +2 -1
- sempy_labs/directlake/_directlake_schema_sync.py +65 -19
- sempy_labs/directlake/_dl_helper.py +0 -6
- sempy_labs/directlake/_generate_shared_expression.py +19 -12
- sempy_labs/directlake/_guardrails.py +2 -1
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +90 -57
- sempy_labs/directlake/_update_directlake_partition_entity.py +5 -2
- sempy_labs/graph/_groups.py +6 -0
- sempy_labs/graph/_teams.py +2 -0
- sempy_labs/graph/_users.py +4 -0
- sempy_labs/lakehouse/__init__.py +12 -3
- sempy_labs/lakehouse/_blobs.py +231 -0
- sempy_labs/lakehouse/_shortcuts.py +29 -8
- sempy_labs/migration/_direct_lake_to_import.py +47 -10
- sempy_labs/migration/_migration_validation.py +0 -4
- sempy_labs/report/__init__.py +4 -0
- sempy_labs/report/_download_report.py +4 -6
- sempy_labs/report/_generate_report.py +6 -6
- sempy_labs/report/_report_functions.py +5 -4
- sempy_labs/report/_report_helper.py +17 -5
- sempy_labs/report/_report_rebind.py +8 -6
- sempy_labs/report/_reportwrapper.py +17 -8
- sempy_labs/report/_save_report.py +147 -0
- sempy_labs/tom/_model.py +154 -23
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info/licenses}/LICENSE +0 -0
- {semantic_link_labs-0.9.5.dist-info → semantic_link_labs-0.9.7.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import sempy
|
|
2
|
-
import
|
|
2
|
+
import pandas as pd
|
|
3
3
|
from sempy_labs.lakehouse import get_lakehouse_columns
|
|
4
4
|
from sempy_labs.directlake._dl_helper import get_direct_lake_source
|
|
5
5
|
from sempy_labs.tom import connect_semantic_model
|
|
@@ -19,8 +19,8 @@ def direct_lake_schema_sync(
|
|
|
19
19
|
dataset: str | UUID,
|
|
20
20
|
workspace: Optional[str | UUID] = None,
|
|
21
21
|
add_to_model: bool = False,
|
|
22
|
-
|
|
23
|
-
):
|
|
22
|
+
remove_from_model: bool = False,
|
|
23
|
+
) -> pd.DataFrame:
|
|
24
24
|
"""
|
|
25
25
|
Shows/adds columns which exist in the lakehouse but do not exist in the semantic model (only for tables in the semantic model).
|
|
26
26
|
|
|
@@ -34,22 +34,18 @@ def direct_lake_schema_sync(
|
|
|
34
34
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
35
35
|
add_to_model : bool, default=False
|
|
36
36
|
If set to True, columns which exist in the lakehouse but do not exist in the semantic model are added to the semantic model. No new tables are added.
|
|
37
|
+
remove_from_model : bool, default=False
|
|
38
|
+
If set to True, columns which exist in the semantic model but do not exist in the lakehouse are removed from the semantic model. No new tables are removed.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
pandas.DataFrame
|
|
43
|
+
A pandas dataframe showing the status of columns in the semantic model and lakehouse (prior to adding/removing them from the model using this function).
|
|
37
44
|
"""
|
|
38
45
|
|
|
39
46
|
sempy.fabric._client._utils._init_analysis_services()
|
|
40
47
|
import Microsoft.AnalysisServices.Tabular as TOM
|
|
41
48
|
|
|
42
|
-
if "lakehouse" in kwargs:
|
|
43
|
-
print(
|
|
44
|
-
"The 'lakehouse' parameter has been deprecated as it is no longer necessary. Please remove this parameter from the function going forward."
|
|
45
|
-
)
|
|
46
|
-
del kwargs["lakehouse"]
|
|
47
|
-
if "lakehouse_workspace" in kwargs:
|
|
48
|
-
print(
|
|
49
|
-
"The 'lakehouse_workspace' parameter has been deprecated as it is no longer necessary. Please remove this parameter from the function going forward."
|
|
50
|
-
)
|
|
51
|
-
del kwargs["lakehouse_workspace"]
|
|
52
|
-
|
|
53
49
|
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
54
50
|
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
55
51
|
|
|
@@ -67,14 +63,54 @@ def direct_lake_schema_sync(
|
|
|
67
63
|
f"{icons.red_dot} This function only supports Direct Lake semantic models where the source lakehouse resides in the same workpace as the semantic model."
|
|
68
64
|
)
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
lc = get_lakehouse_columns(lakehouse_id, lakehouse_workspace_id)
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
readonly = True
|
|
69
|
+
if add_to_model or remove_from_model:
|
|
70
|
+
readonly = False
|
|
71
|
+
df = pd.DataFrame(
|
|
72
|
+
columns=[
|
|
73
|
+
"TableName",
|
|
74
|
+
"ColumnName",
|
|
75
|
+
"SourceTableName",
|
|
76
|
+
"SourceColumnName",
|
|
77
|
+
"Status",
|
|
78
|
+
]
|
|
79
|
+
)
|
|
73
80
|
|
|
74
81
|
with connect_semantic_model(
|
|
75
|
-
dataset=dataset_id, readonly=
|
|
82
|
+
dataset=dataset_id, readonly=readonly, workspace=workspace_id
|
|
76
83
|
) as tom:
|
|
84
|
+
# Check if the columns in the semantic model exist in the lakehouse
|
|
85
|
+
for c in tom.all_columns():
|
|
86
|
+
partition_name = next(p.Name for p in c.Table.Partitions)
|
|
87
|
+
p = c.Table.Partitions[partition_name]
|
|
88
|
+
if p.SourceType == TOM.PartitionSourceType.Entity:
|
|
89
|
+
entity_name = p.Source.EntityName
|
|
90
|
+
source_column = c.SourceColumn
|
|
91
|
+
lc_filt = lc[
|
|
92
|
+
(lc["Table Name"] == entity_name)
|
|
93
|
+
& (lc["Column Name"] == source_column)
|
|
94
|
+
]
|
|
95
|
+
# Remove column from model if it doesn't exist in the lakehouse
|
|
96
|
+
if lc_filt.empty:
|
|
97
|
+
new_data = {
|
|
98
|
+
"TableName": c.Parent.Name,
|
|
99
|
+
"ColumnName": c.Name,
|
|
100
|
+
"SourceTableName": entity_name,
|
|
101
|
+
"SourceColumnName": source_column,
|
|
102
|
+
"Status": "Not in lakehouse",
|
|
103
|
+
}
|
|
104
|
+
df = pd.concat(
|
|
105
|
+
[df, pd.DataFrame(new_data, index=[0])], ignore_index=True
|
|
106
|
+
)
|
|
107
|
+
if remove_from_model:
|
|
108
|
+
tom.remove_object(object=c)
|
|
109
|
+
print(
|
|
110
|
+
f"{icons.green_dot} The '{c.Parent.Name}'[{c.Name}] column has been removed from the '{dataset_name}' semantic model within the '{workspace_name}' workspace."
|
|
111
|
+
)
|
|
77
112
|
|
|
113
|
+
# Check if the lakehouse columns exist in the semantic model
|
|
78
114
|
for i, r in lc.iterrows():
|
|
79
115
|
lakeTName = r["Table Name"]
|
|
80
116
|
lakeCName = r["Column Name"]
|
|
@@ -97,9 +133,17 @@ def direct_lake_schema_sync(
|
|
|
97
133
|
c.SourceColumn == lakeCName and c.Parent.Name == table_name
|
|
98
134
|
for c in tom.all_columns()
|
|
99
135
|
):
|
|
100
|
-
|
|
101
|
-
|
|
136
|
+
new_data = {
|
|
137
|
+
"TableName": table_name,
|
|
138
|
+
"ColumnName": None,
|
|
139
|
+
"SourceTableName": lakeTName,
|
|
140
|
+
"SourceColumnName": lakeCName,
|
|
141
|
+
"Status": "Not in semantic model",
|
|
142
|
+
}
|
|
143
|
+
df = pd.concat(
|
|
144
|
+
[df, pd.DataFrame(new_data, index=[0])], ignore_index=True
|
|
102
145
|
)
|
|
146
|
+
|
|
103
147
|
if add_to_model:
|
|
104
148
|
dt = _convert_data_type(dType)
|
|
105
149
|
tom.add_data_column(
|
|
@@ -111,3 +155,5 @@ def direct_lake_schema_sync(
|
|
|
111
155
|
print(
|
|
112
156
|
f"{icons.green_dot} The '{lakeCName}' column in the '{lakeTName}' lakehouse table was added to the '{dataset_name}' semantic model within the '{workspace_name}' workspace."
|
|
113
157
|
)
|
|
158
|
+
|
|
159
|
+
return df
|
|
@@ -7,7 +7,6 @@ import sempy_labs._icons as icons
|
|
|
7
7
|
from sempy._utils._log import log
|
|
8
8
|
from sempy_labs._helper_functions import (
|
|
9
9
|
retry,
|
|
10
|
-
resolve_lakehouse_name,
|
|
11
10
|
_convert_data_type,
|
|
12
11
|
resolve_dataset_name_and_id,
|
|
13
12
|
resolve_workspace_name_and_id,
|
|
@@ -129,11 +128,6 @@ def generate_direct_lake_semantic_model(
|
|
|
129
128
|
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
130
129
|
if lakehouse_workspace is None:
|
|
131
130
|
lakehouse_workspace = workspace
|
|
132
|
-
if lakehouse is None:
|
|
133
|
-
lakehouse_id = fabric.get_lakehouse_id()
|
|
134
|
-
lakehouse_workspace_id = fabric.get_workspace_id()
|
|
135
|
-
lakehouse_workspace = fabric.resolve_workspace_name(lakehouse_workspace_id)
|
|
136
|
-
lakehouse = resolve_lakehouse_name(lakehouse_id, lakehouse_workspace)
|
|
137
131
|
|
|
138
132
|
dfLT = get_lakehouse_tables(lakehouse=lakehouse, workspace=lakehouse_workspace)
|
|
139
133
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import sempy.fabric as fabric
|
|
2
1
|
from sempy_labs._helper_functions import (
|
|
3
|
-
resolve_lakehouse_name,
|
|
4
|
-
resolve_lakehouse_id,
|
|
5
|
-
resolve_warehouse_id,
|
|
6
2
|
resolve_workspace_name_and_id,
|
|
7
3
|
_base_api,
|
|
4
|
+
resolve_lakehouse_name_and_id,
|
|
5
|
+
resolve_item_name_and_id,
|
|
8
6
|
)
|
|
9
7
|
from typing import Optional
|
|
10
8
|
import sempy_labs._icons as icons
|
|
@@ -15,6 +13,7 @@ def generate_shared_expression(
|
|
|
15
13
|
item_name: Optional[str] = None,
|
|
16
14
|
item_type: str = "Lakehouse",
|
|
17
15
|
workspace: Optional[str | UUID] = None,
|
|
16
|
+
use_sql_endpoint: bool = True,
|
|
18
17
|
) -> str:
|
|
19
18
|
"""
|
|
20
19
|
Dynamically generates the M expression used by a Direct Lake model for a given lakehouse/warehouse.
|
|
@@ -30,6 +29,9 @@ def generate_shared_expression(
|
|
|
30
29
|
The Fabric workspace name or ID used by the item.
|
|
31
30
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
32
31
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
32
|
+
use_sql_endpoint : bool, default=True
|
|
33
|
+
Whether to use the SQL Endpoint for the lakehouse/warehouse.
|
|
34
|
+
If False, the expression will be generated without using the SQL Endpoint.
|
|
33
35
|
|
|
34
36
|
Returns
|
|
35
37
|
-------
|
|
@@ -45,13 +47,14 @@ def generate_shared_expression(
|
|
|
45
47
|
f"{icons.red_dot} Invalid item type. Valid options: {item_types}."
|
|
46
48
|
)
|
|
47
49
|
|
|
48
|
-
if
|
|
49
|
-
item_id =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
if item_type == "Lakehouse":
|
|
51
|
+
(item_name, item_id) = resolve_lakehouse_name_and_id(
|
|
52
|
+
lakehouse=item_name, workspace=workspace_id
|
|
53
|
+
)
|
|
54
|
+
else:
|
|
55
|
+
(item_name, item_id) = resolve_item_name_and_id(
|
|
56
|
+
item=item_name, type=item_type, workspace=workspace_id
|
|
57
|
+
)
|
|
55
58
|
|
|
56
59
|
item_type_rest = f"{item_type.lower()}s"
|
|
57
60
|
response = _base_api(
|
|
@@ -79,4 +82,8 @@ def generate_shared_expression(
|
|
|
79
82
|
end_expr = "\nin\n\tdatabase"
|
|
80
83
|
mid_expr = f'Sql.Database("{sqlEPCS}", "{sqlepid}")'
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
# Build DL/OL expression
|
|
86
|
+
if not use_sql_endpoint and item_type == "Lakehouse":
|
|
87
|
+
return f'AzureDataLakeStorage{{"server":"onelake.dfs.fabric.microsoft.com","path":"/{workspace_id}/{item_id}/"}}'
|
|
88
|
+
else:
|
|
89
|
+
return f"{start_expr}{mid_expr}{end_expr}"
|
|
@@ -48,6 +48,7 @@ def get_sku_size(workspace: Optional[str | UUID] = None) -> str:
|
|
|
48
48
|
str
|
|
49
49
|
The SKU size for a workspace.
|
|
50
50
|
"""
|
|
51
|
+
from sempy_labs._capacities import list_capacities
|
|
51
52
|
|
|
52
53
|
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
53
54
|
|
|
@@ -59,7 +60,7 @@ def get_sku_size(workspace: Optional[str | UUID] = None) -> str:
|
|
|
59
60
|
)
|
|
60
61
|
|
|
61
62
|
capacity_id = dfW["Capacity Id"].iloc[0]
|
|
62
|
-
dfC =
|
|
63
|
+
dfC = list_capacities()
|
|
63
64
|
dfC_filt = dfC[dfC["Id"] == capacity_id]
|
|
64
65
|
|
|
65
66
|
if len(dfC_filt) == 0:
|
|
@@ -1,16 +1,64 @@
|
|
|
1
|
-
import sempy.fabric as fabric
|
|
2
1
|
from sempy_labs.directlake._generate_shared_expression import generate_shared_expression
|
|
3
2
|
from sempy_labs._helper_functions import (
|
|
4
|
-
resolve_lakehouse_name,
|
|
5
3
|
resolve_dataset_name_and_id,
|
|
6
4
|
resolve_workspace_name_and_id,
|
|
5
|
+
resolve_item_name_and_id,
|
|
6
|
+
resolve_lakehouse_name_and_id,
|
|
7
7
|
)
|
|
8
|
+
from sempy._utils._log import log
|
|
8
9
|
from sempy_labs.tom import connect_semantic_model
|
|
9
10
|
from typing import Optional
|
|
10
11
|
import sempy_labs._icons as icons
|
|
11
12
|
from uuid import UUID
|
|
13
|
+
import re
|
|
12
14
|
|
|
13
15
|
|
|
16
|
+
def _extract_expression_list(expression):
|
|
17
|
+
"""
|
|
18
|
+
Finds the pattern for DL/SQL & DL/OL expressions in the semantic model.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
pattern_sql = r'Sql\.Database\s*\(\s*"([^"]+)"\s*,\s*"([^"]+)"\s*\)'
|
|
22
|
+
pattern_no_sql = r'AzureDataLakeStorage\s*\{\s*"server".*?:\s*onelake\.dfs\.fabric\.microsoft\.com"\s*,\s*"path"\s*:\s*"/([\da-fA-F-]+)\s*/\s*([\da-fA-F-]+)\s*/"\s*\}'
|
|
23
|
+
|
|
24
|
+
match_sql = re.search(pattern_sql, expression)
|
|
25
|
+
match_no_sql = re.search(pattern_no_sql, expression)
|
|
26
|
+
|
|
27
|
+
result = []
|
|
28
|
+
if match_sql:
|
|
29
|
+
value_1, value_2 = match_sql.groups()
|
|
30
|
+
result = [value_1, value_2, True]
|
|
31
|
+
elif match_no_sql:
|
|
32
|
+
value_1, value_2 = match_no_sql.groups()
|
|
33
|
+
result = [value_1, value_2, False]
|
|
34
|
+
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _get_direct_lake_expressions(
|
|
39
|
+
dataset: str | UUID, workspace: Optional[str | UUID] = None
|
|
40
|
+
) -> dict:
|
|
41
|
+
"""
|
|
42
|
+
Extracts a dictionary of all Direct Lake expressions from a semantic model.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
from sempy_labs.tom import connect_semantic_model
|
|
46
|
+
|
|
47
|
+
result = {}
|
|
48
|
+
|
|
49
|
+
with connect_semantic_model(dataset=dataset, workspace=workspace) as tom:
|
|
50
|
+
for e in tom.model.Expressions:
|
|
51
|
+
expr_name = e.Name
|
|
52
|
+
expr = e.Expression
|
|
53
|
+
|
|
54
|
+
list_values = _extract_expression_list(expr)
|
|
55
|
+
if list_values:
|
|
56
|
+
result[expr_name] = list_values
|
|
57
|
+
|
|
58
|
+
return result
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@log
|
|
14
62
|
def update_direct_lake_model_lakehouse_connection(
|
|
15
63
|
dataset: str | UUID,
|
|
16
64
|
workspace: Optional[str | UUID] = None,
|
|
@@ -37,54 +85,23 @@ def update_direct_lake_model_lakehouse_connection(
|
|
|
37
85
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
38
86
|
"""
|
|
39
87
|
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if lakehouse is None:
|
|
47
|
-
lakehouse_id = fabric.get_lakehouse_id()
|
|
48
|
-
lakehouse = resolve_lakehouse_name(lakehouse_id, lakehouse_workspace)
|
|
49
|
-
|
|
50
|
-
# Check if lakehouse is valid
|
|
51
|
-
dfI = fabric.list_items(workspace=lakehouse_workspace, type="Lakehouse")
|
|
52
|
-
dfI_filt = dfI[(dfI["Display Name"] == lakehouse)]
|
|
53
|
-
|
|
54
|
-
if len(dfI_filt) == 0:
|
|
55
|
-
raise ValueError(
|
|
56
|
-
f"{icons.red_dot} The '{lakehouse}' lakehouse does not exist within the '{lakehouse_workspace}' workspace. "
|
|
57
|
-
f"Therefore it cannot be used to support the '{dataset_name}' semantic model within the '{workspace_name}' workspace."
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
icons.sll_tags.append("UpdateDLConnection")
|
|
61
|
-
|
|
62
|
-
shEx = generate_shared_expression(
|
|
63
|
-
item_name=lakehouse, item_type="Lakehouse", workspace=lakehouse_workspace
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
with connect_semantic_model(
|
|
67
|
-
dataset=dataset_id, readonly=False, workspace=workspace_id
|
|
68
|
-
) as tom:
|
|
69
|
-
|
|
70
|
-
if not tom.is_direct_lake():
|
|
71
|
-
raise ValueError(
|
|
72
|
-
f"{icons.red_dot} The '{dataset_name}' semantic model is not in Direct Lake. This function is only applicable to Direct Lake semantic models."
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
tom.model.Expressions["DatabaseQuery"].Expression = shEx
|
|
76
|
-
|
|
77
|
-
print(
|
|
78
|
-
f"{icons.green_dot} The expression in the '{dataset_name}' semantic model has been updated to point to the '{lakehouse}' lakehouse in the '{lakehouse_workspace}' workspace."
|
|
88
|
+
update_direct_lake_model_connection(
|
|
89
|
+
dataset=dataset,
|
|
90
|
+
workspace=workspace,
|
|
91
|
+
source=lakehouse,
|
|
92
|
+
source_type="Lakehouse",
|
|
93
|
+
source_workspace=lakehouse_workspace,
|
|
79
94
|
)
|
|
80
95
|
|
|
81
96
|
|
|
97
|
+
@log
|
|
82
98
|
def update_direct_lake_model_connection(
|
|
83
99
|
dataset: str | UUID,
|
|
84
100
|
workspace: Optional[str | UUID] = None,
|
|
85
101
|
source: Optional[str] = None,
|
|
86
102
|
source_type: str = "Lakehouse",
|
|
87
103
|
source_workspace: Optional[str | UUID] = None,
|
|
104
|
+
use_sql_endpoint: bool = True,
|
|
88
105
|
):
|
|
89
106
|
"""
|
|
90
107
|
Remaps a Direct Lake semantic model's SQL Endpoint connection to a new lakehouse/warehouse.
|
|
@@ -106,7 +123,14 @@ def update_direct_lake_model_connection(
|
|
|
106
123
|
The Fabric workspace name or ID used by the lakehouse/warehouse.
|
|
107
124
|
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
108
125
|
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
126
|
+
use_sql_endpoint : bool, default=True
|
|
127
|
+
If True, the SQL Endpoint will be used for the connection.
|
|
128
|
+
If False, Direct Lake over OneLake will be used.
|
|
109
129
|
"""
|
|
130
|
+
if use_sql_endpoint:
|
|
131
|
+
icons.sll_tags.append("UpdateDLConnection_SQL")
|
|
132
|
+
else:
|
|
133
|
+
icons.sll_tags.append("UpdateDLConnection_DLOL")
|
|
110
134
|
|
|
111
135
|
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
112
136
|
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
@@ -121,23 +145,25 @@ def update_direct_lake_model_connection(
|
|
|
121
145
|
if source_workspace is None:
|
|
122
146
|
source_workspace = workspace_name
|
|
123
147
|
|
|
124
|
-
if
|
|
125
|
-
source_id =
|
|
126
|
-
|
|
127
|
-
else:
|
|
128
|
-
source_id = fabric.resolve_item_id(
|
|
129
|
-
item_name=source, type=source_type, workspace=source_workspace
|
|
148
|
+
if source_type == "Lakehouse":
|
|
149
|
+
(source_name, source_id) = resolve_lakehouse_name_and_id(
|
|
150
|
+
lakehouse=source, workspace=source_workspace
|
|
130
151
|
)
|
|
131
|
-
|
|
132
|
-
|
|
152
|
+
else:
|
|
153
|
+
(source_name, source_id) = resolve_item_name_and_id(
|
|
154
|
+
item=source, type=source_type, workspace=source_workspace
|
|
133
155
|
)
|
|
134
156
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
shared_expression = generate_shared_expression(
|
|
158
|
+
item_name=source_name,
|
|
159
|
+
item_type=source_type,
|
|
160
|
+
workspace=source_workspace,
|
|
161
|
+
use_sql_endpoint=use_sql_endpoint,
|
|
139
162
|
)
|
|
140
163
|
|
|
164
|
+
expression_dict = _get_direct_lake_expressions(dataset=dataset, workspace=workspace)
|
|
165
|
+
expressions = list(expression_dict.keys())
|
|
166
|
+
|
|
141
167
|
with connect_semantic_model(
|
|
142
168
|
dataset=dataset_id, readonly=False, workspace=workspace_id
|
|
143
169
|
) as tom:
|
|
@@ -147,8 +173,15 @@ def update_direct_lake_model_connection(
|
|
|
147
173
|
f"{icons.red_dot} The '{dataset_name}' semantic model within the '{workspace_name}' workspace is not in Direct Lake. This function is only applicable to Direct Lake semantic models."
|
|
148
174
|
)
|
|
149
175
|
|
|
150
|
-
|
|
176
|
+
# Update the single connection expression
|
|
177
|
+
if len(expressions) == 1:
|
|
178
|
+
expr = expressions[0]
|
|
179
|
+
tom.model.Expressions[expr].Expression = shared_expression
|
|
151
180
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
181
|
+
print(
|
|
182
|
+
f"{icons.green_dot} The expression in the '{dataset_name}' semantic model within the '{workspace_name}' workspace has been updated to point to the '{source}' {source_type.lower()} in the '{source_workspace}' workspace."
|
|
183
|
+
)
|
|
184
|
+
else:
|
|
185
|
+
print(
|
|
186
|
+
f"{icons.info} Multiple expressions found in the model. Please use the update_direct_lake_partition_entity function to update specific tables."
|
|
187
|
+
)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import sempy
|
|
2
|
-
import sempy.fabric as fabric
|
|
3
2
|
from sempy_labs.tom import connect_semantic_model
|
|
4
3
|
from sempy_labs._refresh_semantic_model import refresh_semantic_model
|
|
5
4
|
from sempy_labs.directlake._dl_helper import get_direct_lake_source
|
|
@@ -7,12 +6,15 @@ from sempy_labs._helper_functions import (
|
|
|
7
6
|
_convert_data_type,
|
|
8
7
|
resolve_dataset_name_and_id,
|
|
9
8
|
resolve_workspace_name_and_id,
|
|
9
|
+
resolve_workspace_name,
|
|
10
10
|
)
|
|
11
|
+
from sempy._utils._log import log
|
|
11
12
|
from typing import List, Optional, Union
|
|
12
13
|
import sempy_labs._icons as icons
|
|
13
14
|
from uuid import UUID
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
@log
|
|
16
18
|
def update_direct_lake_partition_entity(
|
|
17
19
|
dataset: str | UUID,
|
|
18
20
|
table_name: Union[str, List[str]],
|
|
@@ -96,6 +98,7 @@ def update_direct_lake_partition_entity(
|
|
|
96
98
|
)
|
|
97
99
|
|
|
98
100
|
|
|
101
|
+
@log
|
|
99
102
|
def add_table_to_direct_lake_semantic_model(
|
|
100
103
|
dataset: str | UUID,
|
|
101
104
|
table_name: str,
|
|
@@ -144,7 +147,7 @@ def add_table_to_direct_lake_semantic_model(
|
|
|
144
147
|
f"{icons.red_dot} This function only supports Direct Lake semantic models where the source lakehouse resides in the same workpace as the semantic model."
|
|
145
148
|
)
|
|
146
149
|
|
|
147
|
-
lakehouse_workspace =
|
|
150
|
+
lakehouse_workspace = resolve_workspace_name(workspace_id=lakehouse_workspace_id)
|
|
148
151
|
|
|
149
152
|
with connect_semantic_model(
|
|
150
153
|
dataset=dataset_id, readonly=False, workspace=workspace_id
|
sempy_labs/graph/_groups.py
CHANGED
|
@@ -6,6 +6,7 @@ from sempy_labs._helper_functions import (
|
|
|
6
6
|
_create_dataframe,
|
|
7
7
|
_update_dataframe_datatypes,
|
|
8
8
|
)
|
|
9
|
+
from sempy._utils._log import log
|
|
9
10
|
import sempy_labs._icons as icons
|
|
10
11
|
from typing import List, Literal
|
|
11
12
|
|
|
@@ -38,6 +39,7 @@ def resolve_group_id(group: str | UUID) -> UUID:
|
|
|
38
39
|
return group_id
|
|
39
40
|
|
|
40
41
|
|
|
42
|
+
@log
|
|
41
43
|
def list_groups() -> pd.DataFrame:
|
|
42
44
|
"""
|
|
43
45
|
Shows a list of groups and their properties.
|
|
@@ -158,6 +160,7 @@ def _get_group(group_id: UUID) -> pd.DataFrame:
|
|
|
158
160
|
return df
|
|
159
161
|
|
|
160
162
|
|
|
163
|
+
@log
|
|
161
164
|
def list_group_members(group: str | UUID) -> pd.DataFrame:
|
|
162
165
|
"""
|
|
163
166
|
Shows a list of the members of a group.
|
|
@@ -217,6 +220,7 @@ def list_group_members(group: str | UUID) -> pd.DataFrame:
|
|
|
217
220
|
return df
|
|
218
221
|
|
|
219
222
|
|
|
223
|
+
@log
|
|
220
224
|
def list_group_owners(group: str | UUID) -> pd.DataFrame:
|
|
221
225
|
"""
|
|
222
226
|
Shows a list of the owners of a group.
|
|
@@ -332,6 +336,7 @@ def _base_add_to_group(
|
|
|
332
336
|
)
|
|
333
337
|
|
|
334
338
|
|
|
339
|
+
@log
|
|
335
340
|
def add_group_members(
|
|
336
341
|
group: str | UUID,
|
|
337
342
|
user: str | UUID | List[str | UUID],
|
|
@@ -376,6 +381,7 @@ def add_group_owners(
|
|
|
376
381
|
_base_add_to_group(group=group, object=user, object_type="owners")
|
|
377
382
|
|
|
378
383
|
|
|
384
|
+
@log
|
|
379
385
|
def renew_group(group: str | UUID):
|
|
380
386
|
"""
|
|
381
387
|
Renews the group.
|
sempy_labs/graph/_teams.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from uuid import UUID
|
|
3
|
+
from sempy._utils._log import log
|
|
3
4
|
from sempy_labs._helper_functions import (
|
|
4
5
|
_base_api,
|
|
5
6
|
_create_dataframe,
|
|
@@ -7,6 +8,7 @@ from sempy_labs._helper_functions import (
|
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
|
|
11
|
+
@log
|
|
10
12
|
def list_teams() -> pd.DataFrame:
|
|
11
13
|
"""
|
|
12
14
|
Shows a list of teams and their properties.
|
sempy_labs/graph/_users.py
CHANGED
|
@@ -7,6 +7,7 @@ from sempy_labs._helper_functions import (
|
|
|
7
7
|
_base_api,
|
|
8
8
|
_create_dataframe,
|
|
9
9
|
)
|
|
10
|
+
from sempy._utils._log import log
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def resolve_user_id(user: str | UUID) -> UUID:
|
|
@@ -33,6 +34,7 @@ def resolve_user_id(user: str | UUID) -> UUID:
|
|
|
33
34
|
return result.get("id")
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
@log
|
|
36
38
|
def get_user(user: str | UUID) -> pd.DataFrame:
|
|
37
39
|
"""
|
|
38
40
|
Shows properties of a given user.
|
|
@@ -70,6 +72,7 @@ def get_user(user: str | UUID) -> pd.DataFrame:
|
|
|
70
72
|
return pd.DataFrame([new_data])
|
|
71
73
|
|
|
72
74
|
|
|
75
|
+
@log
|
|
73
76
|
def list_users() -> pd.DataFrame:
|
|
74
77
|
"""
|
|
75
78
|
Shows a list of users and their properties.
|
|
@@ -120,6 +123,7 @@ def list_users() -> pd.DataFrame:
|
|
|
120
123
|
return df
|
|
121
124
|
|
|
122
125
|
|
|
126
|
+
@log
|
|
123
127
|
def send_mail(
|
|
124
128
|
user: UUID | str,
|
|
125
129
|
subject: str,
|
sempy_labs/lakehouse/__init__.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
from sempy_labs.lakehouse._get_lakehouse_columns import
|
|
2
|
-
|
|
1
|
+
from sempy_labs.lakehouse._get_lakehouse_columns import (
|
|
2
|
+
get_lakehouse_columns,
|
|
3
|
+
)
|
|
4
|
+
from sempy_labs.lakehouse._get_lakehouse_tables import (
|
|
5
|
+
get_lakehouse_tables,
|
|
6
|
+
)
|
|
3
7
|
from sempy_labs.lakehouse._lakehouse import (
|
|
4
8
|
lakehouse_attached,
|
|
5
9
|
optimize_lakehouse_tables,
|
|
6
10
|
vacuum_lakehouse_tables,
|
|
7
11
|
run_table_maintenance,
|
|
8
12
|
)
|
|
9
|
-
|
|
10
13
|
from sempy_labs.lakehouse._shortcuts import (
|
|
11
14
|
# create_shortcut,
|
|
12
15
|
create_shortcut_onelake,
|
|
@@ -14,6 +17,10 @@ from sempy_labs.lakehouse._shortcuts import (
|
|
|
14
17
|
reset_shortcut_cache,
|
|
15
18
|
list_shortcuts,
|
|
16
19
|
)
|
|
20
|
+
from sempy_labs.lakehouse._blobs import (
|
|
21
|
+
recover_lakehouse_object,
|
|
22
|
+
list_blobs,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
__all__ = [
|
|
19
26
|
"get_lakehouse_columns",
|
|
@@ -27,4 +34,6 @@ __all__ = [
|
|
|
27
34
|
"reset_shortcut_cache",
|
|
28
35
|
"run_table_maintenance",
|
|
29
36
|
"list_shortcuts",
|
|
37
|
+
"recover_lakehouse_object",
|
|
38
|
+
"list_blobs",
|
|
30
39
|
]
|