semantic-link-labs 0.7.4__py3-none-any.whl → 0.8.1__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.4.dist-info → semantic_link_labs-0.8.1.dist-info}/METADATA +43 -7
- {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/RECORD +59 -40
- {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/WHEEL +1 -1
- sempy_labs/__init__.py +116 -58
- sempy_labs/_ai.py +0 -2
- sempy_labs/_capacities.py +39 -3
- sempy_labs/_capacity_migration.py +623 -0
- sempy_labs/_clear_cache.py +8 -8
- sempy_labs/_connections.py +15 -13
- sempy_labs/_data_pipelines.py +118 -0
- sempy_labs/_documentation.py +144 -0
- sempy_labs/_eventhouses.py +118 -0
- sempy_labs/_eventstreams.py +118 -0
- sempy_labs/_generate_semantic_model.py +3 -3
- sempy_labs/_git.py +23 -24
- sempy_labs/_helper_functions.py +140 -47
- sempy_labs/_icons.py +40 -0
- sempy_labs/_kql_databases.py +134 -0
- sempy_labs/_kql_querysets.py +124 -0
- sempy_labs/_list_functions.py +218 -421
- sempy_labs/_mirrored_warehouses.py +50 -0
- sempy_labs/_ml_experiments.py +122 -0
- sempy_labs/_ml_models.py +120 -0
- sempy_labs/_model_auto_build.py +0 -4
- sempy_labs/_model_bpa.py +10 -12
- sempy_labs/_model_bpa_bulk.py +8 -7
- sempy_labs/_model_dependencies.py +26 -18
- sempy_labs/_notebooks.py +5 -16
- sempy_labs/_query_scale_out.py +6 -5
- sempy_labs/_refresh_semantic_model.py +7 -19
- sempy_labs/_spark.py +40 -45
- sempy_labs/_sql.py +60 -15
- sempy_labs/_vertipaq.py +25 -25
- sempy_labs/_warehouses.py +132 -0
- sempy_labs/_workspaces.py +0 -3
- sempy_labs/admin/__init__.py +53 -0
- sempy_labs/admin/_basic_functions.py +888 -0
- sempy_labs/admin/_domains.py +411 -0
- sempy_labs/directlake/_directlake_schema_sync.py +1 -1
- sempy_labs/directlake/_dl_helper.py +32 -16
- sempy_labs/directlake/_generate_shared_expression.py +11 -14
- sempy_labs/directlake/_guardrails.py +7 -7
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +14 -24
- sempy_labs/directlake/_update_directlake_partition_entity.py +1 -1
- sempy_labs/directlake/_warm_cache.py +1 -1
- sempy_labs/lakehouse/_get_lakehouse_tables.py +3 -3
- sempy_labs/lakehouse/_lakehouse.py +3 -2
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +5 -0
- sempy_labs/report/__init__.py +9 -6
- sempy_labs/report/_generate_report.py +1 -1
- sempy_labs/report/_report_bpa.py +369 -0
- sempy_labs/report/_report_bpa_rules.py +113 -0
- sempy_labs/report/_report_helper.py +254 -0
- sempy_labs/report/_report_list_functions.py +95 -0
- sempy_labs/report/_report_rebind.py +0 -4
- sempy_labs/report/_reportwrapper.py +2037 -0
- sempy_labs/tom/_model.py +333 -22
- {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/LICENSE +0 -0
- {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/top_level.txt +0 -0
sempy_labs/tom/_model.py
CHANGED
|
@@ -3,7 +3,10 @@ import sempy.fabric as fabric
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import re
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from sempy_labs._helper_functions import
|
|
6
|
+
from sempy_labs._helper_functions import (
|
|
7
|
+
format_dax_object_name,
|
|
8
|
+
generate_guid,
|
|
9
|
+
)
|
|
7
10
|
from sempy_labs._list_functions import list_relationships
|
|
8
11
|
from sempy_labs._refresh_semantic_model import refresh_semantic_model
|
|
9
12
|
from sempy_labs.directlake._dl_helper import check_fallback_reason
|
|
@@ -11,6 +14,7 @@ from contextlib import contextmanager
|
|
|
11
14
|
from typing import List, Iterator, Optional, Union, TYPE_CHECKING
|
|
12
15
|
from sempy._utils._log import log
|
|
13
16
|
import sempy_labs._icons as icons
|
|
17
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
14
18
|
|
|
15
19
|
if TYPE_CHECKING:
|
|
16
20
|
import Microsoft.AnalysisServices.Tabular
|
|
@@ -226,11 +230,14 @@ class TOMWrapper:
|
|
|
226
230
|
measure_name: str,
|
|
227
231
|
expression: str,
|
|
228
232
|
format_string: Optional[str] = None,
|
|
229
|
-
hidden:
|
|
233
|
+
hidden: bool = False,
|
|
230
234
|
description: Optional[str] = None,
|
|
231
235
|
display_folder: Optional[str] = None,
|
|
232
236
|
format_string_expression: Optional[str] = None,
|
|
237
|
+
data_category: Optional[str] = None,
|
|
238
|
+
lineage_tag: Optional[str] = None,
|
|
233
239
|
source_lineage_tag: Optional[str] = None,
|
|
240
|
+
detail_rows_expression: Optional[str] = None,
|
|
234
241
|
):
|
|
235
242
|
"""
|
|
236
243
|
Adds a measure to the semantic model.
|
|
@@ -253,8 +260,14 @@ class TOMWrapper:
|
|
|
253
260
|
The display folder in which the measure will reside.
|
|
254
261
|
format_string_expression : str, default=None
|
|
255
262
|
The format string expression.
|
|
263
|
+
data_category : str, default=None
|
|
264
|
+
Specifies the type of data contained in the measure so that you can add custom behaviors based on measure type.
|
|
265
|
+
lineage_tag : str, default=None
|
|
266
|
+
A tag that represents the lineage of the object.
|
|
256
267
|
source_lineage_tag : str, default=None
|
|
257
268
|
A tag that represents the lineage of the source for the object.
|
|
269
|
+
detail_rows_expression : str, default=None
|
|
270
|
+
The detail rows expression.
|
|
258
271
|
"""
|
|
259
272
|
import Microsoft.AnalysisServices.Tabular as TOM
|
|
260
273
|
|
|
@@ -272,8 +285,20 @@ class TOMWrapper:
|
|
|
272
285
|
fsd = TOM.FormatStringDefinition()
|
|
273
286
|
fsd.Expression = format_string_expression
|
|
274
287
|
obj.FormatStringDefinition = fsd
|
|
288
|
+
if lineage_tag is not None:
|
|
289
|
+
obj.LineageTag = lineage_tag
|
|
290
|
+
else:
|
|
291
|
+
obj.LineageTag = generate_guid()
|
|
275
292
|
if source_lineage_tag is not None:
|
|
276
293
|
obj.SourceLineageTag = source_lineage_tag
|
|
294
|
+
else:
|
|
295
|
+
obj.SourceLineageTag = generate_guid()
|
|
296
|
+
if detail_rows_expression is not None:
|
|
297
|
+
drd = TOM.DetailRowsDefinition()
|
|
298
|
+
drd.Expression = detail_rows_expression
|
|
299
|
+
obj.DetailRowsDefinition = drd
|
|
300
|
+
if data_category is not None:
|
|
301
|
+
obj.DataCategory = data_category
|
|
277
302
|
|
|
278
303
|
self.model.Tables[table_name].Measures.Add(obj)
|
|
279
304
|
|
|
@@ -284,12 +309,13 @@ class TOMWrapper:
|
|
|
284
309
|
source_column: str,
|
|
285
310
|
data_type: str,
|
|
286
311
|
format_string: Optional[str] = None,
|
|
287
|
-
hidden:
|
|
312
|
+
hidden: bool = False,
|
|
288
313
|
description: Optional[str] = None,
|
|
289
314
|
display_folder: Optional[str] = None,
|
|
290
315
|
data_category: Optional[str] = None,
|
|
291
|
-
key:
|
|
316
|
+
key: bool = False,
|
|
292
317
|
summarize_by: Optional[str] = None,
|
|
318
|
+
lineage_tag: Optional[str] = None,
|
|
293
319
|
source_lineage_tag: Optional[str] = None,
|
|
294
320
|
):
|
|
295
321
|
"""
|
|
@@ -320,6 +346,8 @@ class TOMWrapper:
|
|
|
320
346
|
summarize_by : str, default=None
|
|
321
347
|
Sets the value for the Summarize By property of the column.
|
|
322
348
|
Defaults to None resolves to 'Default'.
|
|
349
|
+
lineage_tag : str, default=None
|
|
350
|
+
A tag that represents the lineage of the object.
|
|
323
351
|
source_lineage_tag : str, default=None
|
|
324
352
|
A tag that represents the lineage of the source for the object.
|
|
325
353
|
"""
|
|
@@ -354,8 +382,14 @@ class TOMWrapper:
|
|
|
354
382
|
obj.DisplayFolder = display_folder
|
|
355
383
|
if data_category is not None:
|
|
356
384
|
obj.DataCategory = data_category
|
|
385
|
+
if lineage_tag is not None:
|
|
386
|
+
obj.LineageTag = lineage_tag
|
|
387
|
+
else:
|
|
388
|
+
obj.LineageTag = generate_guid()
|
|
357
389
|
if source_lineage_tag is not None:
|
|
358
390
|
obj.SourceLineageTag = source_lineage_tag
|
|
391
|
+
else:
|
|
392
|
+
obj.SourceLineageTag = generate_guid()
|
|
359
393
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
360
394
|
|
|
361
395
|
def add_data_column(
|
|
@@ -365,12 +399,13 @@ class TOMWrapper:
|
|
|
365
399
|
source_column: str,
|
|
366
400
|
data_type: str,
|
|
367
401
|
format_string: Optional[str] = None,
|
|
368
|
-
hidden:
|
|
402
|
+
hidden: bool = False,
|
|
369
403
|
description: Optional[str] = None,
|
|
370
404
|
display_folder: Optional[str] = None,
|
|
371
405
|
data_category: Optional[str] = None,
|
|
372
|
-
key:
|
|
406
|
+
key: bool = False,
|
|
373
407
|
summarize_by: Optional[str] = None,
|
|
408
|
+
lineage_tag: Optional[str] = None,
|
|
374
409
|
source_lineage_tag: Optional[str] = None,
|
|
375
410
|
):
|
|
376
411
|
"""
|
|
@@ -401,6 +436,8 @@ class TOMWrapper:
|
|
|
401
436
|
summarize_by : str, default=None
|
|
402
437
|
Sets the value for the Summarize By property of the column.
|
|
403
438
|
Defaults to None resolves to 'Default'.
|
|
439
|
+
lineage_tag : str, default=None
|
|
440
|
+
A tag that represents the lineage of the object.
|
|
404
441
|
source_lineage_tag : str, default=None
|
|
405
442
|
A tag that represents the lineage of the source for the object.
|
|
406
443
|
"""
|
|
@@ -435,8 +472,14 @@ class TOMWrapper:
|
|
|
435
472
|
obj.DisplayFolder = display_folder
|
|
436
473
|
if data_category is not None:
|
|
437
474
|
obj.DataCategory = data_category
|
|
475
|
+
if lineage_tag is not None:
|
|
476
|
+
obj.LineageTag = lineage_tag
|
|
477
|
+
else:
|
|
478
|
+
obj.LineageTag = generate_guid()
|
|
438
479
|
if source_lineage_tag is not None:
|
|
439
480
|
obj.SourceLineageTag = source_lineage_tag
|
|
481
|
+
else:
|
|
482
|
+
obj.SourceLineagetTag = generate_guid()
|
|
440
483
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
441
484
|
|
|
442
485
|
def add_calculated_column(
|
|
@@ -446,12 +489,13 @@ class TOMWrapper:
|
|
|
446
489
|
expression: str,
|
|
447
490
|
data_type: str,
|
|
448
491
|
format_string: Optional[str] = None,
|
|
449
|
-
hidden:
|
|
492
|
+
hidden: bool = False,
|
|
450
493
|
description: Optional[str] = None,
|
|
451
494
|
display_folder: Optional[str] = None,
|
|
452
495
|
data_category: Optional[str] = None,
|
|
453
|
-
key:
|
|
496
|
+
key: bool = False,
|
|
454
497
|
summarize_by: Optional[str] = None,
|
|
498
|
+
lineage_tag: Optional[str] = None,
|
|
455
499
|
source_lineage_tag: Optional[str] = None,
|
|
456
500
|
):
|
|
457
501
|
"""
|
|
@@ -482,6 +526,8 @@ class TOMWrapper:
|
|
|
482
526
|
summarize_by : str, default=None
|
|
483
527
|
Sets the value for the Summarize By property of the column.
|
|
484
528
|
Defaults to None which resolves to 'Default'.
|
|
529
|
+
lineage_tag : str, default=None
|
|
530
|
+
A tag that represents the lineage of the object.
|
|
485
531
|
source_lineage_tag : str, default=None
|
|
486
532
|
A tag that represents the lineage of the source for the object.
|
|
487
533
|
"""
|
|
@@ -516,8 +562,14 @@ class TOMWrapper:
|
|
|
516
562
|
obj.DisplayFolder = display_folder
|
|
517
563
|
if data_category is not None:
|
|
518
564
|
obj.DataCategory = data_category
|
|
565
|
+
if lineage_tag is not None:
|
|
566
|
+
obj.LineageTag = lineage_tag
|
|
567
|
+
else:
|
|
568
|
+
obj.LineageTag = generate_guid()
|
|
519
569
|
if source_lineage_tag is not None:
|
|
520
570
|
obj.SourceLineageTag = source_lineage_tag
|
|
571
|
+
else:
|
|
572
|
+
obj.SourceLineagetTag = generate_guid()
|
|
521
573
|
self.model.Tables[table_name].Columns.Add(obj)
|
|
522
574
|
|
|
523
575
|
def add_calculation_item(
|
|
@@ -676,7 +728,8 @@ class TOMWrapper:
|
|
|
676
728
|
columns: List[str],
|
|
677
729
|
levels: Optional[List[str]] = None,
|
|
678
730
|
hierarchy_description: Optional[str] = None,
|
|
679
|
-
hierarchy_hidden:
|
|
731
|
+
hierarchy_hidden: bool = False,
|
|
732
|
+
lineage_tag: Optional[str] = None,
|
|
680
733
|
source_lineage_tag: Optional[str] = None,
|
|
681
734
|
):
|
|
682
735
|
"""
|
|
@@ -696,6 +749,8 @@ class TOMWrapper:
|
|
|
696
749
|
A description of the hierarchy.
|
|
697
750
|
hierarchy_hidden : bool, default=False
|
|
698
751
|
Whether the hierarchy is visible or hidden.
|
|
752
|
+
lineage_tag : str, default=None
|
|
753
|
+
A tag that represents the lineage of the object.
|
|
699
754
|
source_lineage_tag : str, default=None
|
|
700
755
|
A tag that represents the lineage of the source for the object.
|
|
701
756
|
"""
|
|
@@ -724,8 +779,14 @@ class TOMWrapper:
|
|
|
724
779
|
obj.IsHidden = hierarchy_hidden
|
|
725
780
|
if hierarchy_description is not None:
|
|
726
781
|
obj.Description = hierarchy_description
|
|
782
|
+
if lineage_tag is not None:
|
|
783
|
+
obj.LineageTag = lineage_tag
|
|
784
|
+
else:
|
|
785
|
+
obj.LineageTag = generate_guid()
|
|
727
786
|
if source_lineage_tag is not None:
|
|
728
787
|
obj.SourceLineageTag = source_lineage_tag
|
|
788
|
+
else:
|
|
789
|
+
obj.SourceLineagetTag = generate_guid()
|
|
729
790
|
self.model.Tables[table_name].Hierarchies.Add(obj)
|
|
730
791
|
|
|
731
792
|
for col in columns:
|
|
@@ -733,6 +794,8 @@ class TOMWrapper:
|
|
|
733
794
|
lvl.Column = self.model.Tables[table_name].Columns[col]
|
|
734
795
|
lvl.Name = levels[columns.index(col)]
|
|
735
796
|
lvl.Ordinal = columns.index(col)
|
|
797
|
+
lvl.LineageTag = generate_guid()
|
|
798
|
+
lvl.SourceLineageTag = generate_guid()
|
|
736
799
|
self.model.Tables[table_name].Hierarchies[hierarchy_name].Levels.Add(lvl)
|
|
737
800
|
|
|
738
801
|
def add_relationship(
|
|
@@ -744,9 +807,9 @@ class TOMWrapper:
|
|
|
744
807
|
from_cardinality: str,
|
|
745
808
|
to_cardinality: str,
|
|
746
809
|
cross_filtering_behavior: Optional[str] = None,
|
|
747
|
-
is_active:
|
|
810
|
+
is_active: bool = True,
|
|
748
811
|
security_filtering_behavior: Optional[str] = None,
|
|
749
|
-
rely_on_referential_integrity:
|
|
812
|
+
rely_on_referential_integrity: bool = False,
|
|
750
813
|
):
|
|
751
814
|
"""
|
|
752
815
|
Adds a `relationship <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.singlecolumnrelationship?view=analysisservices-dotnet>`_ to a semantic model.
|
|
@@ -818,7 +881,7 @@ class TOMWrapper:
|
|
|
818
881
|
name: str,
|
|
819
882
|
precedence: int,
|
|
820
883
|
description: Optional[str] = None,
|
|
821
|
-
hidden:
|
|
884
|
+
hidden: bool = False,
|
|
822
885
|
):
|
|
823
886
|
"""
|
|
824
887
|
Adds a `calculation group <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.calculationgroup?view=analysisservices-dotnet>`_ to a semantic model.
|
|
@@ -875,6 +938,7 @@ class TOMWrapper:
|
|
|
875
938
|
name: str,
|
|
876
939
|
expression: str,
|
|
877
940
|
description: Optional[str] = None,
|
|
941
|
+
lineage_tag: Optional[str] = None,
|
|
878
942
|
source_lineage_tag: Optional[str] = None,
|
|
879
943
|
):
|
|
880
944
|
"""
|
|
@@ -888,6 +952,8 @@ class TOMWrapper:
|
|
|
888
952
|
The M expression of the expression.
|
|
889
953
|
description : str, default=None
|
|
890
954
|
A description of the expression.
|
|
955
|
+
lineage_tag : str, default=None
|
|
956
|
+
A tag that represents the lineage of the object.
|
|
891
957
|
source_lineage_tag : str, default=None
|
|
892
958
|
A tag that represents the lineage of the source for the object.
|
|
893
959
|
"""
|
|
@@ -897,8 +963,14 @@ class TOMWrapper:
|
|
|
897
963
|
exp.Name = name
|
|
898
964
|
if description is not None:
|
|
899
965
|
exp.Description = description
|
|
966
|
+
if lineage_tag is not None:
|
|
967
|
+
exp.LineageTag = lineage_tag
|
|
968
|
+
else:
|
|
969
|
+
exp.LineageTag = generate_guid()
|
|
900
970
|
if source_lineage_tag is not None:
|
|
901
971
|
exp.SourceLineageTag = source_lineage_tag
|
|
972
|
+
else:
|
|
973
|
+
exp.SourceLineageTag = generate_guid()
|
|
902
974
|
exp.Kind = TOM.ExpressionKind.M
|
|
903
975
|
exp.Expression = expression
|
|
904
976
|
|
|
@@ -992,6 +1064,7 @@ class TOMWrapper:
|
|
|
992
1064
|
entity_name: str,
|
|
993
1065
|
expression: Optional[str] = None,
|
|
994
1066
|
description: Optional[str] = None,
|
|
1067
|
+
schema_name: str = "dbo",
|
|
995
1068
|
):
|
|
996
1069
|
"""
|
|
997
1070
|
Adds an entity partition to a table within a semantic model.
|
|
@@ -1001,12 +1074,14 @@ class TOMWrapper:
|
|
|
1001
1074
|
table_name : str
|
|
1002
1075
|
Name of the table.
|
|
1003
1076
|
entity_name : str
|
|
1004
|
-
Name of the lakehouse table.
|
|
1077
|
+
Name of the lakehouse/warehouse table.
|
|
1005
1078
|
expression : TOM Object, default=None
|
|
1006
1079
|
The expression used by the table.
|
|
1007
1080
|
Defaults to None which resolves to the 'DatabaseQuery' expression.
|
|
1008
1081
|
description : str, default=None
|
|
1009
1082
|
A description for the partition.
|
|
1083
|
+
schema_name : str, default="dbo"
|
|
1084
|
+
The schema name.
|
|
1010
1085
|
"""
|
|
1011
1086
|
import Microsoft.AnalysisServices.Tabular as TOM
|
|
1012
1087
|
|
|
@@ -1017,6 +1092,7 @@ class TOMWrapper:
|
|
|
1017
1092
|
ep.ExpressionSource = self.model.Expressions["DatabaseQuery"]
|
|
1018
1093
|
else:
|
|
1019
1094
|
ep.ExpressionSource = self.model.Expressions[expression]
|
|
1095
|
+
ep.SchemaName = schema_name
|
|
1020
1096
|
p = TOM.Partition()
|
|
1021
1097
|
p.Name = table_name
|
|
1022
1098
|
p.Source = ep
|
|
@@ -1025,6 +1101,9 @@ class TOMWrapper:
|
|
|
1025
1101
|
p.Description = description
|
|
1026
1102
|
|
|
1027
1103
|
self.model.Tables[table_name].Partitions.Add(p)
|
|
1104
|
+
self.model.Tables[table_name].SourceLineageTag = (
|
|
1105
|
+
f"[{schema_name}].[{entity_name}]"
|
|
1106
|
+
)
|
|
1028
1107
|
|
|
1029
1108
|
def set_alternate_of(
|
|
1030
1109
|
self,
|
|
@@ -1605,13 +1684,25 @@ class TOMWrapper:
|
|
|
1605
1684
|
objType = object.ObjectType
|
|
1606
1685
|
|
|
1607
1686
|
# Have to remove translations and perspectives on the object before removing it.
|
|
1608
|
-
if objType in [
|
|
1687
|
+
if objType in [
|
|
1688
|
+
TOM.ObjectType.Table,
|
|
1689
|
+
TOM.ObjectType.Column,
|
|
1690
|
+
TOM.ObjectType.Measure,
|
|
1691
|
+
TOM.ObjectType.Hierarchy,
|
|
1692
|
+
TOM.ObjectType.Level,
|
|
1693
|
+
]:
|
|
1609
1694
|
for lang in object.Model.Cultures:
|
|
1610
1695
|
try:
|
|
1611
1696
|
self.remove_translation(object=object, language=lang.Name)
|
|
1612
1697
|
except Exception:
|
|
1613
1698
|
pass
|
|
1614
|
-
if objType in [
|
|
1699
|
+
if objType in [
|
|
1700
|
+
TOM.ObjectType.Table,
|
|
1701
|
+
TOM.ObjectType.Column,
|
|
1702
|
+
TOM.ObjectType.Measure,
|
|
1703
|
+
TOM.ObjectType.Hierarchy,
|
|
1704
|
+
TOM.ObjectType.Level,
|
|
1705
|
+
]:
|
|
1615
1706
|
for persp in object.Model.Perspectives:
|
|
1616
1707
|
try:
|
|
1617
1708
|
self.remove_from_perspective(
|
|
@@ -2424,7 +2515,7 @@ class TOMWrapper:
|
|
|
2424
2515
|
)
|
|
2425
2516
|
|
|
2426
2517
|
def set_is_available_in_mdx(
|
|
2427
|
-
self, table_name: str, column_name: str, value:
|
|
2518
|
+
self, table_name: str, column_name: str, value: bool = False
|
|
2428
2519
|
):
|
|
2429
2520
|
"""
|
|
2430
2521
|
Sets the `IsAvailableInMDX <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.column.isavailableinmdx?view=analysisservices-dotnet#microsoft-analysisservices-tabular-column-isavailableinmdx>`_ property on a column.
|
|
@@ -2527,7 +2618,8 @@ class TOMWrapper:
|
|
|
2527
2618
|
name: str,
|
|
2528
2619
|
description: Optional[str] = None,
|
|
2529
2620
|
data_category: Optional[str] = None,
|
|
2530
|
-
hidden:
|
|
2621
|
+
hidden: bool = False,
|
|
2622
|
+
lineage_tag: Optional[str] = None,
|
|
2531
2623
|
source_lineage_tag: Optional[str] = None,
|
|
2532
2624
|
):
|
|
2533
2625
|
"""
|
|
@@ -2543,6 +2635,8 @@ class TOMWrapper:
|
|
|
2543
2635
|
The data category for the table.
|
|
2544
2636
|
hidden : bool, default=False
|
|
2545
2637
|
Whether the table is hidden or visible.
|
|
2638
|
+
lineage_tag : str, default=None
|
|
2639
|
+
A tag that represents the lineage of the object.
|
|
2546
2640
|
source_lineage_tag : str, default=None
|
|
2547
2641
|
A tag that represents the lineage of the source for the object.
|
|
2548
2642
|
"""
|
|
@@ -2554,8 +2648,14 @@ class TOMWrapper:
|
|
|
2554
2648
|
t.Description = description
|
|
2555
2649
|
if data_category is not None:
|
|
2556
2650
|
t.DataCategory = data_category
|
|
2651
|
+
if lineage_tag is not None:
|
|
2652
|
+
t.LineageTag = lineage_tag
|
|
2653
|
+
else:
|
|
2654
|
+
t.LineageTag = generate_guid()
|
|
2557
2655
|
if source_lineage_tag is not None:
|
|
2558
2656
|
t.SourceLineageTag = source_lineage_tag
|
|
2657
|
+
else:
|
|
2658
|
+
t.SourceLineagetTag = generate_guid()
|
|
2559
2659
|
t.Hidden = hidden
|
|
2560
2660
|
self.model.Tables.Add(t)
|
|
2561
2661
|
|
|
@@ -2565,7 +2665,9 @@ class TOMWrapper:
|
|
|
2565
2665
|
expression: str,
|
|
2566
2666
|
description: Optional[str] = None,
|
|
2567
2667
|
data_category: Optional[str] = None,
|
|
2568
|
-
hidden:
|
|
2668
|
+
hidden: bool = False,
|
|
2669
|
+
lineage_tag: Optional[str] = None,
|
|
2670
|
+
source_lineage_tag: Optional[str] = None,
|
|
2569
2671
|
):
|
|
2570
2672
|
"""
|
|
2571
2673
|
Adds a calculated table to the semantic model.
|
|
@@ -2582,6 +2684,10 @@ class TOMWrapper:
|
|
|
2582
2684
|
The data category for the table.
|
|
2583
2685
|
hidden : bool, default=False
|
|
2584
2686
|
Whether the table is hidden or visible.
|
|
2687
|
+
lineage_tag : str, default=None
|
|
2688
|
+
A tag that represents the lineage of the object.
|
|
2689
|
+
source_lineage_tag : str, default=None
|
|
2690
|
+
A tag that represents the lineage of the source for the object.
|
|
2585
2691
|
"""
|
|
2586
2692
|
import Microsoft.AnalysisServices.Tabular as TOM
|
|
2587
2693
|
|
|
@@ -2598,6 +2704,14 @@ class TOMWrapper:
|
|
|
2598
2704
|
t.Description = description
|
|
2599
2705
|
if data_category is not None:
|
|
2600
2706
|
t.DataCategory = data_category
|
|
2707
|
+
if lineage_tag is not None:
|
|
2708
|
+
t.LineageTag = lineage_tag
|
|
2709
|
+
else:
|
|
2710
|
+
t.LineageTag = generate_guid()
|
|
2711
|
+
if source_lineage_tag is not None:
|
|
2712
|
+
t.SourceLineageTag = source_lineage_tag
|
|
2713
|
+
else:
|
|
2714
|
+
t.SourceLineagetTag = generate_guid()
|
|
2601
2715
|
t.Hidden = hidden
|
|
2602
2716
|
t.Partitions.Add(par)
|
|
2603
2717
|
self.model.Tables.Add(t)
|
|
@@ -3304,7 +3418,7 @@ class TOMWrapper:
|
|
|
3304
3418
|
incremental_periods: int,
|
|
3305
3419
|
rolling_window_granularity: str,
|
|
3306
3420
|
rolling_window_periods: int,
|
|
3307
|
-
only_refresh_complete_days:
|
|
3421
|
+
only_refresh_complete_days: bool = False,
|
|
3308
3422
|
detect_data_changes_column: Optional[str] = None,
|
|
3309
3423
|
):
|
|
3310
3424
|
"""
|
|
@@ -3409,7 +3523,7 @@ class TOMWrapper:
|
|
|
3409
3523
|
incremental_periods: int,
|
|
3410
3524
|
rolling_window_granularity: str,
|
|
3411
3525
|
rolling_window_periods: int,
|
|
3412
|
-
only_refresh_complete_days:
|
|
3526
|
+
only_refresh_complete_days: bool = False,
|
|
3413
3527
|
detect_data_changes_column: Optional[str] = None,
|
|
3414
3528
|
):
|
|
3415
3529
|
"""
|
|
@@ -3578,7 +3692,7 @@ class TOMWrapper:
|
|
|
3578
3692
|
self,
|
|
3579
3693
|
table_name: str,
|
|
3580
3694
|
effective_date: Optional[datetime] = None,
|
|
3581
|
-
refresh:
|
|
3695
|
+
refresh: bool = True,
|
|
3582
3696
|
max_parallelism: Optional[int] = 0,
|
|
3583
3697
|
):
|
|
3584
3698
|
"""
|
|
@@ -3896,6 +4010,8 @@ class TOMWrapper:
|
|
|
3896
4010
|
data_category: Optional[str] = None,
|
|
3897
4011
|
key: Optional[bool] = None,
|
|
3898
4012
|
summarize_by: Optional[str] = None,
|
|
4013
|
+
is_nullable: Optional[bool] = None,
|
|
4014
|
+
is_available_in_mdx: Optional[bool] = None,
|
|
3899
4015
|
):
|
|
3900
4016
|
"""
|
|
3901
4017
|
Updates a column within a semantic model.
|
|
@@ -3936,12 +4052,16 @@ class TOMWrapper:
|
|
|
3936
4052
|
summarize_by : str, default=None
|
|
3937
4053
|
Sets the value for the Summarize By property of the column.
|
|
3938
4054
|
Defaults to None which keeps the existing setting.
|
|
4055
|
+
is_nullable : bool, default=None
|
|
4056
|
+
If False, the column cannot contain nulls. Even if True, it may still not allow nulls if it's a key column.
|
|
4057
|
+
is_available_in_mdx : bool, default=None
|
|
4058
|
+
A boolean value that indicates whether the column can be excluded from usage in MDX query tools. False if the column can be excluded from usage in MDX query tools; otherwise true.
|
|
3939
4059
|
"""
|
|
3940
4060
|
|
|
3941
4061
|
import Microsoft.AnalysisServices.Tabular as TOM
|
|
3942
4062
|
import System
|
|
3943
4063
|
|
|
3944
|
-
c = self.model.Tables[table_name].
|
|
4064
|
+
c = self.model.Tables[table_name].Columns[column_name]
|
|
3945
4065
|
if c.Type == TOM.ColumnType.Data:
|
|
3946
4066
|
if source_column is not None:
|
|
3947
4067
|
c.SourceColumn = source_column
|
|
@@ -3964,6 +4084,10 @@ class TOMWrapper:
|
|
|
3964
4084
|
c.DataCategory = data_category
|
|
3965
4085
|
if summarize_by is not None:
|
|
3966
4086
|
c.SummarizeBy = System.Enum.Parse(TOM.AggregateFunction, summarize_by)
|
|
4087
|
+
if is_nullable is not None:
|
|
4088
|
+
c.IsNullable = is_nullable
|
|
4089
|
+
if is_available_in_mdx is not None:
|
|
4090
|
+
c.IsAvailableInMDX = is_available_in_mdx
|
|
3967
4091
|
|
|
3968
4092
|
def update_role(
|
|
3969
4093
|
self,
|
|
@@ -4086,6 +4210,28 @@ class TOMWrapper:
|
|
|
4086
4210
|
|
|
4087
4211
|
self.model.Tables[table_name].Columns[column_name].SortByColumn = None
|
|
4088
4212
|
|
|
4213
|
+
def is_calculated_column(self, table_name: str, column_name: str):
|
|
4214
|
+
"""
|
|
4215
|
+
Identifies if a column is a calculated column.
|
|
4216
|
+
|
|
4217
|
+
Parameters
|
|
4218
|
+
----------
|
|
4219
|
+
table_name : str
|
|
4220
|
+
Name of the table in which the column resides.
|
|
4221
|
+
column_name : str
|
|
4222
|
+
Name of the column.
|
|
4223
|
+
|
|
4224
|
+
Returns
|
|
4225
|
+
-------
|
|
4226
|
+
bool
|
|
4227
|
+
A boolean value indicating whether the column is a calculated column.
|
|
4228
|
+
"""
|
|
4229
|
+
|
|
4230
|
+
import Microsoft.AnalysisServices.Tabular as TOM
|
|
4231
|
+
|
|
4232
|
+
c = self.model.Tables[table_name].Columns[column_name]
|
|
4233
|
+
return c.Type == TOM.ColumnType.Calculated
|
|
4234
|
+
|
|
4089
4235
|
def is_calculated_table(self, table_name: str):
|
|
4090
4236
|
"""
|
|
4091
4237
|
Identifies if a table is a calculated table.
|
|
@@ -4112,6 +4258,171 @@ class TOMWrapper:
|
|
|
4112
4258
|
isCalcTable = True
|
|
4113
4259
|
return isCalcTable
|
|
4114
4260
|
|
|
4261
|
+
def update_lineage_tags(self):
|
|
4262
|
+
"""
|
|
4263
|
+
Adds lineage and source lineage tags for relevant semantic model objects if they do not exist. Also updates schema name for Direct Lake (entity) partitions.
|
|
4264
|
+
"""
|
|
4265
|
+
|
|
4266
|
+
import Microsoft.AnalysisServices.Tabular as TOM
|
|
4267
|
+
|
|
4268
|
+
for t in self.model.Tables:
|
|
4269
|
+
if len(t.LineageTag) == 0:
|
|
4270
|
+
t.LineageTag = generate_guid()
|
|
4271
|
+
if len(t.SourceLineageTag) == 0:
|
|
4272
|
+
if next(p.Mode for p in t.Partitions) == TOM.ModeType.DirectLake:
|
|
4273
|
+
partition_name = next(p.Name for p in t.Partitions)
|
|
4274
|
+
entity_name = t.Partitions[partition_name].Source.EntityName
|
|
4275
|
+
schema_name = t.Partitions[partition_name].Source.SchemaName
|
|
4276
|
+
|
|
4277
|
+
# Update schema name and source lineage tag for DL (entity) partitions
|
|
4278
|
+
if len(schema_name) == 0:
|
|
4279
|
+
schema_name = icons.default_schema
|
|
4280
|
+
t.Partitions[partition_name].Source.SchemaName = (
|
|
4281
|
+
icons.default_schema
|
|
4282
|
+
)
|
|
4283
|
+
t.SourceLineageTag = f"[{schema_name}].[{entity_name}]"
|
|
4284
|
+
else:
|
|
4285
|
+
t.SourceLineageTag = generate_guid()
|
|
4286
|
+
for c in self.all_columns():
|
|
4287
|
+
if len(c.LineageTag) == 0:
|
|
4288
|
+
c.LineageTag = generate_guid()
|
|
4289
|
+
if len(c.SourceLineageTag) == 0:
|
|
4290
|
+
c.SourceLineageTag = generate_guid()
|
|
4291
|
+
for m in self.all_measures():
|
|
4292
|
+
if len(m.LineageTag) == 0:
|
|
4293
|
+
m.LineageTag = generate_guid()
|
|
4294
|
+
if len(m.SourceLineageTag) == 0:
|
|
4295
|
+
m.SourceLineageTag = generate_guid()
|
|
4296
|
+
for h in self.all_hierarchies():
|
|
4297
|
+
if len(h.LineageTag) == 0:
|
|
4298
|
+
h.LineageTag = generate_guid()
|
|
4299
|
+
if len(h.SourceLineageTag) == 0:
|
|
4300
|
+
h.SourceLineageTag = generate_guid()
|
|
4301
|
+
for lvl in self.all_levels():
|
|
4302
|
+
if len(lvl.LineageTag) == 0:
|
|
4303
|
+
lvl.LineageTag = generate_guid()
|
|
4304
|
+
if len(lvl.SourceLineageTag) == 0:
|
|
4305
|
+
lvl.SourceLineageTag = generate_guid()
|
|
4306
|
+
for e in self.model.Expressions():
|
|
4307
|
+
if len(e.LineageTag) == 0:
|
|
4308
|
+
e.LineageTag = generate_guid()
|
|
4309
|
+
if len(e.SourceLineageTag) == 0:
|
|
4310
|
+
e.SourceLineageTag = generate_guid()
|
|
4311
|
+
|
|
4312
|
+
def generate_measure_descriptions(
|
|
4313
|
+
self,
|
|
4314
|
+
measure_name: Optional[str | List[str]] = None,
|
|
4315
|
+
max_batch_size: Optional[int] = 5,
|
|
4316
|
+
):
|
|
4317
|
+
"""
|
|
4318
|
+
Auto-generates descriptions for measures using an LLM.
|
|
4319
|
+
|
|
4320
|
+
Parameters
|
|
4321
|
+
----------
|
|
4322
|
+
measure_name : str | List[str], default=None
|
|
4323
|
+
The measure name (or a list of measure names).
|
|
4324
|
+
Defaults to None which generates descriptions for all measures in the semantic model.
|
|
4325
|
+
max_batch_size : int, default=5
|
|
4326
|
+
Sets the max batch size for each API call.
|
|
4327
|
+
"""
|
|
4328
|
+
|
|
4329
|
+
# import concurrent.futures
|
|
4330
|
+
|
|
4331
|
+
if isinstance(measure_name, str):
|
|
4332
|
+
measure_name = [measure_name]
|
|
4333
|
+
|
|
4334
|
+
workspace_id = fabric.resolve_workspace_id(self._workspace)
|
|
4335
|
+
client = fabric.FabricRestClient()
|
|
4336
|
+
|
|
4337
|
+
if len(measure_name) > max_batch_size:
|
|
4338
|
+
measure_lists = [
|
|
4339
|
+
measure_name[i : i + max_batch_size]
|
|
4340
|
+
for i in range(0, len(measure_name), max_batch_size)
|
|
4341
|
+
]
|
|
4342
|
+
else:
|
|
4343
|
+
measure_lists = [measure_name]
|
|
4344
|
+
|
|
4345
|
+
# Each API call can have a max of 5 measures
|
|
4346
|
+
for measure_list in measure_lists:
|
|
4347
|
+
payload = {
|
|
4348
|
+
"scenarioDefinition": {
|
|
4349
|
+
"generateModelItemDescriptions": {
|
|
4350
|
+
"modelItems": [],
|
|
4351
|
+
},
|
|
4352
|
+
},
|
|
4353
|
+
"workspaceId": workspace_id,
|
|
4354
|
+
"artifactInfo": {"artifactType": "SemanticModel"},
|
|
4355
|
+
}
|
|
4356
|
+
for m_name in measure_list:
|
|
4357
|
+
expr, t_name = next(
|
|
4358
|
+
(ms.Expression, ms.Parent.Name)
|
|
4359
|
+
for ms in self.all_measures()
|
|
4360
|
+
if ms.Name == m_name
|
|
4361
|
+
)
|
|
4362
|
+
if t_name is None:
|
|
4363
|
+
raise ValueError(
|
|
4364
|
+
f"{icons.red_dot} The '{m_name}' measure does not exist in the '{self._dataset}' semantic model within the '{self._workspace}' workspace."
|
|
4365
|
+
)
|
|
4366
|
+
|
|
4367
|
+
new_item = {
|
|
4368
|
+
"urn": m_name,
|
|
4369
|
+
"type": 1,
|
|
4370
|
+
"name": m_name,
|
|
4371
|
+
"expression": expr,
|
|
4372
|
+
}
|
|
4373
|
+
payload["scenarioDefinition"]["generateModelItemDescriptions"][
|
|
4374
|
+
"modelItems"
|
|
4375
|
+
].append(new_item)
|
|
4376
|
+
|
|
4377
|
+
response = client.post("/explore/v202304/nl2nl/completions", json=payload)
|
|
4378
|
+
if response.status_code != 200:
|
|
4379
|
+
raise FabricHTTPException(response)
|
|
4380
|
+
|
|
4381
|
+
for item in response.json().get("modelItems", []):
|
|
4382
|
+
ms_name = item["urn"]
|
|
4383
|
+
if ms_name.startswith("urn: "):
|
|
4384
|
+
ms_name = ms_name[5:]
|
|
4385
|
+
desc = item.get("description")
|
|
4386
|
+
table_name = next(
|
|
4387
|
+
m.Parent.Name for m in self.all_measures() if m.Name == ms_name
|
|
4388
|
+
)
|
|
4389
|
+
self.model.Tables[table_name].Measures[ms_name].Description = desc
|
|
4390
|
+
|
|
4391
|
+
# def process_measure(m):
|
|
4392
|
+
# table_name = m.Parent.Name
|
|
4393
|
+
# m_name = m.Name
|
|
4394
|
+
# m_name_fixed = "1"
|
|
4395
|
+
# expr = m.Expression
|
|
4396
|
+
# if measure_name is None or m_name in measure_name:
|
|
4397
|
+
# payload = {
|
|
4398
|
+
# "scenarioDefinition": {
|
|
4399
|
+
# "generateModelItemDescriptions": {
|
|
4400
|
+
# "modelItems": [
|
|
4401
|
+
# {
|
|
4402
|
+
# "urn": f"modelobject://Table/{table_name}/Measure/{m_name_fixed}",
|
|
4403
|
+
# "type": 1,
|
|
4404
|
+
# "name": m_name,
|
|
4405
|
+
# "expression": expr,
|
|
4406
|
+
# }
|
|
4407
|
+
# ]
|
|
4408
|
+
# }
|
|
4409
|
+
# },
|
|
4410
|
+
# "workspaceId": workspace_id,
|
|
4411
|
+
# "artifactInfo": {"artifactType": "SemanticModel"},
|
|
4412
|
+
# }
|
|
4413
|
+
|
|
4414
|
+
# response = client.post(
|
|
4415
|
+
# "/explore/v202304/nl2nl/completions", json=payload
|
|
4416
|
+
# )
|
|
4417
|
+
# if response.status_code != 200:
|
|
4418
|
+
# raise FabricHTTPException(response)
|
|
4419
|
+
|
|
4420
|
+
# desc = response.json()["modelItems"][0]["description"]
|
|
4421
|
+
# m.Description = desc
|
|
4422
|
+
|
|
4423
|
+
# with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
4424
|
+
# executor.map(process_measure, self.all_measures())
|
|
4425
|
+
|
|
4115
4426
|
def close(self):
|
|
4116
4427
|
if not self._readonly and self.model is not None:
|
|
4117
4428
|
self.model.SaveChanges()
|
|
File without changes
|
|
File without changes
|