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.

Files changed (35) hide show
  1. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/METADATA +7 -3
  2. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/RECORD +35 -34
  3. sempy_labs/__init__.py +14 -0
  4. sempy_labs/_capacities.py +89 -11
  5. sempy_labs/_capacity_migration.py +167 -60
  6. sempy_labs/_clear_cache.py +3 -3
  7. sempy_labs/_data_pipelines.py +48 -0
  8. sempy_labs/_external_data_shares.py +188 -0
  9. sempy_labs/_generate_semantic_model.py +0 -1
  10. sempy_labs/_git.py +1 -1
  11. sempy_labs/_helper_functions.py +14 -11
  12. sempy_labs/_list_functions.py +6 -3
  13. sempy_labs/_model_bpa.py +5 -5
  14. sempy_labs/_model_bpa_bulk.py +3 -5
  15. sempy_labs/_notebooks.py +4 -3
  16. sempy_labs/_sql.py +2 -2
  17. sempy_labs/_translations.py +14 -14
  18. sempy_labs/_vertipaq.py +121 -101
  19. sempy_labs/_warehouses.py +11 -1
  20. sempy_labs/admin/__init__.py +2 -0
  21. sempy_labs/admin/_basic_functions.py +124 -21
  22. sempy_labs/directlake/_directlake_schema_sync.py +0 -5
  23. sempy_labs/directlake/_generate_shared_expression.py +1 -1
  24. sempy_labs/directlake/_guardrails.py +1 -1
  25. sempy_labs/directlake/_show_unsupported_directlake_objects.py +1 -1
  26. sempy_labs/migration/_create_pqt_file.py +2 -2
  27. sempy_labs/report/_generate_report.py +10 -14
  28. sempy_labs/report/_report_bpa.py +8 -10
  29. sempy_labs/report/_report_functions.py +13 -19
  30. sempy_labs/report/_report_rebind.py +4 -1
  31. sempy_labs/report/_reportwrapper.py +3 -3
  32. sempy_labs/tom/_model.py +109 -34
  33. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/LICENSE +0 -0
  34. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.3.dist-info}/WHEEL +0 -0
  35. {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
- if len(lvl.SourceLineageTag) == 0:
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
- if len(e.SourceLineageTag) == 0:
4310
- e.SourceLineageTag = generate_guid()
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 for m in self.all_measures() if m.Name == ms_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: