semantic-link-labs 0.4.1__py3-none-any.whl → 0.5.0__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 (53) hide show
  1. {semantic_link_labs-0.4.1.dist-info → semantic_link_labs-0.5.0.dist-info}/METADATA +1 -1
  2. semantic_link_labs-0.5.0.dist-info/RECORD +53 -0
  3. {semantic_link_labs-0.4.1.dist-info → semantic_link_labs-0.5.0.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +51 -27
  5. sempy_labs/_ai.py +32 -51
  6. sempy_labs/_clear_cache.py +2 -3
  7. sempy_labs/_connections.py +39 -38
  8. sempy_labs/_dax.py +5 -9
  9. sempy_labs/_generate_semantic_model.py +15 -21
  10. sempy_labs/_helper_functions.py +20 -25
  11. sempy_labs/_icons.py +6 -0
  12. sempy_labs/_list_functions.py +1172 -392
  13. sempy_labs/_model_auto_build.py +3 -5
  14. sempy_labs/_model_bpa.py +20 -24
  15. sempy_labs/_model_dependencies.py +7 -14
  16. sempy_labs/_one_lake_integration.py +14 -24
  17. sempy_labs/_query_scale_out.py +13 -31
  18. sempy_labs/_refresh_semantic_model.py +8 -18
  19. sempy_labs/_translations.py +5 -5
  20. sempy_labs/_vertipaq.py +11 -18
  21. sempy_labs/directlake/_directlake_schema_compare.py +11 -15
  22. sempy_labs/directlake/_directlake_schema_sync.py +35 -40
  23. sempy_labs/directlake/_fallback.py +3 -7
  24. sempy_labs/directlake/_get_directlake_lakehouse.py +3 -4
  25. sempy_labs/directlake/_get_shared_expression.py +5 -11
  26. sempy_labs/directlake/_guardrails.py +5 -7
  27. sempy_labs/directlake/_list_directlake_model_calc_tables.py +28 -26
  28. sempy_labs/directlake/_show_unsupported_directlake_objects.py +3 -4
  29. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +11 -16
  30. sempy_labs/directlake/_update_directlake_partition_entity.py +25 -15
  31. sempy_labs/directlake/_warm_cache.py +10 -15
  32. sempy_labs/lakehouse/__init__.py +0 -2
  33. sempy_labs/lakehouse/_get_lakehouse_columns.py +4 -3
  34. sempy_labs/lakehouse/_get_lakehouse_tables.py +12 -11
  35. sempy_labs/lakehouse/_lakehouse.py +6 -7
  36. sempy_labs/lakehouse/_shortcuts.py +10 -111
  37. sempy_labs/migration/__init__.py +4 -2
  38. sempy_labs/migration/_create_pqt_file.py +5 -14
  39. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +7 -7
  40. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +4 -4
  41. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +3 -8
  42. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +6 -6
  43. sempy_labs/migration/_migration_validation.py +5 -164
  44. sempy_labs/migration/_refresh_calc_tables.py +5 -5
  45. sempy_labs/report/__init__.py +2 -2
  46. sempy_labs/report/_generate_report.py +14 -19
  47. sempy_labs/report/_report_functions.py +41 -83
  48. sempy_labs/report/_report_rebind.py +43 -44
  49. sempy_labs/tom/__init__.py +6 -0
  50. sempy_labs/{_tom.py → tom/_model.py} +274 -337
  51. semantic_link_labs-0.4.1.dist-info/RECORD +0 -52
  52. {semantic_link_labs-0.4.1.dist-info → semantic_link_labs-0.5.0.dist-info}/LICENSE +0 -0
  53. {semantic_link_labs-0.4.1.dist-info → semantic_link_labs-0.5.0.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ from sempy_labs._list_functions import list_relationships
8
8
  from sempy_labs._refresh_semantic_model import refresh_semantic_model
9
9
  from sempy_labs.directlake._fallback import check_fallback_reason
10
10
  from contextlib import contextmanager
11
- from typing import List, Optional, Union, TYPE_CHECKING
11
+ from typing import List, Iterator, Optional, Union, TYPE_CHECKING
12
12
  from sempy._utils._log import log
13
13
  import sempy_labs._icons as icons
14
14
 
@@ -17,32 +17,28 @@ if TYPE_CHECKING:
17
17
  import Microsoft.AnalysisServices.Tabular as TOM
18
18
 
19
19
 
20
- checked = "\u2611"
21
- unchecked = "\u2610"
22
- start_bold = "\033[1m"
23
- end_bold = "\033[0m"
24
-
25
-
26
20
  class TOMWrapper:
27
21
  """
28
- Convenience wrapper around the TOM object model for a semantic model. Always use connect_semantic_model function to make sure the TOM object is initialized correctly.
22
+ 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.
23
+
24
+ `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.
29
25
  """
30
26
 
31
- dataset: str
32
- workspace: str
33
- readonly: bool
34
- tables_added: List[str]
27
+ _dataset: str
28
+ _workspace: str
29
+ _readonly: bool
30
+ _tables_added: List[str]
35
31
 
36
32
  def __init__(self, dataset, workspace, readonly):
37
- self.dataset = dataset
38
- self.workspace = workspace
39
- self.readonly = readonly
40
- self.tables_added = []
33
+ self._dataset = dataset
34
+ self._workspace = workspace
35
+ self._readonly = readonly
36
+ self._tables_added = []
41
37
 
42
- self.tom_server = fabric.create_tom_server(
38
+ self._tom_server = fabric.create_tom_server(
43
39
  readonly=readonly, workspace=workspace
44
40
  )
45
- self.model = self.tom_server.Databases.GetByName(dataset).Model
41
+ self.model = self._tom_server.Databases.GetByName(dataset).Model
46
42
 
47
43
  def all_columns(self):
48
44
  """
@@ -97,7 +93,7 @@ class TOMWrapper:
97
93
  import Microsoft.AnalysisServices.Tabular as TOM
98
94
 
99
95
  for t in self.model.Tables:
100
- if any(p.SourceType == TOM.ColumnType.Calculated for p in t.Partitions):
96
+ if any(p.SourceType == TOM.PartitionSourceType.Calculated for p in t.Partitions):
101
97
  yield t
102
98
 
103
99
  def all_calculation_groups(self):
@@ -181,10 +177,10 @@ class TOMWrapper:
181
177
  All levels within the semantic model.
182
178
  """
183
179
 
184
- for t in self.model.Tables:
185
- for h in t.Hierarchies:
186
- for l in h.Levels:
187
- yield l
180
+ for table in self.model.Tables:
181
+ for hierarchy in table.Hierarchies:
182
+ for level in hierarchy.Levels:
183
+ yield level
188
184
 
189
185
  def all_calculation_items(self):
190
186
  """
@@ -459,7 +455,7 @@ class TOMWrapper:
459
455
  Marks the column as the primary key of the table.
460
456
  summarize_by : str, default=None
461
457
  Sets the value for the Summarize By property of the column.
462
- Defaults to None resolves to 'Default'.
458
+ Defaults to None which resolves to 'Default'.
463
459
  """
464
460
  import Microsoft.AnalysisServices.Tabular as TOM
465
461
  import System
@@ -504,7 +500,7 @@ class TOMWrapper:
504
500
  description: Optional[str] = None,
505
501
  ):
506
502
  """
507
- Adds a calculation item to a calculation group within a semantic model.
503
+ Adds a `calculation item <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.calculationitem?view=analysisservices-dotnet>`_ to a `calculation group <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.calculationgroup?view=analysisservices-dotnet>`_ within a semantic model.
508
504
 
509
505
  Parameters
510
506
  ----------
@@ -642,7 +638,7 @@ class TOMWrapper:
642
638
  hierarchy_hidden: Optional[bool] = False,
643
639
  ):
644
640
  """
645
- Adds a hierarchy to a table within a semantic model.
641
+ Adds a `hierarchy <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.hierarchy?view=analysisservices-dotnet>`_ to a table within a semantic model.
646
642
 
647
643
  Parameters
648
644
  ----------
@@ -662,22 +658,16 @@ class TOMWrapper:
662
658
  import Microsoft.AnalysisServices.Tabular as TOM
663
659
 
664
660
  if isinstance(columns, str):
665
- print(
666
- f"The 'levels' parameter must be a list. For example: ['Continent', 'Country', 'City']"
667
- )
668
- return
661
+ raise ValueError(f"{icons.red_dot} The 'levels' parameter must be a list. For example: ['Continent', 'Country', 'City']")
662
+
669
663
  if len(columns) == 1:
670
- print(f"There must be at least 2 levels in order to create a hierarchy.")
671
- return
664
+ raise ValueError(f"{icons.red_dot} There must be at least 2 levels in order to create a hierarchy.")
672
665
 
673
666
  if levels is None:
674
667
  levels = columns
675
668
 
676
669
  if len(columns) != len(levels):
677
- print(
678
- f"If specifying level names, you must specify a level for each column."
679
- )
680
- return
670
+ raise ValueError(f"{icons.red_dot} If specifying level names, you must specify a level for each column.")
681
671
 
682
672
  obj = TOM.Hierarchy()
683
673
  obj.Name = hierarchy_name
@@ -707,7 +697,7 @@ class TOMWrapper:
707
697
  rely_on_referential_integrity: Optional[bool] = False,
708
698
  ):
709
699
  """
710
- Adds a relationship to a semantic model.
700
+ Adds a `relationship <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.singlecolumnrelationship?view=analysisservices-dotnet>`_ to a semantic model.
711
701
 
712
702
  Parameters
713
703
  ----------
@@ -779,7 +769,7 @@ class TOMWrapper:
779
769
  hidden: Optional[bool] = False,
780
770
  ):
781
771
  """
782
- Adds a calculation group to a semantic model.
772
+ Adds a `calculation group <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.calculationgroup?view=analysisservices-dotnet>`_ to a semantic model.
783
773
 
784
774
  Parameters
785
775
  ----------
@@ -832,7 +822,7 @@ class TOMWrapper:
832
822
  self, name: str, expression: str, description: Optional[str] = None
833
823
  ):
834
824
  """
835
- Adds an expression to a semantic model.
825
+ Adds an `expression <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.namedexpression?view=analysisservices-dotnet>`_ to a semantic model.
836
826
 
837
827
  Parameters
838
828
  ----------
@@ -856,7 +846,7 @@ class TOMWrapper:
856
846
 
857
847
  def add_translation(self, language: str):
858
848
  """
859
- Adds a translation language (culture) to a semantic model.
849
+ Adds a `translation language <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.culture?view=analysisservices-dotnet>`_ (culture) to a semantic model.
860
850
 
861
851
  Parameters
862
852
  ----------
@@ -875,7 +865,7 @@ class TOMWrapper:
875
865
 
876
866
  def add_perspective(self, perspective_name: str):
877
867
  """
878
- Adds a perspective to a semantic model.
868
+ Adds a `perspective <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.perspective?view=analysisservices-dotnet>`_ to a semantic model.
879
869
 
880
870
  Parameters
881
871
  ----------
@@ -910,18 +900,22 @@ class TOMWrapper:
910
900
  mode : str, default=None
911
901
  The query mode for the partition.
912
902
  Defaults to None which resolves to 'Import'.
903
+ `Valid mode values <https://learn.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.modetype?view=analysisservices-dotnet>`_
913
904
  description : str, default=None
914
905
  A description for the partition.
915
906
  """
916
907
  import Microsoft.AnalysisServices.Tabular as TOM
917
908
  import System
918
909
 
919
- mode = (
920
- mode.title()
921
- .replace("query", "Query")
922
- .replace(" ", "")
923
- .replace("lake", "Lake")
924
- )
910
+ if mode is None:
911
+ mode = "Default"
912
+ else:
913
+ mode = (
914
+ mode.title()
915
+ .replace("query", "Query")
916
+ .replace(" ", "")
917
+ .replace("lake", "Lake")
918
+ )
925
919
 
926
920
  mp = TOM.MPartitionSource()
927
921
  mp.Expression = expression
@@ -930,8 +924,6 @@ class TOMWrapper:
930
924
  p.Source = mp
931
925
  if description is not None:
932
926
  p.Description = description
933
- if mode is None:
934
- mode = "Default"
935
927
  p.Mode = System.Enum.Parse(TOM.ModeType, mode)
936
928
 
937
929
  self.model.Tables[table_name].Partitions.Add(p)
@@ -966,7 +958,7 @@ class TOMWrapper:
966
958
  if expression is None:
967
959
  ep.ExpressionSource = self.model.Expressions["DatabaseQuery"]
968
960
  else:
969
- ep.ExpressionSource = expression
961
+ ep.ExpressionSource = self.model.Expressions[expression]
970
962
  p = TOM.Partition()
971
963
  p.Name = table_name
972
964
  p.Source = ep
@@ -985,7 +977,7 @@ class TOMWrapper:
985
977
  base_column: Optional[str] = None,
986
978
  ):
987
979
  """
988
- Sets the 'alternate of' property on a column.
980
+ Sets the `alternate of <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.alternateof?view=analysisservices-dotnet>`_ property on a column.
989
981
 
990
982
  Parameters
991
983
  ----------
@@ -1005,9 +997,7 @@ class TOMWrapper:
1005
997
  import System
1006
998
 
1007
999
  if base_column is not None and base_table is None:
1008
- print(
1009
- f"ERROR: If you specify the base table you must also specify the base column"
1010
- )
1000
+ raise ValueError(f"{icons.red_dot} If you specify the base table you must also specify the base column")
1011
1001
 
1012
1002
  summarization_type = (
1013
1003
  summarization_type.replace(" ", "")
@@ -1017,10 +1007,7 @@ class TOMWrapper:
1017
1007
 
1018
1008
  summarizationTypes = ["Sum", "GroupBy", "Count", "Min", "Max"]
1019
1009
  if summarization_type not in summarizationTypes:
1020
- print(
1021
- f"The 'summarization_type' parameter must be one of the following valuse: {summarizationTypes}."
1022
- )
1023
- return
1010
+ raise ValueError(f"{icons.red_dot} The 'summarization_type' parameter must be one of the following valuse: {summarizationTypes}.")
1024
1011
 
1025
1012
  ao = TOM.AlternateOf()
1026
1013
  ao.Summarization = System.Enum.Parse(TOM.SummarizationType, summarization_type)
@@ -1039,7 +1026,7 @@ class TOMWrapper:
1039
1026
 
1040
1027
  def remove_alternate_of(self, table_name: str, column_name: str):
1041
1028
  """
1042
- Removes the 'alternate of' property on a column.
1029
+ Removes the `alternate of <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.alternateof?view=analysisservices-dotnet>`_ property on a column.
1043
1030
 
1044
1031
  Parameters
1045
1032
  ----------
@@ -1059,7 +1046,7 @@ class TOMWrapper:
1059
1046
  self, object
1060
1047
  ) -> "Microsoft.AnalysisServices.Tabular.Annotation":
1061
1048
  """
1062
- Shows all annotations for a given object within a semantic model.
1049
+ Shows all `annotations <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.annotation?view=analysisservices-dotnet>`_ for a given object within a semantic model.
1063
1050
 
1064
1051
  Parameters
1065
1052
  ----------
@@ -1081,7 +1068,7 @@ class TOMWrapper:
1081
1068
 
1082
1069
  def set_annotation(self, object, name: str, value: str):
1083
1070
  """
1084
- Sets an annotation on an object within the semantic model.
1071
+ Sets an `annotation <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.annotation?view=analysisservices-dotnet>`_ on an object within the semantic model.
1085
1072
 
1086
1073
  Parameters
1087
1074
  ----------
@@ -1105,7 +1092,7 @@ class TOMWrapper:
1105
1092
 
1106
1093
  def get_annotation_value(self, object, name: str):
1107
1094
  """
1108
- Obtains the annotation value for a given annotation on an object within the semantic model.
1095
+ Obtains the `annotation <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.annotation?view=analysisservices-dotnet>`_ value for a given annotation on an object within the semantic model.
1109
1096
 
1110
1097
  Parameters
1111
1098
  ----------
@@ -1124,7 +1111,7 @@ class TOMWrapper:
1124
1111
 
1125
1112
  def remove_annotation(self, object, name: str):
1126
1113
  """
1127
- Removes an annotation on an object within the semantic model.
1114
+ Removes an `annotation <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.annotation?view=analysisservices-dotnet>`_ on an object within the semantic model.
1128
1115
 
1129
1116
  Parameters
1130
1117
  ----------
@@ -1138,7 +1125,7 @@ class TOMWrapper:
1138
1125
 
1139
1126
  def clear_annotations(self, object):
1140
1127
  """
1141
- Removes all annotations on an object within the semantic model.
1128
+ Removes all `annotations <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.annotation?view=analysisservices-dotnet>`_ on an object within the semantic model.
1142
1129
 
1143
1130
  Parameters
1144
1131
  ----------
@@ -1152,7 +1139,7 @@ class TOMWrapper:
1152
1139
  self, object
1153
1140
  ) -> "Microsoft.AnalysisServices.Tabular.ExtendedProperty":
1154
1141
  """
1155
- Retrieves all extended properties on an object within the semantic model.
1142
+ Retrieves all `extended properties <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.extendedproperty?view=analysisservices-dotnet>`_ on an object within the semantic model.
1156
1143
 
1157
1144
  Parameters
1158
1145
  ----------
@@ -1172,7 +1159,7 @@ class TOMWrapper:
1172
1159
  self, object, extended_property_type: str, name: str, value: str
1173
1160
  ):
1174
1161
  """
1175
- Sets an extended property on an object within the semantic model.
1162
+ Sets an `extended property <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.extendedproperty?view=analysisservices-dotnet>`_ on an object within the semantic model.
1176
1163
 
1177
1164
  Parameters
1178
1165
  ----------
@@ -1205,7 +1192,7 @@ class TOMWrapper:
1205
1192
 
1206
1193
  def get_extended_property_value(self, object, name: str):
1207
1194
  """
1208
- Retrieves the value of an extended property for an object within the semantic model.
1195
+ Retrieves the value of an `extended property <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.extendedproperty?view=analysisservices-dotnet>`_ for an object within the semantic model.
1209
1196
 
1210
1197
  Parameters
1211
1198
  ----------
@@ -1224,7 +1211,7 @@ class TOMWrapper:
1224
1211
 
1225
1212
  def remove_extended_property(self, object, name: str):
1226
1213
  """
1227
- Removes an extended property on an object within the semantic model.
1214
+ Removes an `extended property <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.extendedproperty?view=analysisservices-dotnet>`_ on an object within the semantic model.
1228
1215
 
1229
1216
  Parameters
1230
1217
  ----------
@@ -1238,7 +1225,7 @@ class TOMWrapper:
1238
1225
 
1239
1226
  def clear_extended_properties(self, object):
1240
1227
  """
1241
- Removes all extended properties on an object within the semantic model.
1228
+ Removes all `extended properties <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.extendedproperty?view=analysisservices-dotnet>`_ on an object within the semantic model.
1242
1229
 
1243
1230
  Parameters
1244
1231
  ----------
@@ -1254,7 +1241,7 @@ class TOMWrapper:
1254
1241
  perspective_name: str,
1255
1242
  ):
1256
1243
  """
1257
- Indicates whether an object is contained within a given perspective.
1244
+ Indicates whether an object is contained within a given `perspective <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.perspective?view=analysisservices-dotnet>`_.
1258
1245
 
1259
1246
  Parameters
1260
1247
  ----------
@@ -1279,10 +1266,7 @@ class TOMWrapper:
1279
1266
  objectType = object.ObjectType
1280
1267
 
1281
1268
  if objectType not in validObjects:
1282
- print(
1283
- f"Only the following object types are valid for perspectives: {validObjects}."
1284
- )
1285
- return
1269
+ raise ValueError(f"{icons.red_dot} Only the following object types are valid for perspectives: {validObjects}.")
1286
1270
 
1287
1271
  object.Model.Perspectives[perspective_name]
1288
1272
 
@@ -1313,7 +1297,7 @@ class TOMWrapper:
1313
1297
  perspective_name: str,
1314
1298
  ):
1315
1299
  """
1316
- Adds an object to a perspective.
1300
+ Adds an object to a `perspective <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.perspective?view=analysisservices-dotnet>`_.
1317
1301
 
1318
1302
  Parameters
1319
1303
  ----------
@@ -1333,15 +1317,12 @@ class TOMWrapper:
1333
1317
  objectType = object.ObjectType
1334
1318
 
1335
1319
  if objectType not in validObjects:
1336
- print(
1337
- f"Only the following object types are valid for perspectives: {validObjects}."
1338
- )
1339
- return
1320
+ raise ValueError(f"{icons.red_dot} Only the following object types are valid for perspectives: {validObjects}.")
1321
+
1340
1322
  try:
1341
1323
  object.Model.Perspectives[perspective_name]
1342
1324
  except:
1343
- print(f"The '{perspective_name}' perspective does not exist.")
1344
- return
1325
+ raise ValueError(f"{icons.red_dot} The '{perspective_name}' perspective does not exist.")
1345
1326
 
1346
1327
  # try:
1347
1328
  if objectType == TOM.ObjectType.Table:
@@ -1375,7 +1356,7 @@ class TOMWrapper:
1375
1356
  perspective_name: str,
1376
1357
  ):
1377
1358
  """
1378
- Removes an object from a perspective.
1359
+ Removes an object from a `perspective <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.perspective?view=analysisservices-dotnet>`_.
1379
1360
 
1380
1361
  Parameters
1381
1362
  ----------
@@ -1395,15 +1376,12 @@ class TOMWrapper:
1395
1376
  objectType = object.ObjectType
1396
1377
 
1397
1378
  if objectType not in validObjects:
1398
- print(
1399
- f"Only the following object types are valid for perspectives: {validObjects}."
1400
- )
1401
- return
1379
+ raise ValueError(f"{icons.red_dot} Only the following object types are valid for perspectives: {validObjects}.")
1380
+
1402
1381
  try:
1403
1382
  object.Model.Perspectives[perspective_name]
1404
1383
  except:
1405
- print(f"The '{perspective_name}' perspective does not exist.")
1406
- return
1384
+ raise ValueError(f"{icons.red_dot} The '{perspective_name}' perspective does not exist.")
1407
1385
 
1408
1386
  # try:
1409
1387
  if objectType == TOM.ObjectType.Table:
@@ -1449,7 +1427,7 @@ class TOMWrapper:
1449
1427
  value: str,
1450
1428
  ):
1451
1429
  """
1452
- Sets a translation value for an object's property.
1430
+ Sets a `translation <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.culture?view=analysisservices-dotnet>`_ value for an object's property.
1453
1431
 
1454
1432
  Parameters
1455
1433
  ----------
@@ -1476,8 +1454,7 @@ class TOMWrapper:
1476
1454
  ] # , 'Level'
1477
1455
 
1478
1456
  if object.ObjectType not in validObjects:
1479
- print(f"Translations can only be set to {validObjects}.")
1480
- return
1457
+ raise ValueError(f"{icons.red_dot} Translations can only be set to {validObjects}.")
1481
1458
 
1482
1459
  mapping = {
1483
1460
  "Name": TOM.TranslatedProperty.Caption,
@@ -1486,14 +1463,13 @@ class TOMWrapper:
1486
1463
  }
1487
1464
 
1488
1465
  prop = mapping.get(property)
1466
+ if prop == None:
1467
+ raise ValueError(f"{icons.red_dot} Invalid property value. Please choose from the following: ['Name', 'Description', Display Folder].")
1489
1468
 
1490
1469
  try:
1491
1470
  object.Model.Cultures[language]
1492
1471
  except:
1493
- print(
1494
- f"The '{language}' translation language does not exist in the semantic model."
1495
- )
1496
- return
1472
+ raise ValueError(f"{icons.red_dot} The '{language}' translation language does not exist in the semantic model.")
1497
1473
 
1498
1474
  object.Model.Cultures[language].ObjectTranslations.SetTranslation(
1499
1475
  object, prop, value
@@ -1505,7 +1481,7 @@ class TOMWrapper:
1505
1481
  language: str,
1506
1482
  ):
1507
1483
  """
1508
- Removes an object's translation value.
1484
+ Removes an object's `translation <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.culture?view=analysisservices-dotnet>`_ value.
1509
1485
 
1510
1486
  Parameters
1511
1487
  ----------
@@ -1579,7 +1555,7 @@ class TOMWrapper:
1579
1555
 
1580
1556
  def used_in_relationships(self, object: Union["TOM.Table", "TOM.Column"]):
1581
1557
  """
1582
- Shows all relationships in which a table/column is used.
1558
+ Shows all `relationships <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.singlecolumnrelationship?view=analysisservices-dotnet>`_ in which a table/column is used.
1583
1559
 
1584
1560
  Parameters
1585
1561
  ----------
@@ -1612,7 +1588,7 @@ class TOMWrapper:
1612
1588
 
1613
1589
  def used_in_levels(self, column: "TOM.Column"):
1614
1590
  """
1615
- Shows all levels in which a column is used.
1591
+ Shows all `levels <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.level?view=analysisservices-dotnet>`_ in which a column is used.
1616
1592
 
1617
1593
  Parameters
1618
1594
  ----------
@@ -1629,16 +1605,16 @@ class TOMWrapper:
1629
1605
  objType = column.ObjectType
1630
1606
 
1631
1607
  if objType == TOM.ObjectType.Column:
1632
- for l in self.all_levels():
1608
+ for level in self.all_levels():
1633
1609
  if (
1634
- l.Parent.Table.Name == column.Parent.Name
1635
- and l.Column.Name == column.Name
1610
+ level.Parent.Table.Name == column.Parent.Name
1611
+ and level.Column.Name == column.Name
1636
1612
  ):
1637
- yield l
1613
+ yield level
1638
1614
 
1639
1615
  def used_in_hierarchies(self, column: "TOM.Column"):
1640
1616
  """
1641
- Shows all hierarchies in which a column is used.
1617
+ Shows all `hierarchies <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.hierarchy?view=analysisservices-dotnet>`_ in which a column is used.
1642
1618
 
1643
1619
  Parameters
1644
1620
  ----------
@@ -1691,7 +1667,7 @@ class TOMWrapper:
1691
1667
  dependencies: pd.DataFrame,
1692
1668
  ):
1693
1669
  """
1694
- Identifies the filter expressions which reference a given object.
1670
+ Identifies the row level security `filter expressions <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.tablepermission.filterexpression?view=analysisservices-dotnet#microsoft-analysisservices-tabular-tablepermission-filterexpression>`_ which reference a given object.
1695
1671
 
1696
1672
  Parameters
1697
1673
  ----------
@@ -1855,7 +1831,7 @@ class TOMWrapper:
1855
1831
 
1856
1832
  def hybrid_tables(self):
1857
1833
  """
1858
- Outputs the hybrid tables within a semantic model.
1834
+ Outputs the `hybrid tables <https://learn.microsoft.com/power-bi/connect-data/service-dataset-modes-understand#hybrid-tables>`_ within a semantic model.
1859
1835
 
1860
1836
  Parameters
1861
1837
  ----------
@@ -1874,7 +1850,7 @@ class TOMWrapper:
1874
1850
 
1875
1851
  def date_tables(self):
1876
1852
  """
1877
- Outputs the tables which are marked as date tables within a semantic model.
1853
+ Outputs the tables which are marked as `date tables <https://learn.microsoft.com/power-bi/transform-model/desktop-date-tables>`_ within a semantic model.
1878
1854
 
1879
1855
  Parameters
1880
1856
  ----------
@@ -1895,7 +1871,7 @@ class TOMWrapper:
1895
1871
 
1896
1872
  def is_hybrid_table(self, table_name: str):
1897
1873
  """
1898
- Identifies if a table is a hybrid table.
1874
+ Identifies if a table is a `hybrid table <https://learn.microsoft.com/power-bi/connect-data/service-dataset-modes-understand#hybrid-tables>`_.
1899
1875
 
1900
1876
  Parameters
1901
1877
  ----------
@@ -1925,7 +1901,7 @@ class TOMWrapper:
1925
1901
 
1926
1902
  def is_date_table(self, table_name: str):
1927
1903
  """
1928
- Identifies if a table is marked as a date table.
1904
+ Identifies if a table is marked as a `date tables <https://learn.microsoft.com/power-bi/transform-model/desktop-date-tables>`_.
1929
1905
 
1930
1906
  Parameters
1931
1907
  ----------
@@ -1939,18 +1915,11 @@ class TOMWrapper:
1939
1915
  """
1940
1916
  import Microsoft.AnalysisServices.Tabular as TOM
1941
1917
 
1942
- isDateTable = False
1943
- t = self.model.Tables[table_name]
1944
-
1945
- if t.DataCategory == "Time":
1946
- if any(c.IsKey and c.DataType == TOM.DataType.DateTime for c in t.Columns):
1947
- isDateTable = True
1948
-
1949
- return isDateTable
1918
+ return any(c.IsKey and c.DataType == TOM.DataType.DateTime for c in self.all_columns() if c.Parent.Name == table_name and c.Parent.DataCategory == 'Time')
1950
1919
 
1951
1920
  def mark_as_date_table(self, table_name: str, column_name: str):
1952
1921
  """
1953
- Marks a table as a date table.
1922
+ Marks a table as a `date table <https://learn.microsoft.com/power-bi/transform-model/desktop-date-tables>`_.
1954
1923
 
1955
1924
  Parameters
1956
1925
  ----------
@@ -1964,11 +1933,8 @@ class TOMWrapper:
1964
1933
  t = self.model.Tables[table_name]
1965
1934
  c = t.Columns[column_name]
1966
1935
  if c.DataType != TOM.DataType.DateTime:
1967
- print(
1968
- f"{icons.red_dot} The column specified in the 'column_name' parameter in this function must be of DateTime data type."
1969
- )
1970
- return
1971
-
1936
+ raise ValueError(f"{icons.red_dot} The column specified in the 'column_name' parameter in this function must be of DateTime data type.")
1937
+
1972
1938
  daxQuery = f"""
1973
1939
  define measure '{table_name}'[test] =
1974
1940
  var mn = MIN('{table_name}'[{column_name}])
@@ -1983,14 +1949,11 @@ class TOMWrapper:
1983
1949
  )
1984
1950
  """
1985
1951
  df = fabric.evaluate_dax(
1986
- dataset=self.dataset, workspace=self.workspace, dax_string=daxQuery
1952
+ dataset=self._dataset, workspace=self._workspace, dax_string=daxQuery
1987
1953
  )
1988
1954
  value = df["1"].iloc[0]
1989
1955
  if value != "1":
1990
- print(
1991
- f"{icons.red_dot} The '{column_name}' within the '{table_name}' table does not contain contiguous date values."
1992
- )
1993
- return
1956
+ raise ValueError(f"{icons.red_dot} The '{column_name}' within the '{table_name}' table does not contain contiguous date values.")
1994
1957
 
1995
1958
  # Mark as a date table
1996
1959
  t.DataCategory = "Time"
@@ -2001,7 +1964,7 @@ class TOMWrapper:
2001
1964
 
2002
1965
  def has_aggs(self):
2003
1966
  """
2004
- Identifies if a semantic model has any aggregations.
1967
+ Identifies if a semantic model has any `aggregations <https://learn.microsoft.com/power-bi/transform-model/aggregations-advanced>`_.
2005
1968
 
2006
1969
  Parameters
2007
1970
  ----------
@@ -2012,17 +1975,11 @@ class TOMWrapper:
2012
1975
  Indicates if the semantic model has any aggregations.
2013
1976
  """
2014
1977
 
2015
- hasAggs = False
2016
-
2017
- for c in self.all_columns():
2018
- if c.AlterateOf is not None:
2019
- hasAggs = True
2020
-
2021
- return hasAggs
1978
+ return any(c.AlternateOf is not None for c in self.all_columns())
2022
1979
 
2023
1980
  def is_agg_table(self, table_name: str):
2024
1981
  """
2025
- Identifies if a table has aggregations.
1982
+ Identifies if a table has `aggregations <https://learn.microsoft.com/power-bi/transform-model/aggregations-advanced>`_.
2026
1983
 
2027
1984
  Parameters
2028
1985
  ----------
@@ -2041,7 +1998,7 @@ class TOMWrapper:
2041
1998
 
2042
1999
  def has_hybrid_table(self):
2043
2000
  """
2044
- Identifies if a semantic model has a hybrid table.
2001
+ Identifies if a semantic model has a `hybrid table <https://learn.microsoft.com/power-bi/connect-data/service-dataset-modes-understand#hybrid-tables>`_.
2045
2002
 
2046
2003
  Parameters
2047
2004
  ----------
@@ -2050,19 +2007,13 @@ class TOMWrapper:
2050
2007
  -------
2051
2008
  bool
2052
2009
  Indicates if the semantic model has a hybrid table.
2053
- """
2010
+ """
2054
2011
 
2055
- hasHybridTable = False
2056
-
2057
- for t in self.model.Tables:
2058
- if self.is_hybrid_table(table_name=t.Name):
2059
- hasHybridTable = True
2060
-
2061
- return hasHybridTable
2012
+ return any(self.is_hybrid_table(table_name=t.Name) for t in self.model.Tables)
2062
2013
 
2063
2014
  def has_date_table(self):
2064
2015
  """
2065
- Identifies if a semantic model has a table marked as a date table.
2016
+ Identifies if a semantic model has a table marked as a `date table <https://learn.microsoft.com/power-bi/transform-model/desktop-date-tables>`_.
2066
2017
 
2067
2018
  Parameters
2068
2019
  ----------
@@ -2073,17 +2024,11 @@ class TOMWrapper:
2073
2024
  Indicates if the semantic model has a table marked as a date table.
2074
2025
  """
2075
2026
 
2076
- hasDateTable = False
2077
-
2078
- for t in self.model.Tables:
2079
- if self.is_date_table(table_name=t.Name):
2080
- hasDateTable = True
2081
-
2082
- return hasDateTable
2027
+ return any(self.is_date_table(table_name=t.Name) for t in self.model.Tables)
2083
2028
 
2084
2029
  def is_direct_lake(self):
2085
2030
  """
2086
- Identifies if a semantic model is in Direct Lake mode.
2031
+ Identifies if a semantic model is in `Direct Lake <https://learn.microsoft.com/fabric/get-started/direct-lake-overview>`_ mode.
2087
2032
 
2088
2033
  Parameters
2089
2034
  ----------
@@ -2093,6 +2038,7 @@ class TOMWrapper:
2093
2038
  bool
2094
2039
  Indicates if the semantic model is in Direct Lake mode.
2095
2040
  """
2041
+ import Microsoft.AnalysisServices.Tabular as TOM
2096
2042
 
2097
2043
  return any(
2098
2044
  p.Mode == TOM.ModeType.DirectLake
@@ -2102,7 +2048,7 @@ class TOMWrapper:
2102
2048
 
2103
2049
  def is_field_parameter(self, table_name: str):
2104
2050
  """
2105
- Identifies if a table is a field parameter.
2051
+ Identifies if a table is a `field parameter <https://learn.microsoft.com/power-bi/create-reports/power-bi-field-parameters>`_.
2106
2052
 
2107
2053
  Parameters
2108
2054
  ----------
@@ -2134,7 +2080,7 @@ class TOMWrapper:
2134
2080
 
2135
2081
  def is_auto_date_table(self, table_name: str):
2136
2082
  """
2137
- Identifies if a table is an auto-date table.
2083
+ Identifies if a table is an `auto date/time table <https://learn.microsoft.com/power-bi/transform-model/desktop-auto-date-time>`_.
2138
2084
 
2139
2085
  Parameters
2140
2086
  ----------
@@ -2174,7 +2120,7 @@ class TOMWrapper:
2174
2120
  status_graphic: Optional[str] = None,
2175
2121
  ):
2176
2122
  """
2177
- Sets the properties to add/update a KPI for a measure.
2123
+ Sets the properties to add/update a `KPI <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.kpi?view=analysisservices-dotnet>`_ for a measure.
2178
2124
 
2179
2125
  Parameters
2180
2126
  ----------
@@ -2202,58 +2148,44 @@ class TOMWrapper:
2202
2148
  # https://github.com/m-kovalsky/Tabular/blob/master/KPI%20Graphics.md
2203
2149
 
2204
2150
  if measure_name == target:
2205
- print(
2206
- f"The 'target' parameter cannot be the same measure as the 'measure_name' parameter."
2207
- )
2208
- return
2151
+ raise ValueError(f"{icons.red_dot} The 'target' parameter cannot be the same measure as the 'measure_name' parameter.")
2209
2152
 
2210
2153
  if status_graphic is None:
2211
2154
  status_graphic = "Three Circles Colored"
2212
2155
 
2213
- statusType = ["Linear", "LinearReversed", "Centered", "CenteredReversed"]
2214
- status_type = status_type.title().replace(" ", "")
2215
-
2156
+ valid_status_types = ["Linear", "LinearReversed", "Centered", "CenteredReversed"]
2157
+ status_type = status_type
2216
2158
  if status_type is None:
2217
2159
  status_type = "Linear"
2160
+ else:
2161
+ status_type = status_type.title().replace(" ", "")
2218
2162
 
2219
- if status_type not in statusType:
2220
- print(
2221
- f"'{status_type}' is an invalid status_type. Please choose from these options: {statusType}."
2222
- )
2223
- return
2163
+ if status_type not in valid_status_types:
2164
+ raise ValueError(f"{icons.red_dot} '{status_type}' is an invalid status_type. Please choose from these options: {valid_status_types}.")
2224
2165
 
2225
2166
  if status_type in ["Linear", "LinearReversed"]:
2226
2167
  if upper_bound is not None or lower_mid_bound is not None:
2227
- print(
2228
- f"The 'upper_mid_bound' and 'lower_mid_bound' parameters are not used in the 'Linear' and 'LinearReversed' status types. Make sure these parameters are set to None."
2229
- )
2230
- return
2168
+ raise ValueError(f"{icons.red_dot} The 'upper_mid_bound' and 'lower_mid_bound' parameters are not used in the 'Linear' and 'LinearReversed' status types. Make sure these parameters are set to None.")
2169
+
2231
2170
  elif upper_bound <= lower_bound:
2232
- print(f"The upper_bound must be greater than the lower_bound.")
2233
- return
2171
+ raise ValueError(f"{icons.red_dot} The upper_bound must be greater than the lower_bound.")
2234
2172
 
2235
2173
  if status_type in ["Centered", "CenteredReversed"]:
2236
2174
  if upper_mid_bound is None or lower_mid_bound is None:
2237
- print(
2238
- f"The 'upper_mid_bound' and 'lower_mid_bound' parameters are necessary in the 'Centered' and 'CenteredReversed' status types."
2239
- )
2240
- return
2175
+ raise ValueError(f"{icons.red_dot} The 'upper_mid_bound' and 'lower_mid_bound' parameters are necessary in the 'Centered' and 'CenteredReversed' status types.")
2241
2176
  elif upper_bound <= upper_mid_bound:
2242
- print(f"The upper_bound must be greater than the upper_mid_bound.")
2177
+ raise ValueError(f"{icons.red_dot} The upper_bound must be greater than the upper_mid_bound.")
2243
2178
  elif upper_mid_bound <= lower_mid_bound:
2244
- print(f"The upper_mid_bound must be greater than the lower_mid_bound.")
2179
+ raise ValueError(f"{icons.red_dot} The upper_mid_bound must be greater than the lower_mid_bound.")
2245
2180
  elif lower_mid_bound <= lower_bound:
2246
- print(f"The lower_mid_bound must be greater than the lower_bound.")
2181
+ raise ValueError(f"{icons.red_dot} The lower_mid_bound must be greater than the lower_bound.")
2247
2182
 
2248
2183
  try:
2249
2184
  table_name = next(
2250
2185
  m.Parent.Name for m in self.all_measures() if m.Name == measure_name
2251
2186
  )
2252
2187
  except:
2253
- print(
2254
- f"The '{measure_name}' measure does not exist in the '{self.dataset}' semantic model within the '{self.workspace}'."
2255
- )
2256
- return
2188
+ raise ValueError(f"{icons.red_dot} The '{measure_name}' measure does not exist in the '{self._dataset}' semantic model within the '{self._workspace}'.")
2257
2189
 
2258
2190
  graphics = [
2259
2191
  "Cylinder",
@@ -2276,10 +2208,7 @@ class TOMWrapper:
2276
2208
  ]
2277
2209
 
2278
2210
  if status_graphic not in graphics:
2279
- print(
2280
- f"The '{status_graphic}' status graphic is not valid. Please choose from these options: {graphics}."
2281
- )
2282
- return
2211
+ raise ValueError(f"{icons.red_dot} The '{status_graphic}' status graphic is not valid. Please choose from these options: {graphics}.")
2283
2212
 
2284
2213
  measure_target = True
2285
2214
 
@@ -2295,10 +2224,8 @@ class TOMWrapper:
2295
2224
  if m.Name == target
2296
2225
  )
2297
2226
  except:
2298
- print(
2299
- f"The '{target}' measure does not exist in the '{self.dataset}' semantic model within the '{self.workspace}'."
2300
- )
2301
-
2227
+ raise ValueError(f"{icons.red_dot} The '{target}' measure does not exist in the '{self._dataset}' semantic model within the '{self._workspace}'.")
2228
+
2302
2229
  if measure_target:
2303
2230
  expr = f"var x = [{measure_name}]/[{target}]\nreturn"
2304
2231
  else:
@@ -2328,7 +2255,7 @@ class TOMWrapper:
2328
2255
 
2329
2256
  def set_aggregations(self, table_name: str, agg_table_name: str):
2330
2257
  """
2331
- Sets the aggregations (alternate of) for all the columns in an aggregation table based on a base table.
2258
+ Sets the `aggregations <https://learn.microsoft.com/power-bi/transform-model/aggregations-advanced>`_ (alternate of) for all the columns in an aggregation table based on a base table.
2332
2259
 
2333
2260
  Parameters
2334
2261
  ----------
@@ -2367,7 +2294,7 @@ class TOMWrapper:
2367
2294
  self, table_name: str, column_name: str, value: Optional[bool] = False
2368
2295
  ):
2369
2296
  """
2370
- Sets the IsAvailableInMdx property on a column.
2297
+ 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.
2371
2298
 
2372
2299
  Parameters
2373
2300
  ----------
@@ -2385,7 +2312,7 @@ class TOMWrapper:
2385
2312
  self, table_name: str, column_name: str, value: Optional[str] = None
2386
2313
  ):
2387
2314
  """
2388
- Sets the SummarizeBy property on a column.
2315
+ Sets the `SummarizeBy <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.column.summarizeby?view=analysisservices-dotnet#microsoft-analysisservices-tabular-column-summarizeby>`_ property on a column.
2389
2316
 
2390
2317
  Parameters
2391
2318
  ----------
@@ -2421,10 +2348,7 @@ class TOMWrapper:
2421
2348
  )
2422
2349
 
2423
2350
  if value not in values:
2424
- print(
2425
- f"'{value}' is not a valid value for the SummarizeBy property. These are the valid values: {values}."
2426
- )
2427
- return
2351
+ raise ValueError(f"{icons.red_dot} '{value}' is not a valid value for the SummarizeBy property. These are the valid values: {values}.")
2428
2352
 
2429
2353
  self.model.Tables[table_name].Columns[column_name].SummarizeBy = (
2430
2354
  System.Enum.Parse(TOM.AggregateFunction, value)
@@ -2432,7 +2356,7 @@ class TOMWrapper:
2432
2356
 
2433
2357
  def set_direct_lake_behavior(self, direct_lake_behavior: str):
2434
2358
  """
2435
- Sets the Direct Lake Behavior property for a semantic model.
2359
+ Sets the `Direct Lake Behavior <https://learn.microsoft.com/fabric/get-started/direct-lake-overview#fallback-behavior>`_ property for a semantic model.
2436
2360
 
2437
2361
  Parameters
2438
2362
  ----------
@@ -2453,10 +2377,7 @@ class TOMWrapper:
2453
2377
  dlValues = ["Automatic", "DirectLakeOnly", "DirectQueryOnly"]
2454
2378
 
2455
2379
  if direct_lake_behavior not in dlValues:
2456
- print(
2457
- f"The 'direct_lake_behavior' parameter must be one of these values: {dlValues}."
2458
- )
2459
- return
2380
+ raise ValueError(f"{icons.red_dot} The 'direct_lake_behavior' parameter must be one of these values: {dlValues}.")
2460
2381
 
2461
2382
  self.model.DirectLakeBehavior = System.Enum.Parse(
2462
2383
  TOM.DirectLakeBehavior, direct_lake_behavior
@@ -2539,7 +2460,7 @@ class TOMWrapper:
2539
2460
 
2540
2461
  def add_field_parameter(self, table_name: str, objects: List[str]):
2541
2462
  """
2542
- Adds a table to the semantic model.
2463
+ Adds a `field parameter <https://learn.microsoft.com/power-bi/create-reports/power-bi-field-parameters>`_ to the semantic model.
2543
2464
 
2544
2465
  Parameters
2545
2466
  ----------
@@ -2551,14 +2472,13 @@ class TOMWrapper:
2551
2472
  Measures may be formatted as '[Measure Name]' or 'Measure Name'.
2552
2473
  """
2553
2474
 
2475
+ import Microsoft.AnalysisServices.Tabular as TOM
2476
+
2554
2477
  if isinstance(objects, str):
2555
- print(f"The 'objects' parameter must be a list of columns/measures.")
2556
- return
2478
+ raise ValueError(f"{icons.red_dot} The 'objects' parameter must be a list of columns/measures.")
2479
+
2557
2480
  if len(objects) == 1:
2558
- print(
2559
- f"There must be more than one object (column/measure) within the objects parameter."
2560
- )
2561
- return
2481
+ raise ValueError(f"{icons.red_dot} There must be more than one object (column/measure) within the objects parameter.")
2562
2482
 
2563
2483
  expr = ""
2564
2484
  i = 0
@@ -2594,10 +2514,7 @@ class TOMWrapper:
2594
2514
  )
2595
2515
  success = True
2596
2516
  if not success:
2597
- print(
2598
- f"The '{obj}' object was not found in the '{self.dataset}' semantic model."
2599
- )
2600
- return
2517
+ raise ValueError(f"{icons.red_dot} The '{obj}' object was not found in the '{self._dataset}' semantic model.")
2601
2518
  else:
2602
2519
  i += 1
2603
2520
 
@@ -2631,7 +2548,6 @@ class TOMWrapper:
2631
2548
  )
2632
2549
 
2633
2550
  self.set_extended_property(
2634
- self=self,
2635
2551
  object=self.model.Tables[table_name].Columns[col2],
2636
2552
  extended_property_type="Json",
2637
2553
  name="ParameterMetadata",
@@ -2649,11 +2565,11 @@ class TOMWrapper:
2649
2565
  ].Columns[col3]
2650
2566
  self.model.Tables[table_name].Columns[table_name].RelatedColumnDetails = rcd
2651
2567
 
2652
- self.tables_added.append(table_name)
2568
+ self._tables_added.append(table_name)
2653
2569
 
2654
2570
  def remove_vertipaq_annotations(self):
2655
2571
  """
2656
- Removes the annotations set using the [set_vertipaq_annotations] function.
2572
+ Removes the annotations set using the set_vertipaq_annotations function.
2657
2573
  """
2658
2574
 
2659
2575
  for t in self.model.Tables:
@@ -2683,10 +2599,10 @@ class TOMWrapper:
2683
2599
  """
2684
2600
 
2685
2601
  dfT = fabric.list_tables(
2686
- dataset=self.dataset, workspace=self.workspace, extended=True
2602
+ dataset=self._dataset, workspace=self._workspace, extended=True
2687
2603
  )
2688
2604
  dfC = fabric.list_columns(
2689
- dataset=self.dataset, workspace=self.workspace, extended=True
2605
+ dataset=self._dataset, workspace=self._workspace, extended=True
2690
2606
  )
2691
2607
  # intList = ['Total Size']#, 'Data Size', 'Dictionary Size', 'Hierarchy Size']
2692
2608
  dfCSum = dfC.groupby(["Table Name"])["Total Size"].sum().reset_index()
@@ -2698,16 +2614,16 @@ class TOMWrapper:
2698
2614
  how="inner",
2699
2615
  )
2700
2616
  dfP = fabric.list_partitions(
2701
- dataset=self.dataset, workspace=self.workspace, extended=True
2617
+ dataset=self._dataset, workspace=self._workspace, extended=True
2702
2618
  )
2703
2619
  dfP["Records per Segment"] = round(
2704
2620
  dfP["Record Count"] / dfP["Segment Count"], 2
2705
2621
  )
2706
2622
  dfH = fabric.list_hierarchies(
2707
- dataset=self.dataset, workspace=self.workspace, extended=True
2623
+ dataset=self._dataset, workspace=self._workspace, extended=True
2708
2624
  )
2709
2625
  dfR = list_relationships(
2710
- dataset=self.dataset, workspace=self.workspace, extended=True
2626
+ dataset=self._dataset, workspace=self._workspace, extended=True
2711
2627
  )
2712
2628
 
2713
2629
  for t in self.model.Tables:
@@ -3100,7 +3016,7 @@ class TOMWrapper:
3100
3016
  import Microsoft.AnalysisServices.Tabular as TOM
3101
3017
 
3102
3018
  def create_pattern(a, b):
3103
- return r"(?<!" + a + "\[)(?<!" + a + "'\[)" + b
3019
+ return r"(?<!" + re.escape(a) + r"\[)(?<!" + re.escape(a) + r"'\[)" + re.escape(b)
3104
3020
 
3105
3021
  for obj in self.depends_on(object=object, dependencies=dependencies):
3106
3022
  if obj.ObjectType == TOM.ObjectType.Column:
@@ -3128,7 +3044,7 @@ class TOMWrapper:
3128
3044
  usingView = False
3129
3045
 
3130
3046
  if self.is_direct_lake():
3131
- df = check_fallback_reason(dataset=self.dataset, workspace=self.workspace)
3047
+ df = check_fallback_reason(dataset=self._dataset, workspace=self._workspace)
3132
3048
  df_filt = df[df["FallbackReasonID"] == 2]
3133
3049
 
3134
3050
  if len(df_filt) > 0:
@@ -3138,7 +3054,7 @@ class TOMWrapper:
3138
3054
 
3139
3055
  def has_incremental_refresh_policy(self, table_name: str):
3140
3056
  """
3141
- Identifies whether a table has an incremental refresh policy.
3057
+ Identifies whether a table has an `incremental refresh <https://learn.microsoft.com/power-bi/connect-data/incremental-refresh-overview>`_ policy.
3142
3058
 
3143
3059
  Parameters
3144
3060
  ----------
@@ -3161,7 +3077,7 @@ class TOMWrapper:
3161
3077
 
3162
3078
  def show_incremental_refresh_policy(self, table_name: str):
3163
3079
  """
3164
- Prints the incremental refresh policy for a table.
3080
+ Prints the `incremental refresh <https://learn.microsoft.com/power-bi/connect-data/incremental-refresh-overview>`_ policy for a table.
3165
3081
 
3166
3082
  Parameters
3167
3083
  ----------
@@ -3169,11 +3085,13 @@ class TOMWrapper:
3169
3085
  Name of the table.
3170
3086
  """
3171
3087
 
3088
+ import Microsoft.AnalysisServices.Tabular as TOM
3089
+
3172
3090
  rp = self.model.Tables[table_name].RefreshPolicy
3173
3091
 
3174
3092
  if rp is None:
3175
3093
  print(
3176
- f"The '{table_name}' table in the '{self.dataset}' semantic model within the '{self.workspace}' workspace does not have an incremental refresh policy."
3094
+ f"{icons.yellow_dot} The '{table_name}' table in the '{self._dataset}' semantic model within the '{self._workspace}' workspace does not have an incremental refresh policy."
3177
3095
  )
3178
3096
  else:
3179
3097
  print(f"Table Name: {table_name}")
@@ -3181,33 +3099,33 @@ class TOMWrapper:
3181
3099
  icGran = str(rp.IncrementalGranularity).lower()
3182
3100
  if rp.RollingWindowPeriods > 1:
3183
3101
  print(
3184
- f"Archive data starting {start_bold}{rp.RollingWindowPeriods} {rwGran}s{end_bold} before refresh date."
3102
+ f"Archive data starting {icons.start_bold}{rp.RollingWindowPeriods} {rwGran}s{icons.end_bold} before refresh date."
3185
3103
  )
3186
3104
  else:
3187
3105
  print(
3188
- f"Archive data starting {start_bold}{rp.RollingWindowPeriods} {rwGran}{end_bold} before refresh date."
3106
+ f"Archive data starting {icons.start_bold}{rp.RollingWindowPeriods} {rwGran}{icons.end_bold} before refresh date."
3189
3107
  )
3190
3108
  if rp.IncrementalPeriods > 1:
3191
3109
  print(
3192
- f"Incrementally refresh data {start_bold}{rp.IncrementalPeriods} {icGran}s{end_bold} before refresh date."
3110
+ f"Incrementally refresh data {icons.start_bold}{rp.IncrementalPeriods} {icGran}s{icons.end_bold} before refresh date."
3193
3111
  )
3194
3112
  else:
3195
3113
  print(
3196
- f"Incrementally refresh data {start_bold}{rp.IncrementalPeriods} {icGran}{end_bold} before refresh date."
3114
+ f"Incrementally refresh data {icons.start_bold}{rp.IncrementalPeriods} {icGran}{icons.end_bold} before refresh date."
3197
3115
  )
3198
3116
 
3199
3117
  if rp.Mode == TOM.RefreshPolicyMode.Hybrid:
3200
3118
  print(
3201
- f"{checked} Get the latest data in real time with DirectQuery (Premium only)"
3119
+ f"{icons.checked} Get the latest data in real time with DirectQuery (Premium only)"
3202
3120
  )
3203
3121
  else:
3204
3122
  print(
3205
- f"{unchecked} Get the latest data in real time with DirectQuery (Premium only)"
3123
+ f"{icons.unchecked} Get the latest data in real time with DirectQuery (Premium only)"
3206
3124
  )
3207
3125
  if rp.IncrementalPeriodsOffset == -1:
3208
- print(f"{checked} Only refresh complete days")
3126
+ print(f"{icons.checked} Only refresh complete days")
3209
3127
  else:
3210
- print(f"{unchecked} Only refresh complete days")
3128
+ print(f"{icons.unchecked} Only refresh complete days")
3211
3129
  if len(rp.PollingExpression) > 0:
3212
3130
  pattern = r"\[([^\]]+)\]"
3213
3131
  match = re.search(pattern, rp.PollingExpression)
@@ -3215,10 +3133,10 @@ class TOMWrapper:
3215
3133
  col = match[0][1:-1]
3216
3134
  fullCol = format_dax_object_name(table_name, col)
3217
3135
  print(
3218
- f"{checked} Detect data changes: {start_bold}{fullCol}{end_bold}"
3136
+ f"{icons.checked} Detect data changes: {icons.start_bold}{fullCol}{icons.end_bold}"
3219
3137
  )
3220
3138
  else:
3221
- print(f"{unchecked} Detect data changes")
3139
+ print(f"{icons.unchecked} Detect data changes")
3222
3140
 
3223
3141
  def update_incremental_refresh_policy(
3224
3142
  self,
@@ -3231,7 +3149,7 @@ class TOMWrapper:
3231
3149
  detect_data_changes_column: Optional[str] = None,
3232
3150
  ):
3233
3151
  """
3234
- Updates the incremental refresh policy for a table within a semantic model.
3152
+ Updates the `incremental refresh <https://learn.microsoft.com/power-bi/connect-data/incremental-refresh-overview>`_ policy for a table within a semantic model.
3235
3153
 
3236
3154
  Parameters
3237
3155
  ----------
@@ -3266,26 +3184,16 @@ class TOMWrapper:
3266
3184
  rolling_window_granularity = rolling_window_granularity.capitalize()
3267
3185
 
3268
3186
  if incremental_granularity not in incGran:
3269
- print(
3270
- f"{icons.red_dot} Invalid 'incremental_granularity' value. Please choose from the following options: {incGran}."
3271
- )
3272
- return
3187
+ raise ValueError(f"{icons.red_dot} Invalid 'incremental_granularity' value. Please choose from the following options: {incGran}.")
3188
+
3273
3189
  if rolling_window_granularity not in incGran:
3274
- print(
3275
- f"{icons.red_dot} Invalid 'rolling_window_granularity' value. Please choose from the following options: {incGran}."
3276
- )
3277
- return
3190
+ raise ValueError(f"{icons.red_dot} Invalid 'rolling_window_granularity' value. Please choose from the following options: {incGran}.")
3278
3191
 
3279
3192
  if rolling_window_periods < 1:
3280
- print(
3281
- f"{icons.red_dot} Invalid 'rolling_window_periods' value. Must be a value greater than 0."
3282
- )
3283
- return
3193
+ raise ValueError(f"{icons.red_dot} Invalid 'rolling_window_periods' value. Must be a value greater than 0.")
3194
+
3284
3195
  if incremental_periods < 1:
3285
- print(
3286
- f"{icons.red_dot} Invalid 'incremental_periods' value. Must be a value greater than 0."
3287
- )
3288
- return
3196
+ raise ValueError(f"{icons.red_dot} Invalid 'incremental_periods' value. Must be a value greater than 0.")
3289
3197
 
3290
3198
  t = self.model.Tables[table_name]
3291
3199
 
@@ -3293,10 +3201,7 @@ class TOMWrapper:
3293
3201
  dc = t.Columns[detect_data_changes_column]
3294
3202
 
3295
3203
  if dc.DataType != TOM.DataType.DateTime:
3296
- print(
3297
- f"{icons.red_dot} Invalid 'detect_data_changes_column' parameter. This column must be of DateTime data type."
3298
- )
3299
- return
3204
+ raise ValueError(f"{icons.red_dot} Invalid 'detect_data_changes_column' parameter. This column must be of DateTime data type.")
3300
3205
 
3301
3206
  rp = TOM.BasicRefreshPolicy()
3302
3207
  rp.IncrementalPeriods = incremental_periods
@@ -3339,7 +3244,7 @@ class TOMWrapper:
3339
3244
  detect_data_changes_column: Optional[str] = None,
3340
3245
  ):
3341
3246
  """
3342
- Adds anincremental refresh policy for a table within a semantic model.
3247
+ Adds an `incremental refresh <https://learn.microsoft.com/power-bi/connect-data/incremental-refresh-overview>`_ policy for a table within a semantic model.
3343
3248
 
3344
3249
  Parameters
3345
3250
  ----------
@@ -3376,26 +3281,16 @@ class TOMWrapper:
3376
3281
  rolling_window_granularity = rolling_window_granularity.capitalize()
3377
3282
 
3378
3283
  if incremental_granularity not in incGran:
3379
- print(
3380
- f"{icons.red_dot} Invalid 'incremental_granularity' value. Please choose from the following options: {incGran}."
3381
- )
3382
- return
3284
+ raise ValueError(f"{icons.red_dot} Invalid 'incremental_granularity' value. Please choose from the following options: {incGran}.")
3285
+
3383
3286
  if rolling_window_granularity not in incGran:
3384
- print(
3385
- f"{icons.red_dot} Invalid 'rolling_window_granularity' value. Please choose from the following options: {incGran}."
3386
- )
3387
- return
3287
+ raise ValueError(f"{icons.red_dot} Invalid 'rolling_window_granularity' value. Please choose from the following options: {incGran}.")
3388
3288
 
3389
3289
  if rolling_window_periods < 1:
3390
- print(
3391
- f"{icons.red_dot} Invalid 'rolling_window_periods' value. Must be a value greater than 0."
3392
- )
3393
- return
3290
+ raise ValueError(f"{icons.red_dot} Invalid 'rolling_window_periods' value. Must be a value greater than 0.")
3291
+
3394
3292
  if incremental_periods < 1:
3395
- print(
3396
- f"{icons.red_dot} Invalid 'incremental_periods' value. Must be a value greater than 0."
3397
- )
3398
- return
3293
+ raise ValueError(f"{icons.red_dot} Invalid 'incremental_periods' value. Must be a value greater than 0.")
3399
3294
 
3400
3295
  date_format = "%m/%d/%Y"
3401
3296
 
@@ -3410,10 +3305,7 @@ class TOMWrapper:
3410
3305
  end_day = date_obj_end.day
3411
3306
 
3412
3307
  if date_obj_end <= date_obj_start:
3413
- print(
3414
- f"{icons.red_dot} Invalid 'start_date' or 'end_date'. The 'end_date' must be after the 'start_date'."
3415
- )
3416
- return
3308
+ raise ValueError(f"{icons.red_dot} Invalid 'start_date' or 'end_date'. The 'end_date' must be after the 'start_date'.")
3417
3309
 
3418
3310
  t = self.model.Tables[table_name]
3419
3311
 
@@ -3422,20 +3314,14 @@ class TOMWrapper:
3422
3314
  dType = c.DataType
3423
3315
 
3424
3316
  if dType != TOM.DataType.DateTime:
3425
- print(
3426
- f"{icons.red_dot} The {fcName} column is of '{dType}' data type. The column chosen must be of DateTime data type."
3427
- )
3428
- return
3317
+ raise ValueError(f"{icons.red_dot} The {fcName} column is of '{dType}' data type. The column chosen must be of DateTime data type.")
3429
3318
 
3430
3319
  if detect_data_changes_column is not None:
3431
3320
  dc = t.Columns[detect_data_changes_column]
3432
3321
  dcType = dc.DataType
3433
3322
 
3434
3323
  if dcType != TOM.DataType.DateTime:
3435
- print(
3436
- f"{icons.red_dot} Invalid 'detect_data_changes_column' parameter. This column must be of DateTime data type."
3437
- )
3438
- return
3324
+ raise ValueError(f"{icons.red_dot} Invalid 'detect_data_changes_column' parameter. This column must be of DateTime data type.")
3439
3325
 
3440
3326
  # Start changes:
3441
3327
 
@@ -3443,10 +3329,8 @@ class TOMWrapper:
3443
3329
  i = 0
3444
3330
  for p in t.Partitions:
3445
3331
  if p.SourceType != TOM.PartitionSourceType.M:
3446
- print(
3447
- f"{icons.red_dot} Invalid partition source type. Incremental refresh can only be set up if the table's partition is an M-partition."
3448
- )
3449
- return
3332
+ raise ValueError(f"{icons.red_dot} Invalid partition source type. Incremental refresh can only be set up if the table's partition is an M-partition.")
3333
+
3450
3334
  elif i == 0:
3451
3335
  text = p.Expression
3452
3336
  text = text.rstrip()
@@ -3462,8 +3346,7 @@ class TOMWrapper:
3462
3346
 
3463
3347
  print(text_before_last_match)
3464
3348
  else:
3465
- print(f"{icons.red_dot} Invalid M-partition expression.")
3466
- return
3349
+ raise ValueError(f"{icons.red_dot} Invalid M-partition expression.")
3467
3350
 
3468
3351
  endExpr = f'#"Filtered Rows IR" = Table.SelectRows({obj}, each [{column_name}] >= RangeStart and [{column_name}] <= RangeEnd)\n#"Filtered Rows IR"'
3469
3352
  finalExpr = text_before_last_match + endExpr
@@ -3514,7 +3397,7 @@ class TOMWrapper:
3514
3397
  max_parallelism: Optional[int] = 0,
3515
3398
  ):
3516
3399
  """
3517
- Applies the incremental refresh policy for a table within a semantic model.
3400
+ `Applies the incremental refresh <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.table.applyrefreshpolicy?view=analysisservices-dotnet#microsoft-analysisservices-tabular-table-applyrefreshpolicy(system-boolean-system-int32)>`_ policy for a table within a semantic model.
3518
3401
 
3519
3402
  Parameters
3520
3403
  ----------
@@ -3538,7 +3421,7 @@ class TOMWrapper:
3538
3421
  self, table_name: str, partition_name: str, expression: str
3539
3422
  ):
3540
3423
  """
3541
- Sets the data coverage definition for a partition.
3424
+ Sets the `data coverage definition <https://learn.microsoft.com/analysis-services/tom/table-partitions?view=asallproducts-allversions>`_ for a partition.
3542
3425
 
3543
3426
  Parameters
3544
3427
  ----------
@@ -3559,15 +3442,9 @@ class TOMWrapper:
3559
3442
  ht = self.is_hybrid_table(table_name=table_name)
3560
3443
 
3561
3444
  if not ht:
3562
- print(
3563
- f"The data coverage definition property is only applicable to hybrid tables. See the documentation: {doc}."
3564
- )
3565
- return
3445
+ raise ValueError(f"{icons.red_dot} The `data coverage definition <https://learn.microsoft.com/analysis-services/tom/table-partitions?view=asallproducts-allversions>`_ property is only applicable to `hybrid tables <https://learn.microsoft.com/power-bi/connect-data/service-dataset-modes-understand#hybrid-tables>`_. See the documentation: {doc}.")
3566
3446
  if p.Mode != TOM.ModeType.DirectQuery:
3567
- print(
3568
- f"The data coverage definition property is only applicable to the DirectQuery partition of a hybrid table. See the documentation: {doc}."
3569
- )
3570
- return
3447
+ raise ValueError(f"{icons.red_dot} The `data coverage definition <https://learn.microsoft.com/analysis-services/tom/table-partitions?view=asallproducts-allversions>`_ property is only applicable to the DirectQuery partition of a `hybrid table <https://learn.microsoft.com/power-bi/connect-data/service-dataset-modes-understand#hybrid-tables>`_. See the documentation: {doc}.")
3571
3448
 
3572
3449
  dcd = TOM.DataCoverageDefinition()
3573
3450
  dcd.Expression = expression
@@ -3575,7 +3452,7 @@ class TOMWrapper:
3575
3452
 
3576
3453
  def set_encoding_hint(self, table_name: str, column_name: str, value: str):
3577
3454
  """
3578
- Sets the encoding hint for a column.
3455
+ Sets the `encoding hint <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.encodinghinttype?view=analysisservices-dotnet>`_ for a column.
3579
3456
 
3580
3457
  Parameters
3581
3458
  ----------
@@ -3594,10 +3471,7 @@ class TOMWrapper:
3594
3471
  value = value.capitalize()
3595
3472
 
3596
3473
  if value not in values:
3597
- print(
3598
- f"{icons.red_dot} Invalid encoding hint value. Please choose from these options: {values}."
3599
- )
3600
- return
3474
+ raise ValueError(f"{icons.red_dot} Invalid encoding hint value. Please choose from these options: {values}.")
3601
3475
 
3602
3476
  self.model.Tables[table_name].Columns[column_name].EncodingHint = (
3603
3477
  System.Enum.Parse(TOM.EncodingHintType, value)
@@ -3605,7 +3479,7 @@ class TOMWrapper:
3605
3479
 
3606
3480
  def set_data_type(self, table_name: str, column_name: str, value: str):
3607
3481
  """
3608
- Sets the data type for a column.
3482
+ Sets the `data type <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.datatype?view=analysisservices-dotnet>`_ for a column.
3609
3483
 
3610
3484
  Parameters
3611
3485
  ----------
@@ -3617,6 +3491,7 @@ class TOMWrapper:
3617
3491
  The data type.
3618
3492
  `Data type valid values <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.datatype?view=analysisservices-dotnet>`_
3619
3493
  """
3494
+ import Microsoft.AnalysisServices.Tabular as TOM
3620
3495
  import System
3621
3496
 
3622
3497
  values = [
@@ -3638,10 +3513,7 @@ class TOMWrapper:
3638
3513
  value = "Boolean"
3639
3514
 
3640
3515
  if value not in values:
3641
- print(
3642
- f"{icons.red_dot} Invalid data type. Please choose from these options: {values}."
3643
- )
3644
- return
3516
+ raise ValueError(f"{icons.red_dot} Invalid data type. Please choose from these options: {values}.")
3645
3517
 
3646
3518
  self.model.Tables[table_name].Columns[column_name].DataType = System.Enum.Parse(
3647
3519
  TOM.DataType, value
@@ -3673,10 +3545,7 @@ class TOMWrapper:
3673
3545
  for t in time_intel:
3674
3546
  t = t.capitalize()
3675
3547
  if t not in [time_intel_options]:
3676
- print(
3677
- f"The '{t}' time intelligence variation is not supported. Valid options: {time_intel_options}."
3678
- )
3679
- return
3548
+ raise ValueError(f"{icons.red_dot} The '{t}' time intelligence variation is not supported. Valid options: {time_intel_options}.")
3680
3549
 
3681
3550
  # Validate measure and extract table name
3682
3551
  for m in self.all_measures():
@@ -3684,17 +3553,11 @@ class TOMWrapper:
3684
3553
  table_name = m.Parent.Name
3685
3554
 
3686
3555
  if table_name is None:
3687
- print(
3688
- f"The '{measure_name}' is not a valid measure in the '{self.dataset}' semantic model within the '{self.workspace}' workspace."
3689
- )
3690
- return
3556
+ raise ValueError(f"{icons.red_dot} The '{measure_name}' is not a valid measure in the '{self._dataset}' semantic model within the '{self._workspace}' workspace.")
3691
3557
 
3692
3558
  # Validate date table
3693
3559
  if not self.is_date_table(date_table):
3694
- print(
3695
- f"{icons.red_dot} The '{date_table}' table is not a valid date table in the '{self.dataset}' wemantic model within the '{self.workspace}' workspace."
3696
- )
3697
- return
3560
+ raise ValueError(f"{icons.red_dot} The '{date_table}' table is not a valid date table in the '{self._dataset}' wemantic model within the '{self._workspace}' workspace.")
3698
3561
 
3699
3562
  # Extract date key from date table
3700
3563
  for c in self.all_columns():
@@ -3712,26 +3575,100 @@ class TOMWrapper:
3712
3575
  expression=expr,
3713
3576
  )
3714
3577
 
3578
+ def update_m_partition(self, table_name: str, partition_name: str, expression: Optional[str | None] = None, mode: Optional[str | None] = None, description: Optional[str | None] = None):
3579
+
3580
+ """
3581
+ Updates an M partition for a table within a semantic model.
3582
+
3583
+ Parameters
3584
+ ----------
3585
+ table_name : str
3586
+ Name of the table.
3587
+ partition_name : str
3588
+ Name of the partition.
3589
+ expression : str, default=None
3590
+ The `M expression <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.mpartitionsource.expression?view=analysisservices-dotnet>`_ containing the logic for the partition.
3591
+ Defaults to None which keeps the existing setting.
3592
+ mode : str, default=None
3593
+ The query `mode <https://learn.microsoft.com/dotnet/api/microsoft.analysisservices.tabular.modetype?view=analysisservices-dotnet>`_ of the partition.
3594
+ Defaults to None which keeps the existing setting.
3595
+ description : str, default=None
3596
+ The description of the partition.
3597
+ Defaults to None which keeps the existing setting.
3598
+ """
3599
+
3600
+ import Microsoft.AnalysisServices.Tabular as TOM
3601
+ import System
3602
+
3603
+ p = self.model.Tables[table_name].Partitions[partition_name]
3604
+ if p.SourceType != TOM.PartitionSourceType.M:
3605
+ raise ValueError(f"Invalid partition source type. This function is only for M partitions.")
3606
+ if expression is not None:
3607
+ p.Source.Expression = expression
3608
+ if mode is not None:
3609
+ p.Mode = System.Enum.Parse(TOM.ModeType, mode)
3610
+ if description is not None:
3611
+ p.Description = description
3612
+
3613
+ def set_sort_by_column(self, table_name: str, column_name: str, sort_by_column: str):
3614
+
3615
+ """
3616
+ Sets the sort by column for a column in a semantic model.
3617
+
3618
+ Parameters
3619
+ ----------
3620
+ table_name : str
3621
+ Name of the table.
3622
+ column_name : str
3623
+ Name of the column.
3624
+ sort_by_column : str
3625
+ Name of the column to use for sorting. Must be of integer (Int64) data type.
3626
+ """
3627
+
3628
+ import Microsoft.AnalysisServices.Tabular as TOM
3629
+
3630
+ sbc = self.model.Tables[table_name].Columns[sort_by_column]
3631
+
3632
+ if sbc.DataType != TOM.DataType.Int64:
3633
+ raise ValueError(f"Invalid sort by column data type. The sort by column must be of 'Int64' data type.")
3634
+
3635
+ self.model.Tables[table_name].Columns[column_name].SortByColumn = sbc
3636
+
3637
+ def remove_sort_by_column(self, table_name: str, column_name: str):
3638
+
3639
+ """
3640
+ Removes the sort by column for a column in a semantic model.
3641
+
3642
+ Parameters
3643
+ ----------
3644
+ table_name : str
3645
+ Name of the table.
3646
+ column_name : str
3647
+ Name of the column.
3648
+ """
3649
+
3650
+ self.model.Tables[table_name].Columns[column_name].SortByColumn = None
3651
+
3715
3652
  def close(self):
3716
- if not self.readonly and self.model is not None:
3653
+ if not self._readonly and self.model is not None:
3717
3654
  self.model.SaveChanges()
3718
3655
 
3719
- if len(self.tables_added) > 0:
3656
+ if len(self._tables_added) > 0:
3720
3657
  refresh_semantic_model(
3721
- dataset=self.dataset,
3722
- tables=self.tables_added,
3723
- workspace=self.workspace,
3658
+ dataset=self._dataset,
3659
+ tables=self._tables_added,
3660
+ workspace=self._workspace,
3724
3661
  )
3725
3662
  self.model = None
3726
3663
 
3727
- self.tom_server.Dispose()
3664
+ self._tom_server.Dispose()
3728
3665
 
3729
3666
 
3730
3667
  @log
3731
3668
  @contextmanager
3732
3669
  def connect_semantic_model(
3733
3670
  dataset: str, readonly: bool = True, workspace: Optional[str] = None
3734
- ):
3671
+ ) -> Iterator[TOMWrapper]:
3735
3672
  """
3736
3673
  Connects to the Tabular Object Model (TOM) within a semantic model.
3737
3674
 
@@ -3748,7 +3685,7 @@ def connect_semantic_model(
3748
3685
 
3749
3686
  Returns
3750
3687
  -------
3751
- str
3688
+ typing.Iterator[TOMWrapper]
3752
3689
  A connection to the semantic model's Tabular Object Model.
3753
3690
  """
3754
3691
 
@@ -3763,4 +3700,4 @@ def connect_semantic_model(
3763
3700
  try:
3764
3701
  yield tw
3765
3702
  finally:
3766
- tw.close()
3703
+ tw.close()