semantic-link-labs 0.8.2__py3-none-any.whl → 0.8.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.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/METADATA +7 -3
- {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/RECORD +35 -34
- sempy_labs/__init__.py +14 -0
- sempy_labs/_capacities.py +89 -11
- sempy_labs/_capacity_migration.py +167 -60
- sempy_labs/_clear_cache.py +3 -3
- sempy_labs/_data_pipelines.py +48 -0
- sempy_labs/_external_data_shares.py +188 -0
- sempy_labs/_generate_semantic_model.py +0 -1
- sempy_labs/_git.py +1 -1
- sempy_labs/_helper_functions.py +14 -11
- sempy_labs/_list_functions.py +6 -3
- sempy_labs/_model_bpa.py +5 -5
- sempy_labs/_model_bpa_bulk.py +3 -5
- sempy_labs/_notebooks.py +4 -3
- sempy_labs/_sql.py +2 -2
- sempy_labs/_translations.py +14 -14
- sempy_labs/_vertipaq.py +121 -101
- sempy_labs/_warehouses.py +11 -1
- sempy_labs/admin/__init__.py +2 -0
- sempy_labs/admin/_basic_functions.py +124 -21
- sempy_labs/directlake/_directlake_schema_sync.py +0 -5
- sempy_labs/directlake/_generate_shared_expression.py +1 -1
- sempy_labs/directlake/_guardrails.py +1 -1
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +1 -1
- sempy_labs/migration/_create_pqt_file.py +2 -2
- sempy_labs/report/_generate_report.py +10 -14
- sempy_labs/report/_report_bpa.py +8 -10
- sempy_labs/report/_report_functions.py +13 -19
- sempy_labs/report/_report_rebind.py +4 -1
- sempy_labs/report/_reportwrapper.py +3 -3
- sempy_labs/tom/_model.py +109 -34
- {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/top_level.txt +0 -0
sempy_labs/tom/_model.py
CHANGED
|
@@ -33,6 +33,8 @@ class TOMWrapper:
|
|
|
33
33
|
_workspace: str
|
|
34
34
|
_readonly: bool
|
|
35
35
|
_tables_added: List[str]
|
|
36
|
+
_table_map = dict
|
|
37
|
+
_column_map = dict
|
|
36
38
|
|
|
37
39
|
def __init__(self, dataset, workspace, readonly):
|
|
38
40
|
self._dataset = dataset
|
|
@@ -45,6 +47,18 @@ class TOMWrapper:
|
|
|
45
47
|
)
|
|
46
48
|
self.model = self._tom_server.Databases.GetByName(dataset).Model
|
|
47
49
|
|
|
50
|
+
self._table_map = {}
|
|
51
|
+
self._column_map = {}
|
|
52
|
+
for t in self.model.Tables:
|
|
53
|
+
if len(t.LineageTag) == 0:
|
|
54
|
+
t.LineageTag = generate_guid()
|
|
55
|
+
self._table_map[t.LineageTag] = t.Name
|
|
56
|
+
|
|
57
|
+
for c in self.all_columns():
|
|
58
|
+
if len(c.LineageTag) == 0:
|
|
59
|
+
c.LineageTag = generate_guid()
|
|
60
|
+
self._column_map[c.LineageTag] = [c.Name, c.DataType]
|
|
61
|
+
|
|
48
62
|
def all_columns(self):
|
|
49
63
|
"""
|
|
50
64
|
Outputs a list of all columns within all tables in the semantic model.
|
|
@@ -291,8 +305,6 @@ class TOMWrapper:
|
|
|
291
305
|
obj.LineageTag = generate_guid()
|
|
292
306
|
if source_lineage_tag is not None:
|
|
293
307
|
obj.SourceLineageTag = source_lineage_tag
|
|
294
|
-
else:
|
|
295
|
-
obj.SourceLineageTag = generate_guid()
|
|
296
308
|
if detail_rows_expression is not None:
|
|
297
309
|
drd = TOM.DetailRowsDefinition()
|
|
298
310
|
drd.Expression = detail_rows_expression
|
|
@@ -388,8 +400,6 @@ class TOMWrapper:
|
|
|
388
400
|
obj.LineageTag = generate_guid()
|
|
389
401
|
if source_lineage_tag is not None:
|
|
390
402
|
obj.SourceLineageTag = source_lineage_tag
|
|
391
|
-
else:
|
|
392
|
-
obj.SourceLineageTag = generate_guid()
|
|
393
403
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
394
404
|
|
|
395
405
|
def add_data_column(
|
|
@@ -478,8 +488,6 @@ class TOMWrapper:
|
|
|
478
488
|
obj.LineageTag = generate_guid()
|
|
479
489
|
if source_lineage_tag is not None:
|
|
480
490
|
obj.SourceLineageTag = source_lineage_tag
|
|
481
|
-
else:
|
|
482
|
-
obj.SourceLineagetTag = generate_guid()
|
|
483
491
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
484
492
|
|
|
485
493
|
def add_calculated_column(
|
|
@@ -568,8 +576,6 @@ class TOMWrapper:
|
|
|
568
576
|
obj.LineageTag = generate_guid()
|
|
569
577
|
if source_lineage_tag is not None:
|
|
570
578
|
obj.SourceLineageTag = source_lineage_tag
|
|
571
|
-
else:
|
|
572
|
-
obj.SourceLineagetTag = generate_guid()
|
|
573
579
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
574
580
|
|
|
575
581
|
def add_calculation_item(
|
|
@@ -785,8 +791,6 @@ class TOMWrapper:
|
|
|
785
791
|
obj.LineageTag = generate_guid()
|
|
786
792
|
if source_lineage_tag is not None:
|
|
787
793
|
obj.SourceLineageTag = source_lineage_tag
|
|
788
|
-
else:
|
|
789
|
-
obj.SourceLineagetTag = generate_guid()
|
|
790
794
|
self.model.Tables[table_name].Hierarchies.Add(obj)
|
|
791
795
|
|
|
792
796
|
for col in columns:
|
|
@@ -795,7 +799,6 @@ class TOMWrapper:
|
|
|
795
799
|
lvl.Name = levels[columns.index(col)]
|
|
796
800
|
lvl.Ordinal = columns.index(col)
|
|
797
801
|
lvl.LineageTag = generate_guid()
|
|
798
|
-
lvl.SourceLineageTag = generate_guid()
|
|
799
802
|
self.model.Tables[table_name].Hierarchies[hierarchy_name].Levels.Add(lvl)
|
|
800
803
|
|
|
801
804
|
def add_relationship(
|
|
@@ -969,8 +972,6 @@ class TOMWrapper:
|
|
|
969
972
|
exp.LineageTag = generate_guid()
|
|
970
973
|
if source_lineage_tag is not None:
|
|
971
974
|
exp.SourceLineageTag = source_lineage_tag
|
|
972
|
-
else:
|
|
973
|
-
exp.SourceLineageTag = generate_guid()
|
|
974
975
|
exp.Kind = TOM.ExpressionKind.M
|
|
975
976
|
exp.Expression = expression
|
|
976
977
|
|
|
@@ -2654,8 +2655,6 @@ class TOMWrapper:
|
|
|
2654
2655
|
t.LineageTag = generate_guid()
|
|
2655
2656
|
if source_lineage_tag is not None:
|
|
2656
2657
|
t.SourceLineageTag = source_lineage_tag
|
|
2657
|
-
else:
|
|
2658
|
-
t.SourceLineagetTag = generate_guid()
|
|
2659
2658
|
t.Hidden = hidden
|
|
2660
2659
|
self.model.Tables.Add(t)
|
|
2661
2660
|
|
|
@@ -2710,8 +2709,6 @@ class TOMWrapper:
|
|
|
2710
2709
|
t.LineageTag = generate_guid()
|
|
2711
2710
|
if source_lineage_tag is not None:
|
|
2712
2711
|
t.SourceLineageTag = source_lineage_tag
|
|
2713
|
-
else:
|
|
2714
|
-
t.SourceLineagetTag = generate_guid()
|
|
2715
2712
|
t.Hidden = hidden
|
|
2716
2713
|
t.Partitions.Add(par)
|
|
2717
2714
|
self.model.Tables.Add(t)
|
|
@@ -4281,41 +4278,67 @@ class TOMWrapper:
|
|
|
4281
4278
|
icons.default_schema
|
|
4282
4279
|
)
|
|
4283
4280
|
t.SourceLineageTag = f"[{schema_name}].[{entity_name}]"
|
|
4284
|
-
else:
|
|
4285
|
-
t.SourceLineageTag = generate_guid()
|
|
4286
4281
|
for c in self.all_columns():
|
|
4287
4282
|
if len(c.LineageTag) == 0:
|
|
4288
4283
|
c.LineageTag = generate_guid()
|
|
4289
|
-
if len(c.SourceLineageTag) == 0:
|
|
4290
|
-
c.SourceLineageTag = generate_guid()
|
|
4291
4284
|
for m in self.all_measures():
|
|
4292
4285
|
if len(m.LineageTag) == 0:
|
|
4293
4286
|
m.LineageTag = generate_guid()
|
|
4294
|
-
if len(m.SourceLineageTag) == 0:
|
|
4295
|
-
m.SourceLineageTag = generate_guid()
|
|
4296
4287
|
for h in self.all_hierarchies():
|
|
4297
4288
|
if len(h.LineageTag) == 0:
|
|
4298
4289
|
h.LineageTag = generate_guid()
|
|
4299
|
-
if len(h.SourceLineageTag) == 0:
|
|
4300
|
-
h.SourceLineageTag = generate_guid()
|
|
4301
4290
|
for lvl in self.all_levels():
|
|
4302
4291
|
if len(lvl.LineageTag) == 0:
|
|
4303
4292
|
lvl.LineageTag = generate_guid()
|
|
4304
|
-
|
|
4305
|
-
lvl.SourceLineageTag = generate_guid()
|
|
4306
|
-
for e in self.model.Expressions():
|
|
4293
|
+
for e in self.model.Expressions:
|
|
4307
4294
|
if len(e.LineageTag) == 0:
|
|
4308
4295
|
e.LineageTag = generate_guid()
|
|
4309
|
-
|
|
4310
|
-
|
|
4296
|
+
|
|
4297
|
+
def add_changed_property(self, object, property: str):
|
|
4298
|
+
"""
|
|
4299
|
+
Adds a `ChangedProperty <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.changedproperty.property?view=analysisservices-dotnet#microsoft-analysisservices-tabular-changedproperty-property>`_ property to a semantic model object. Only adds the property if it does not already exist for the object.
|
|
4300
|
+
|
|
4301
|
+
Parameters
|
|
4302
|
+
----------
|
|
4303
|
+
object : TOM Object
|
|
4304
|
+
The TOM object within the semantic model.
|
|
4305
|
+
property : str
|
|
4306
|
+
The property to set (i.e. 'Name', 'DataType').
|
|
4307
|
+
"""
|
|
4308
|
+
|
|
4309
|
+
import Microsoft.AnalysisServices.Tabular as TOM
|
|
4310
|
+
|
|
4311
|
+
# Only add the property if it does not already exist for that object
|
|
4312
|
+
if not any(c.Property == property for c in object.ChangedProperties):
|
|
4313
|
+
cp = TOM.ChangedProperty()
|
|
4314
|
+
cp.Property = property
|
|
4315
|
+
object.ChangedProperties.Add(cp)
|
|
4316
|
+
|
|
4317
|
+
def remove_changed_property(self, object, property: str):
|
|
4318
|
+
"""
|
|
4319
|
+
Removes a `ChangedProperty <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.changedproperty.property?view=analysisservices-dotnet#microsoft-analysisservices-tabular-changedproperty-property>`_ property to a semantic model object. Only adds the property if it does not already exist for the object.
|
|
4320
|
+
|
|
4321
|
+
Parameters
|
|
4322
|
+
----------
|
|
4323
|
+
object : TOM Object
|
|
4324
|
+
The TOM object within the semantic model.
|
|
4325
|
+
property : str
|
|
4326
|
+
The property to set (i.e. 'Name', 'DataType').
|
|
4327
|
+
"""
|
|
4328
|
+
|
|
4329
|
+
for cp in object.ChangedProperties:
|
|
4330
|
+
if cp.Property == property:
|
|
4331
|
+
object.ChangedProperties.Remove(cp)
|
|
4311
4332
|
|
|
4312
4333
|
def generate_measure_descriptions(
|
|
4313
4334
|
self,
|
|
4314
4335
|
measure_name: Optional[str | List[str]] = None,
|
|
4315
4336
|
max_batch_size: Optional[int] = 5,
|
|
4316
|
-
):
|
|
4337
|
+
) -> pd.DataFrame:
|
|
4317
4338
|
"""
|
|
4318
|
-
Auto-generates descriptions for measures using an LLM.
|
|
4339
|
+
Auto-generates descriptions for measures using an LLM. This function requires a paid F-sku (Fabric) of F64 or higher.
|
|
4340
|
+
Setting the 'readonly' parameter in connect_semantic_model to True will allow you to see the auto-generated descriptions in a dataframe. Setting the 'readonly' parameter
|
|
4341
|
+
to False will update the descriptions for the measures within the 'measure_name' parameter.
|
|
4319
4342
|
|
|
4320
4343
|
Parameters
|
|
4321
4344
|
----------
|
|
@@ -4324,9 +4347,21 @@ class TOMWrapper:
|
|
|
4324
4347
|
Defaults to None which generates descriptions for all measures in the semantic model.
|
|
4325
4348
|
max_batch_size : int, default=5
|
|
4326
4349
|
Sets the max batch size for each API call.
|
|
4350
|
+
|
|
4351
|
+
Returns
|
|
4352
|
+
-------
|
|
4353
|
+
pandas.DataFrame
|
|
4354
|
+
A pandas dataframe showing the updated measure(s) and their new description(s).
|
|
4327
4355
|
"""
|
|
4328
4356
|
|
|
4357
|
+
df = pd.DataFrame(
|
|
4358
|
+
columns=["Table Name", "Measure Name", "Expression", "Description"]
|
|
4359
|
+
)
|
|
4360
|
+
data = []
|
|
4361
|
+
|
|
4329
4362
|
# import concurrent.futures
|
|
4363
|
+
if measure_name is None:
|
|
4364
|
+
measure_name = [m.Name for m in self.all_measures()]
|
|
4330
4365
|
|
|
4331
4366
|
if isinstance(measure_name, str):
|
|
4332
4367
|
measure_name = [measure_name]
|
|
@@ -4383,11 +4418,28 @@ class TOMWrapper:
|
|
|
4383
4418
|
if ms_name.startswith("urn: "):
|
|
4384
4419
|
ms_name = ms_name[5:]
|
|
4385
4420
|
desc = item.get("description")
|
|
4386
|
-
table_name = next(
|
|
4387
|
-
m.Parent.Name
|
|
4421
|
+
(table_name, expr) = next(
|
|
4422
|
+
(m.Parent.Name, m.Expression)
|
|
4423
|
+
for m in self.all_measures()
|
|
4424
|
+
if m.Name == ms_name
|
|
4388
4425
|
)
|
|
4389
4426
|
self.model.Tables[table_name].Measures[ms_name].Description = desc
|
|
4390
4427
|
|
|
4428
|
+
# Collect new descriptions in a dataframe
|
|
4429
|
+
new_data = {
|
|
4430
|
+
"Table Name": table_name,
|
|
4431
|
+
"Measure Name": ms_name,
|
|
4432
|
+
"Expression": expr,
|
|
4433
|
+
"Description": desc,
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
data.append(new_data)
|
|
4437
|
+
|
|
4438
|
+
if data:
|
|
4439
|
+
df = pd.concat([df, pd.DataFrame(data)], ignore_index=True)
|
|
4440
|
+
|
|
4441
|
+
return df
|
|
4442
|
+
|
|
4391
4443
|
# def process_measure(m):
|
|
4392
4444
|
# table_name = m.Parent.Name
|
|
4393
4445
|
# m_name = m.Name
|
|
@@ -4425,6 +4477,29 @@ class TOMWrapper:
|
|
|
4425
4477
|
|
|
4426
4478
|
def close(self):
|
|
4427
4479
|
if not self._readonly and self.model is not None:
|
|
4480
|
+
|
|
4481
|
+
import Microsoft.AnalysisServices.Tabular as TOM
|
|
4482
|
+
|
|
4483
|
+
# ChangedProperty logic
|
|
4484
|
+
for t in self.model.Tables:
|
|
4485
|
+
if any(
|
|
4486
|
+
p.SourceType == TOM.PartitionSourceType.Entity for p in t.Partitions
|
|
4487
|
+
):
|
|
4488
|
+
if t.LineageTag in list(self._table_map.keys()):
|
|
4489
|
+
if self._table_map.get(t.LineageTag) != t.Name:
|
|
4490
|
+
self.add_changed_property(object=t, property="Name")
|
|
4491
|
+
|
|
4492
|
+
for c in self.all_columns():
|
|
4493
|
+
if c.LineageTag in list(self._column_map.keys()):
|
|
4494
|
+
if any(
|
|
4495
|
+
p.SourceType == TOM.PartitionSourceType.Entity
|
|
4496
|
+
for p in c.Parent.Partitions
|
|
4497
|
+
):
|
|
4498
|
+
if self._column_map.get(c.LineageTag)[0] != c.Name:
|
|
4499
|
+
self.add_changed_property(object=c, property="Name")
|
|
4500
|
+
if self._column_map.get(c.LineageTag)[1] != c.DataType:
|
|
4501
|
+
self.add_changed_property(object=c, property="DataType")
|
|
4502
|
+
|
|
4428
4503
|
self.model.SaveChanges()
|
|
4429
4504
|
|
|
4430
4505
|
if len(self._tables_added) > 0:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|