semantic-link-labs 0.8.8__py3-none-any.whl → 0.8.10__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.8.dist-info → semantic_link_labs-0.8.10.dist-info}/METADATA +5 -2
- {semantic_link_labs-0.8.8.dist-info → semantic_link_labs-0.8.10.dist-info}/RECORD +28 -28
- sempy_labs/__init__.py +10 -0
- sempy_labs/_authentication.py +31 -2
- sempy_labs/_dataflows.py +1 -1
- sempy_labs/_dax.py +69 -54
- sempy_labs/_gateways.py +46 -0
- sempy_labs/_generate_semantic_model.py +74 -27
- sempy_labs/_git.py +32 -27
- sempy_labs/_helper_functions.py +60 -23
- sempy_labs/_list_functions.py +178 -32
- sempy_labs/_model_bpa.py +25 -23
- sempy_labs/_model_bpa_bulk.py +5 -5
- sempy_labs/_model_dependencies.py +17 -8
- sempy_labs/_notebooks.py +50 -18
- sempy_labs/_refresh_semantic_model.py +23 -17
- sempy_labs/_translations.py +80 -148
- sempy_labs/_workspaces.py +1 -1
- sempy_labs/admin/__init__.py +6 -0
- sempy_labs/admin/_basic_functions.py +120 -40
- sempy_labs/admin/_domains.py +3 -2
- sempy_labs/admin/_scanner.py +5 -5
- sempy_labs/directlake/_dl_helper.py +13 -8
- sempy_labs/report/_reportwrapper.py +14 -9
- sempy_labs/tom/_model.py +77 -35
- {semantic_link_labs-0.8.8.dist-info → semantic_link_labs-0.8.10.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.8.8.dist-info → semantic_link_labs-0.8.10.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.8.8.dist-info → semantic_link_labs-0.8.10.dist-info}/top_level.txt +0 -0
sempy_labs/tom/_model.py
CHANGED
|
@@ -7,6 +7,8 @@ from sempy_labs._helper_functions import (
|
|
|
7
7
|
format_dax_object_name,
|
|
8
8
|
generate_guid,
|
|
9
9
|
_make_list_unique,
|
|
10
|
+
resolve_dataset_name_and_id,
|
|
11
|
+
resolve_workspace_name_and_id,
|
|
10
12
|
)
|
|
11
13
|
from sempy_labs._list_functions import list_relationships
|
|
12
14
|
from sempy_labs._refresh_semantic_model import refresh_semantic_model
|
|
@@ -17,6 +19,7 @@ from sempy._utils._log import log
|
|
|
17
19
|
import sempy_labs._icons as icons
|
|
18
20
|
from sempy.fabric.exceptions import FabricHTTPException
|
|
19
21
|
import ast
|
|
22
|
+
from uuid import UUID
|
|
20
23
|
|
|
21
24
|
if TYPE_CHECKING:
|
|
22
25
|
import Microsoft.AnalysisServices.Tabular
|
|
@@ -27,27 +30,33 @@ class TOMWrapper:
|
|
|
27
30
|
"""
|
|
28
31
|
Convenience wrapper around the TOM object model for a semantic model. Always use the connect_semantic_model function to make sure the TOM object is initialized correctly.
|
|
29
32
|
|
|
30
|
-
`XMLA read/write endpoints <https://learn.microsoft.com/power-bi/enterprise/service-premium-connect-tools#to-enable-read-write-for-a-premium-capacity>`_ must
|
|
31
|
-
be enabled if setting the readonly parameter to False.
|
|
33
|
+
`XMLA read/write endpoints <https://learn.microsoft.com/power-bi/enterprise/service-premium-connect-tools#to-enable-read-write-for-a-premium-capacity>`_ must be enabled if setting the readonly parameter to False.
|
|
32
34
|
"""
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
_dataset_id: UUID
|
|
37
|
+
_dataset_name: str
|
|
38
|
+
_workspace_id: UUID
|
|
39
|
+
_workspace_name: str
|
|
36
40
|
_readonly: bool
|
|
37
41
|
_tables_added: List[str]
|
|
38
42
|
_table_map = dict
|
|
39
43
|
_column_map = dict
|
|
40
44
|
|
|
41
45
|
def __init__(self, dataset, workspace, readonly):
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
|
|
47
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
48
|
+
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
49
|
+
self._dataset_id = dataset_id
|
|
50
|
+
self._dataset_name = dataset_name
|
|
51
|
+
self._workspace_name = workspace_name
|
|
52
|
+
self._workspace_id = workspace_id
|
|
44
53
|
self._readonly = readonly
|
|
45
54
|
self._tables_added = []
|
|
46
55
|
|
|
47
56
|
self._tom_server = fabric.create_tom_server(
|
|
48
|
-
readonly=readonly, workspace=
|
|
57
|
+
readonly=readonly, workspace=workspace_id
|
|
49
58
|
)
|
|
50
|
-
self.model = self._tom_server.Databases.
|
|
59
|
+
self.model = self._tom_server.Databases[dataset_id].Model
|
|
51
60
|
|
|
52
61
|
self._table_map = {}
|
|
53
62
|
self._column_map = {}
|
|
@@ -1634,7 +1643,7 @@ class TOMWrapper:
|
|
|
1634
1643
|
prop = mapping.get(property)
|
|
1635
1644
|
if prop is None:
|
|
1636
1645
|
raise ValueError(
|
|
1637
|
-
f"{icons.red_dot} Invalid property value. Please choose from the following:
|
|
1646
|
+
f"{icons.red_dot} Invalid property value. Please choose from the following: {list(mapping.keys())}."
|
|
1638
1647
|
)
|
|
1639
1648
|
|
|
1640
1649
|
if not any(c.Name == language for c in self.model.Cultures):
|
|
@@ -2160,7 +2169,9 @@ class TOMWrapper:
|
|
|
2160
2169
|
)
|
|
2161
2170
|
"""
|
|
2162
2171
|
df = fabric.evaluate_dax(
|
|
2163
|
-
dataset=self.
|
|
2172
|
+
dataset=self._dataset_id,
|
|
2173
|
+
workspace=self._workspace_id,
|
|
2174
|
+
dax_string=dax_query,
|
|
2164
2175
|
)
|
|
2165
2176
|
value = df["[1]"].iloc[0]
|
|
2166
2177
|
if value != "1":
|
|
@@ -2424,7 +2435,7 @@ class TOMWrapper:
|
|
|
2424
2435
|
)
|
|
2425
2436
|
except Exception:
|
|
2426
2437
|
raise ValueError(
|
|
2427
|
-
f"{icons.red_dot} The '{measure_name}' measure does not exist in the '{self.
|
|
2438
|
+
f"{icons.red_dot} The '{measure_name}' measure does not exist in the '{self._dataset_name}' semantic model within the '{self._workspace_name}'."
|
|
2428
2439
|
)
|
|
2429
2440
|
|
|
2430
2441
|
graphics = [
|
|
@@ -2467,7 +2478,7 @@ class TOMWrapper:
|
|
|
2467
2478
|
)
|
|
2468
2479
|
except Exception:
|
|
2469
2480
|
raise ValueError(
|
|
2470
|
-
f"{icons.red_dot} The '{target}' measure does not exist in the '{self.
|
|
2481
|
+
f"{icons.red_dot} The '{target}' measure does not exist in the '{self._dataset_name}' semantic model within the '{self._workspace_name}'."
|
|
2471
2482
|
)
|
|
2472
2483
|
|
|
2473
2484
|
if measure_target:
|
|
@@ -2793,7 +2804,7 @@ class TOMWrapper:
|
|
|
2793
2804
|
success = True
|
|
2794
2805
|
if not success:
|
|
2795
2806
|
raise ValueError(
|
|
2796
|
-
f"{icons.red_dot} The '{obj}' object was not found in the '{self.
|
|
2807
|
+
f"{icons.red_dot} The '{obj}' object was not found in the '{self._dataset_name}' semantic model."
|
|
2797
2808
|
)
|
|
2798
2809
|
else:
|
|
2799
2810
|
i += 1
|
|
@@ -2881,19 +2892,19 @@ class TOMWrapper:
|
|
|
2881
2892
|
from sempy_labs._list_functions import list_tables
|
|
2882
2893
|
|
|
2883
2894
|
dfT = list_tables(
|
|
2884
|
-
dataset=self.
|
|
2895
|
+
dataset=self._dataset_id, workspace=self._workspace_id, extended=True
|
|
2885
2896
|
)
|
|
2886
2897
|
dfC = fabric.list_columns(
|
|
2887
|
-
dataset=self.
|
|
2898
|
+
dataset=self._dataset_id, workspace=self._workspace_id, extended=True
|
|
2888
2899
|
)
|
|
2889
2900
|
dfP = fabric.list_partitions(
|
|
2890
|
-
dataset=self.
|
|
2901
|
+
dataset=self._dataset_id, workspace=self._workspace_id, extended=True
|
|
2891
2902
|
)
|
|
2892
2903
|
dfH = fabric.list_hierarchies(
|
|
2893
|
-
dataset=self.
|
|
2904
|
+
dataset=self._dataset_id, workspace=self._workspace_id, extended=True
|
|
2894
2905
|
)
|
|
2895
2906
|
dfR = list_relationships(
|
|
2896
|
-
dataset=self.
|
|
2907
|
+
dataset=self._dataset_id, workspace=self._workspace_id, extended=True
|
|
2897
2908
|
)
|
|
2898
2909
|
|
|
2899
2910
|
for t in self.model.Tables:
|
|
@@ -3338,7 +3349,9 @@ class TOMWrapper:
|
|
|
3338
3349
|
usingView = False
|
|
3339
3350
|
|
|
3340
3351
|
if self.is_direct_lake():
|
|
3341
|
-
df = check_fallback_reason(
|
|
3352
|
+
df = check_fallback_reason(
|
|
3353
|
+
dataset=self._dataset_id, workspace=self._workspace_id
|
|
3354
|
+
)
|
|
3342
3355
|
df_filt = df[df["FallbackReasonID"] == 2]
|
|
3343
3356
|
|
|
3344
3357
|
if len(df_filt) > 0:
|
|
@@ -3385,7 +3398,7 @@ class TOMWrapper:
|
|
|
3385
3398
|
|
|
3386
3399
|
if rp is None:
|
|
3387
3400
|
print(
|
|
3388
|
-
f"{icons.yellow_dot} The '{table_name}' table in the '{self.
|
|
3401
|
+
f"{icons.yellow_dot} The '{table_name}' table in the '{self._dataset_name}' semantic model within the '{self._workspace_name}' workspace does not have an incremental refresh policy."
|
|
3389
3402
|
)
|
|
3390
3403
|
else:
|
|
3391
3404
|
print(f"Table Name: {table_name}")
|
|
@@ -3884,14 +3897,14 @@ class TOMWrapper:
|
|
|
3884
3897
|
|
|
3885
3898
|
if table_name is None:
|
|
3886
3899
|
raise ValueError(
|
|
3887
|
-
f"{icons.red_dot} The '{measure_name}' is not a valid measure in the '{self.
|
|
3900
|
+
f"{icons.red_dot} The '{measure_name}' is not a valid measure in the '{self._dataset_name}' semantic model within the '{self._workspace_name}' workspace."
|
|
3888
3901
|
)
|
|
3889
3902
|
|
|
3890
3903
|
table_name = matching_measures[0]
|
|
3891
3904
|
# Validate date table
|
|
3892
3905
|
if not self.is_date_table(date_table):
|
|
3893
3906
|
raise ValueError(
|
|
3894
|
-
f"{icons.red_dot} The '{date_table}' table is not a valid date table in the '{self.
|
|
3907
|
+
f"{icons.red_dot} The '{date_table}' table is not a valid date table in the '{self._dataset_name}' wemantic model within the '{self._workspace_name}' workspace."
|
|
3895
3908
|
)
|
|
3896
3909
|
|
|
3897
3910
|
# Extract date key from date table
|
|
@@ -3903,7 +3916,7 @@ class TOMWrapper:
|
|
|
3903
3916
|
|
|
3904
3917
|
if not matching_columns:
|
|
3905
3918
|
raise ValueError(
|
|
3906
|
-
f"{icons.red_dot} The '{date_table}' table does not have a date key column in the '{self.
|
|
3919
|
+
f"{icons.red_dot} The '{date_table}' table does not have a date key column in the '{self._dataset_name}' semantic model within the '{self._workspace_name}' workspace."
|
|
3907
3920
|
)
|
|
3908
3921
|
|
|
3909
3922
|
date_key = matching_columns[0]
|
|
@@ -4383,7 +4396,6 @@ class TOMWrapper:
|
|
|
4383
4396
|
if isinstance(measure_name, str):
|
|
4384
4397
|
measure_name = [measure_name]
|
|
4385
4398
|
|
|
4386
|
-
workspace_id = fabric.resolve_workspace_id(self._workspace)
|
|
4387
4399
|
client = fabric.FabricRestClient()
|
|
4388
4400
|
|
|
4389
4401
|
if len(measure_name) > max_batch_size:
|
|
@@ -4402,7 +4414,7 @@ class TOMWrapper:
|
|
|
4402
4414
|
"modelItems": [],
|
|
4403
4415
|
},
|
|
4404
4416
|
},
|
|
4405
|
-
"workspaceId":
|
|
4417
|
+
"workspaceId": self._workspace_id,
|
|
4406
4418
|
"artifactInfo": {"artifactType": "SemanticModel"},
|
|
4407
4419
|
}
|
|
4408
4420
|
for m_name in measure_list:
|
|
@@ -4413,7 +4425,7 @@ class TOMWrapper:
|
|
|
4413
4425
|
)
|
|
4414
4426
|
if t_name is None:
|
|
4415
4427
|
raise ValueError(
|
|
4416
|
-
f"{icons.red_dot} The '{m_name}' measure does not exist in the '{self.
|
|
4428
|
+
f"{icons.red_dot} The '{m_name}' measure does not exist in the '{self._dataset_name}' semantic model within the '{self._workspace_name}' workspace."
|
|
4417
4429
|
)
|
|
4418
4430
|
|
|
4419
4431
|
new_item = {
|
|
@@ -4515,6 +4527,40 @@ class TOMWrapper:
|
|
|
4515
4527
|
TOM.ValueFilterBehaviorType, value_filter_behavior
|
|
4516
4528
|
)
|
|
4517
4529
|
|
|
4530
|
+
def add_role_member(self, role_name: str, member: str | List[str]):
|
|
4531
|
+
"""
|
|
4532
|
+
Adds a external model role member (AzureAD) to a role.
|
|
4533
|
+
|
|
4534
|
+
Parameters
|
|
4535
|
+
----------
|
|
4536
|
+
role_name : str
|
|
4537
|
+
The role name.
|
|
4538
|
+
member : str | List[str]
|
|
4539
|
+
The email address(es) of the member(s) to add.
|
|
4540
|
+
"""
|
|
4541
|
+
|
|
4542
|
+
import Microsoft.AnalysisServices.Tabular as TOM
|
|
4543
|
+
|
|
4544
|
+
if isinstance(member, str):
|
|
4545
|
+
member = [member]
|
|
4546
|
+
|
|
4547
|
+
role = self.model.Roles[role_name]
|
|
4548
|
+
current_members = [m.MemberName for m in role.Members]
|
|
4549
|
+
|
|
4550
|
+
for m in member:
|
|
4551
|
+
if m not in current_members:
|
|
4552
|
+
rm = TOM.ExternalModelRoleMember()
|
|
4553
|
+
rm.IdentityProvider = "AzureAD"
|
|
4554
|
+
rm.MemberName = m
|
|
4555
|
+
role.Members.Add(rm)
|
|
4556
|
+
print(
|
|
4557
|
+
f"{icons.green_dot} '{m}' has been added as a member of the '{role_name}' role."
|
|
4558
|
+
)
|
|
4559
|
+
else:
|
|
4560
|
+
print(
|
|
4561
|
+
f"{icons.yellow_dot} '{m}' is already a member in the '{role_name}' role."
|
|
4562
|
+
)
|
|
4563
|
+
|
|
4518
4564
|
def close(self):
|
|
4519
4565
|
|
|
4520
4566
|
if not self._readonly and self.model is not None:
|
|
@@ -4572,9 +4618,9 @@ class TOMWrapper:
|
|
|
4572
4618
|
|
|
4573
4619
|
if len(self._tables_added) > 0:
|
|
4574
4620
|
refresh_semantic_model(
|
|
4575
|
-
dataset=self.
|
|
4621
|
+
dataset=self._dataset_id,
|
|
4576
4622
|
tables=self._tables_added,
|
|
4577
|
-
workspace=self.
|
|
4623
|
+
workspace=self._workspace_id,
|
|
4578
4624
|
)
|
|
4579
4625
|
self.model = None
|
|
4580
4626
|
|
|
@@ -4584,15 +4630,15 @@ class TOMWrapper:
|
|
|
4584
4630
|
@log
|
|
4585
4631
|
@contextmanager
|
|
4586
4632
|
def connect_semantic_model(
|
|
4587
|
-
dataset: str, readonly: bool = True, workspace: Optional[str] = None
|
|
4633
|
+
dataset: str | UUID, readonly: bool = True, workspace: Optional[str] = None
|
|
4588
4634
|
) -> Iterator[TOMWrapper]:
|
|
4589
4635
|
"""
|
|
4590
4636
|
Connects to the Tabular Object Model (TOM) within a semantic model.
|
|
4591
4637
|
|
|
4592
4638
|
Parameters
|
|
4593
4639
|
----------
|
|
4594
|
-
dataset : str
|
|
4595
|
-
Name of the semantic model.
|
|
4640
|
+
dataset : str | UUID
|
|
4641
|
+
Name or ID of the semantic model.
|
|
4596
4642
|
readonly: bool, default=True
|
|
4597
4643
|
Whether the connection is read-only or read/write. Setting this to False enables read/write which saves the changes made back to the server.
|
|
4598
4644
|
workspace : str, default=None
|
|
@@ -4609,10 +4655,6 @@ def connect_semantic_model(
|
|
|
4609
4655
|
# initialize .NET to make sure System and Microsoft.AnalysisServices.Tabular is defined
|
|
4610
4656
|
sempy.fabric._client._utils._init_analysis_services()
|
|
4611
4657
|
|
|
4612
|
-
if workspace is None:
|
|
4613
|
-
workspace_id = fabric.get_workspace_id()
|
|
4614
|
-
workspace = fabric.resolve_workspace_name(workspace_id)
|
|
4615
|
-
|
|
4616
4658
|
tw = TOMWrapper(dataset=dataset, workspace=workspace, readonly=readonly)
|
|
4617
4659
|
try:
|
|
4618
4660
|
yield tw
|
|
File without changes
|
|
File without changes
|
|
File without changes
|