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.

Files changed (59) hide show
  1. {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/METADATA +43 -7
  2. {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/RECORD +59 -40
  3. {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +116 -58
  5. sempy_labs/_ai.py +0 -2
  6. sempy_labs/_capacities.py +39 -3
  7. sempy_labs/_capacity_migration.py +623 -0
  8. sempy_labs/_clear_cache.py +8 -8
  9. sempy_labs/_connections.py +15 -13
  10. sempy_labs/_data_pipelines.py +118 -0
  11. sempy_labs/_documentation.py +144 -0
  12. sempy_labs/_eventhouses.py +118 -0
  13. sempy_labs/_eventstreams.py +118 -0
  14. sempy_labs/_generate_semantic_model.py +3 -3
  15. sempy_labs/_git.py +23 -24
  16. sempy_labs/_helper_functions.py +140 -47
  17. sempy_labs/_icons.py +40 -0
  18. sempy_labs/_kql_databases.py +134 -0
  19. sempy_labs/_kql_querysets.py +124 -0
  20. sempy_labs/_list_functions.py +218 -421
  21. sempy_labs/_mirrored_warehouses.py +50 -0
  22. sempy_labs/_ml_experiments.py +122 -0
  23. sempy_labs/_ml_models.py +120 -0
  24. sempy_labs/_model_auto_build.py +0 -4
  25. sempy_labs/_model_bpa.py +10 -12
  26. sempy_labs/_model_bpa_bulk.py +8 -7
  27. sempy_labs/_model_dependencies.py +26 -18
  28. sempy_labs/_notebooks.py +5 -16
  29. sempy_labs/_query_scale_out.py +6 -5
  30. sempy_labs/_refresh_semantic_model.py +7 -19
  31. sempy_labs/_spark.py +40 -45
  32. sempy_labs/_sql.py +60 -15
  33. sempy_labs/_vertipaq.py +25 -25
  34. sempy_labs/_warehouses.py +132 -0
  35. sempy_labs/_workspaces.py +0 -3
  36. sempy_labs/admin/__init__.py +53 -0
  37. sempy_labs/admin/_basic_functions.py +888 -0
  38. sempy_labs/admin/_domains.py +411 -0
  39. sempy_labs/directlake/_directlake_schema_sync.py +1 -1
  40. sempy_labs/directlake/_dl_helper.py +32 -16
  41. sempy_labs/directlake/_generate_shared_expression.py +11 -14
  42. sempy_labs/directlake/_guardrails.py +7 -7
  43. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +14 -24
  44. sempy_labs/directlake/_update_directlake_partition_entity.py +1 -1
  45. sempy_labs/directlake/_warm_cache.py +1 -1
  46. sempy_labs/lakehouse/_get_lakehouse_tables.py +3 -3
  47. sempy_labs/lakehouse/_lakehouse.py +3 -2
  48. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +5 -0
  49. sempy_labs/report/__init__.py +9 -6
  50. sempy_labs/report/_generate_report.py +1 -1
  51. sempy_labs/report/_report_bpa.py +369 -0
  52. sempy_labs/report/_report_bpa_rules.py +113 -0
  53. sempy_labs/report/_report_helper.py +254 -0
  54. sempy_labs/report/_report_list_functions.py +95 -0
  55. sempy_labs/report/_report_rebind.py +0 -4
  56. sempy_labs/report/_reportwrapper.py +2037 -0
  57. sempy_labs/tom/_model.py +333 -22
  58. {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/LICENSE +0 -0
  59. {semantic_link_labs-0.7.4.dist-info → semantic_link_labs-0.8.1.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ from sempy_labs._helper_functions import (
5
5
  resolve_lakehouse_id,
6
6
  resolve_dataset_id,
7
7
  pagination,
8
- lro,
9
8
  resolve_item_type,
10
9
  format_dax_object_name,
11
10
  )
@@ -83,7 +82,7 @@ def get_object_level_security(
83
82
 
84
83
 
85
84
  def list_tables(
86
- dataset: str, workspace: Optional[str] = None, extended: Optional[bool] = False
85
+ dataset: str, workspace: Optional[str] = None, extended: bool = False
87
86
  ) -> pd.DataFrame:
88
87
  """
89
88
  Shows a semantic model's tables and their properties.
@@ -706,9 +705,9 @@ def list_lakehouses(workspace: Optional[str] = None) -> pd.DataFrame:
706
705
  return df
707
706
 
708
707
 
709
- def list_warehouses(workspace: Optional[str] = None) -> pd.DataFrame:
708
+ def list_sql_endpoints(workspace: Optional[str] = None) -> pd.DataFrame:
710
709
  """
711
- Shows the warehouses within a workspace.
710
+ Shows the SQL endpoints within a workspace.
712
711
 
713
712
  Parameters
714
713
  ----------
@@ -720,64 +719,10 @@ def list_warehouses(workspace: Optional[str] = None) -> pd.DataFrame:
720
719
  Returns
721
720
  -------
722
721
  pandas.DataFrame
723
- A pandas dataframe showing the warehouses within a workspace.
722
+ A pandas dataframe showing the SQL endpoints within a workspace.
724
723
  """
725
724
 
726
- df = pd.DataFrame(
727
- columns=[
728
- "Warehouse Name",
729
- "Warehouse ID",
730
- "Description",
731
- "Connection Info",
732
- "Created Date",
733
- "Last Updated Time",
734
- ]
735
- )
736
-
737
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
738
-
739
- client = fabric.FabricRestClient()
740
- response = client.get(f"/v1/workspaces/{workspace_id}/warehouses")
741
- if response.status_code != 200:
742
- raise FabricHTTPException(response)
743
-
744
- responses = pagination(client, response)
745
-
746
- for r in responses:
747
- for v in r.get("value", []):
748
- prop = v.get("properties", {})
749
-
750
- new_data = {
751
- "Warehouse Name": v.get("displayName"),
752
- "Warehouse ID": v.get("id"),
753
- "Description": v.get("description"),
754
- "Connection Info": prop.get("connectionInfo"),
755
- "Created Date": prop.get("createdDate"),
756
- "Last Updated Time": prop.get("lastUpdatedTime"),
757
- }
758
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
759
-
760
- return df
761
-
762
-
763
- def list_sqlendpoints(workspace: Optional[str] = None) -> pd.DataFrame:
764
- """
765
- Shows the SQL Endpoints within a workspace.
766
-
767
- Parameters
768
- ----------
769
- workspace : str, default=None
770
- The Fabric workspace name.
771
- Defaults to None which resolves to the workspace of the attached lakehouse
772
- or if no lakehouse attached, resolves to the workspace of the notebook.
773
-
774
- Returns
775
- -------
776
- pandas.DataFrame
777
- A pandas dataframe showing the SQL Endpoints within a workspace.
778
- """
779
-
780
- df = pd.DataFrame(columns=["SQL Endpoint ID", "SQL Endpoint Name", "Description"])
725
+ df = pd.DataFrame(columns=["SQL Endpoint Id", "SQL Endpoint Name", "Description"])
781
726
 
782
727
  (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
783
728
 
@@ -792,7 +737,7 @@ def list_sqlendpoints(workspace: Optional[str] = None) -> pd.DataFrame:
792
737
  for v in r.get("value", []):
793
738
 
794
739
  new_data = {
795
- "SQL Endpoint ID": v.get("id"),
740
+ "SQL Endpoint Id": v.get("id"),
796
741
  "SQL Endpoint Name": v.get("displayName"),
797
742
  "Description": v.get("description"),
798
743
  }
@@ -801,310 +746,6 @@ def list_sqlendpoints(workspace: Optional[str] = None) -> pd.DataFrame:
801
746
  return df
802
747
 
803
748
 
804
- def list_mirroredwarehouses(workspace: Optional[str] = None) -> pd.DataFrame:
805
- """
806
- Shows the mirrored warehouses within a workspace.
807
-
808
- Parameters
809
- ----------
810
- workspace : str, default=None
811
- The Fabric workspace name.
812
- Defaults to None which resolves to the workspace of the attached lakehouse
813
- or if no lakehouse attached, resolves to the workspace of the notebook.
814
-
815
- Returns
816
- -------
817
- pandas.DataFrame
818
- A pandas dataframe showing the mirrored warehouses within a workspace.
819
- """
820
-
821
- df = pd.DataFrame(
822
- columns=["Mirrored Warehouse", "Mirrored Warehouse ID", "Description"]
823
- )
824
-
825
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
826
-
827
- client = fabric.FabricRestClient()
828
- response = client.get(f"/v1/workspaces/{workspace_id}/mirroredWarehouses")
829
- if response.status_code != 200:
830
- raise FabricHTTPException(response)
831
-
832
- responses = pagination(client, response)
833
-
834
- for r in responses:
835
- for v in r.get("value", []):
836
-
837
- new_data = {
838
- "Mirrored Warehouse": v.get("displayName"),
839
- "Mirrored Warehouse ID": v.get("id"),
840
- "Description": v.get("description"),
841
- }
842
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
843
-
844
- return df
845
-
846
-
847
- def list_kqldatabases(workspace: Optional[str] = None) -> pd.DataFrame:
848
- """
849
- Shows the KQL databases within a workspace.
850
-
851
- Parameters
852
- ----------
853
- workspace : str, default=None
854
- The Fabric workspace name.
855
- Defaults to None which resolves to the workspace of the attached lakehouse
856
- or if no lakehouse attached, resolves to the workspace of the notebook.
857
-
858
- Returns
859
- -------
860
- pandas.DataFrame
861
- A pandas dataframe showing the KQL Databases within a workspace.
862
- """
863
-
864
- df = pd.DataFrame(
865
- columns=[
866
- "KQL Database Name",
867
- "KQL Database ID",
868
- "Description",
869
- "Parent Eventhouse Item ID",
870
- "Query Service URI",
871
- "Ingestion Service URI",
872
- "Kusto Database Type",
873
- ]
874
- )
875
-
876
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
877
-
878
- client = fabric.FabricRestClient()
879
- response = client.get(f"/v1/workspaces/{workspace_id}/kqlDatabases")
880
- if response.status_code != 200:
881
- raise FabricHTTPException(response)
882
-
883
- responses = pagination(client, response)
884
-
885
- for r in responses:
886
- for v in r.get("value", []):
887
- prop = v.get("properties", {})
888
-
889
- new_data = {
890
- "KQL Database Name": v.get("displayName"),
891
- "KQL Database ID": v.get("id"),
892
- "Description": v.get("description"),
893
- "Parent Eventhouse Item ID": prop.get("parentEventhouseItemId"),
894
- "Query Service URI": prop.get("queryServiceUri"),
895
- "Ingestion Service URI": prop.get("ingestionServiceUri"),
896
- "Kusto Database Type": prop.get("kustoDatabaseType"),
897
- }
898
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
899
-
900
- return df
901
-
902
-
903
- def list_kqlquerysets(workspace: Optional[str] = None) -> pd.DataFrame:
904
- """
905
- Shows the KQL Querysets within a workspace.
906
-
907
- Parameters
908
- ----------
909
- workspace : str, default=None
910
- The Fabric workspace name.
911
- Defaults to None which resolves to the workspace of the attached lakehouse
912
- or if no lakehouse attached, resolves to the workspace of the notebook.
913
-
914
- Returns
915
- -------
916
- pandas.DataFrame
917
- A pandas dataframe showing the KQL Querysets within a workspace.
918
- """
919
-
920
- df = pd.DataFrame(columns=["KQL Queryset Name", "KQL Queryset ID", "Description"])
921
-
922
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
923
-
924
- client = fabric.FabricRestClient()
925
- response = client.get(f"/v1/workspaces/{workspace_id}/kqlQuerysets")
926
- if response.status_code != 200:
927
- raise FabricHTTPException(response)
928
-
929
- responses = pagination(client, response)
930
-
931
- for r in responses:
932
- for v in r.get("value", []):
933
-
934
- new_data = {
935
- "KQL Queryset Name": v.get("displayName"),
936
- "KQL Queryset ID": v.get("id"),
937
- "Description": v.get("description"),
938
- }
939
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
940
-
941
- return df
942
-
943
-
944
- def list_mlmodels(workspace: Optional[str] = None) -> pd.DataFrame:
945
- """
946
- Shows the ML models within a workspace.
947
-
948
- Parameters
949
- ----------
950
- workspace : str, default=None
951
- The Fabric workspace name.
952
- Defaults to None which resolves to the workspace of the attached lakehouse
953
- or if no lakehouse attached, resolves to the workspace of the notebook.
954
-
955
- Returns
956
- -------
957
- pandas.DataFrame
958
- A pandas dataframe showing the ML models within a workspace.
959
- """
960
-
961
- df = pd.DataFrame(columns=["ML Model Name", "ML Model ID", "Description"])
962
-
963
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
964
-
965
- client = fabric.FabricRestClient()
966
- response = client.get(f"/v1/workspaces/{workspace_id}/mlModels")
967
- if response.status_code != 200:
968
- raise FabricHTTPException(response)
969
-
970
- responses = pagination(client, response)
971
-
972
- for r in responses:
973
- for v in r.get("value", []):
974
- model_id = v.get("id")
975
- modelName = v.get("displayName")
976
- desc = v.get("description")
977
-
978
- new_data = {
979
- "ML Model Name": modelName,
980
- "ML Model ID": model_id,
981
- "Description": desc,
982
- }
983
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
984
-
985
- return df
986
-
987
-
988
- def list_eventstreams(workspace: Optional[str] = None) -> pd.DataFrame:
989
- """
990
- Shows the eventstreams within a workspace.
991
-
992
- Parameters
993
- ----------
994
- workspace : str, default=None
995
- The Fabric workspace name.
996
- Defaults to None which resolves to the workspace of the attached lakehouse
997
- or if no lakehouse attached, resolves to the workspace of the notebook.
998
-
999
- Returns
1000
- -------
1001
- pandas.DataFrame
1002
- A pandas dataframe showing the eventstreams within a workspace.
1003
- """
1004
-
1005
- df = pd.DataFrame(columns=["Eventstream Name", "Eventstream ID", "Description"])
1006
-
1007
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
1008
-
1009
- client = fabric.FabricRestClient()
1010
- response = client.get(f"/v1/workspaces/{workspace_id}/eventstreams")
1011
- if response.status_code != 200:
1012
- raise FabricHTTPException(response)
1013
-
1014
- responses = pagination(client, response)
1015
-
1016
- for r in responses:
1017
- for v in r.get("value", []):
1018
- new_data = {
1019
- "Eventstream Name": v.get("displayName"),
1020
- "Eventstream ID": v.get("id"),
1021
- "Description": v.get("description"),
1022
- }
1023
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
1024
-
1025
- return df
1026
-
1027
-
1028
- def list_datapipelines(workspace: Optional[str] = None) -> pd.DataFrame:
1029
- """
1030
- Shows the data pipelines within a workspace.
1031
-
1032
- Parameters
1033
- ----------
1034
- workspace : str, default=None
1035
- The Fabric workspace name.
1036
- Defaults to None which resolves to the workspace of the attached lakehouse
1037
- or if no lakehouse attached, resolves to the workspace of the notebook.
1038
-
1039
- Returns
1040
- -------
1041
- pandas.DataFrame
1042
- A pandas dataframe showing the data pipelines within a workspace.
1043
- """
1044
-
1045
- df = pd.DataFrame(columns=["Data Pipeline Name", "Data Pipeline ID", "Description"])
1046
-
1047
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
1048
-
1049
- client = fabric.FabricRestClient()
1050
- response = client.get(f"/v1/workspaces/{workspace_id}/dataPipelines")
1051
- if response.status_code != 200:
1052
- raise FabricHTTPException(response)
1053
-
1054
- responses = pagination(client, response)
1055
-
1056
- for r in responses:
1057
- for v in r.get("value", []):
1058
- new_data = {
1059
- "Data Pipeline Name": v.get("displayName"),
1060
- "Data Pipeline ID": v.get("id"),
1061
- "Description": v.get("description"),
1062
- }
1063
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
1064
-
1065
- return df
1066
-
1067
-
1068
- def list_mlexperiments(workspace: Optional[str] = None) -> pd.DataFrame:
1069
- """
1070
- Shows the ML experiments within a workspace.
1071
-
1072
- Parameters
1073
- ----------
1074
- workspace : str, default=None
1075
- The Fabric workspace name.
1076
- Defaults to None which resolves to the workspace of the attached lakehouse
1077
- or if no lakehouse attached, resolves to the workspace of the notebook.
1078
-
1079
- Returns
1080
- -------
1081
- pandas.DataFrame
1082
- A pandas dataframe showing the ML experiments within a workspace.
1083
- """
1084
-
1085
- df = pd.DataFrame(columns=["ML Experiment Name", "ML Experiment ID", "Description"])
1086
-
1087
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
1088
-
1089
- client = fabric.FabricRestClient()
1090
- response = client.get(f"/v1/workspaces/{workspace_id}/mlExperiments")
1091
- if response.status_code != 200:
1092
- raise FabricHTTPException(response)
1093
-
1094
- responses = pagination(client, response)
1095
-
1096
- for r in responses:
1097
- for v in r.get("value", []):
1098
- new_data = {
1099
- "ML Experiment Name": v.get("displayName"),
1100
- "ML Experiment ID": v.get("id"),
1101
- "Description": v.get("description"),
1102
- }
1103
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
1104
-
1105
- return df
1106
-
1107
-
1108
749
  def list_datamarts(workspace: Optional[str] = None) -> pd.DataFrame:
1109
750
  """
1110
751
  Shows the datamarts within a workspace.
@@ -1145,43 +786,6 @@ def list_datamarts(workspace: Optional[str] = None) -> pd.DataFrame:
1145
786
  return df
1146
787
 
1147
788
 
1148
- def create_warehouse(
1149
- warehouse: str, description: Optional[str] = None, workspace: Optional[str] = None
1150
- ):
1151
- """
1152
- Creates a Fabric warehouse.
1153
-
1154
- Parameters
1155
- ----------
1156
- warehouse: str
1157
- Name of the warehouse.
1158
- description : str, default=None
1159
- A description of the warehouse.
1160
- workspace : str, default=None
1161
- The Fabric workspace name.
1162
- Defaults to None which resolves to the workspace of the attached lakehouse
1163
- or if no lakehouse attached, resolves to the workspace of the notebook.
1164
- """
1165
-
1166
- (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
1167
-
1168
- request_body = {"displayName": warehouse}
1169
-
1170
- if description:
1171
- request_body["description"] = description
1172
-
1173
- client = fabric.FabricRestClient()
1174
- response = client.post(
1175
- f"/v1/workspaces/{workspace_id}/warehouses/", json=request_body
1176
- )
1177
-
1178
- lro(client, response, status_codes=[201, 202])
1179
-
1180
- print(
1181
- f"{icons.green_dot} The '{warehouse}' warehouse has been created within the '{workspace}' workspace."
1182
- )
1183
-
1184
-
1185
789
  def update_item(
1186
790
  item_type: str,
1187
791
  current_name: str,
@@ -1209,27 +813,14 @@ def update_item(
1209
813
  """
1210
814
 
1211
815
  (workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
1212
-
1213
- itemTypes = {
1214
- "DataPipeline": "dataPipelines",
1215
- "Eventstream": "eventstreams",
1216
- "KQLDatabase": "kqlDatabases",
1217
- "KQLQueryset": "kqlQuerysets",
1218
- "Lakehouse": "lakehouses",
1219
- "MLExperiment": "mlExperiments",
1220
- "MLModel": "mlModels",
1221
- "Notebook": "notebooks",
1222
- "Warehouse": "warehouses",
1223
- }
1224
-
1225
816
  item_type = item_type.replace(" ", "").capitalize()
1226
817
 
1227
- if item_type not in itemTypes.keys():
818
+ if item_type not in icons.itemTypes.keys():
1228
819
  raise ValueError(
1229
820
  f"{icons.red_dot} The '{item_type}' is not a valid item type. "
1230
821
  )
1231
822
 
1232
- itemType = itemTypes[item_type]
823
+ itemType = icons.itemTypes[item_type]
1233
824
 
1234
825
  dfI = fabric.list_items(workspace=workspace, type=item_type)
1235
826
  dfI_filt = dfI[(dfI["Display Name"] == current_name)]
@@ -1263,7 +854,7 @@ def update_item(
1263
854
 
1264
855
 
1265
856
  def list_relationships(
1266
- dataset: str, workspace: Optional[str] = None, extended: Optional[bool] = False
857
+ dataset: str, workspace: Optional[str] = None, extended: bool = False
1267
858
  ) -> pd.DataFrame:
1268
859
  """
1269
860
  Shows a semantic model's relationships and their properties.
@@ -1687,9 +1278,6 @@ def list_capacities() -> pd.DataFrame:
1687
1278
  """
1688
1279
  Shows the capacities and their properties.
1689
1280
 
1690
- Parameters
1691
- ----------
1692
-
1693
1281
  Returns
1694
1282
  -------
1695
1283
  pandas.DataFrame
@@ -1774,3 +1362,212 @@ def list_reports_using_semantic_model(
1774
1362
  df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
1775
1363
 
1776
1364
  return df
1365
+
1366
+
1367
+ def list_report_semantic_model_objects(
1368
+ dataset: str, workspace: Optional[str] = None, extended: bool = False
1369
+ ) -> pd.DataFrame:
1370
+ """
1371
+ Shows a list of semantic model objects (i.e. columns, measures, hierarchies) used in all reports which feed data from
1372
+ a given semantic model.
1373
+
1374
+ Requirement: Reports must be in the PBIR format.
1375
+
1376
+ Parameters
1377
+ ----------
1378
+ dataset : str
1379
+ Name of the semantic model.
1380
+ workspace : str, default=None
1381
+ The Fabric workspace name.
1382
+ Defaults to None which resolves to the workspace of the attached lakehouse
1383
+ or if no lakehouse attached, resolves to the workspace of the notebook.
1384
+ extended: bool, default=False
1385
+ If True, adds an extra column called 'Valid Semantic Model Object' which identifies whether the semantic model object used
1386
+ in the report exists in the semantic model which feeds data to the report.
1387
+
1388
+ Returns
1389
+ -------
1390
+ pandas.DataFrame
1391
+ A pandas dataframe showing a list of semantic model objects (i.e. columns, measures, hierarchies) used in all reports which feed data from
1392
+ a given semantic model.
1393
+ """
1394
+
1395
+ from sempy_labs.report import ReportWrapper
1396
+ from sempy_labs.tom import connect_semantic_model
1397
+
1398
+ dfRO = pd.DataFrame(
1399
+ columns=[
1400
+ "Report Name",
1401
+ "Report Workspace Name",
1402
+ "Table Name",
1403
+ "Object Name",
1404
+ "Object Type",
1405
+ "Report Source",
1406
+ "Report Source Object",
1407
+ ]
1408
+ )
1409
+
1410
+ # Collect all reports which use the semantic model
1411
+ dfR = list_reports_using_semantic_model(dataset=dataset, workspace=workspace)
1412
+
1413
+ if len(dfR) == 0:
1414
+ return dfRO
1415
+
1416
+ for _, r in dfR.iterrows():
1417
+ report_name = r["Report Name"]
1418
+ report_workspace = r["Report Workspace Name"]
1419
+
1420
+ rpt = ReportWrapper(report=report_name, workspace=report_workspace)
1421
+ # Collect all semantic model objects used in the report
1422
+ dfRSO = rpt.list_semantic_model_objects()
1423
+ dfRSO["Report Name"] = report_name
1424
+ dfRSO["Report Workspace Name"] = report_workspace
1425
+ colName = "Report Name"
1426
+ dfRSO.insert(0, colName, dfRSO.pop(colName))
1427
+ colName = "Report Workspace Name"
1428
+ dfRSO.insert(1, colName, dfRSO.pop(colName))
1429
+
1430
+ dfRO = pd.concat([dfRO, dfRSO], ignore_index=True)
1431
+
1432
+ # Collect all semantic model objects
1433
+ if extended:
1434
+ with connect_semantic_model(
1435
+ dataset=dataset, readonly=True, workspace=workspace
1436
+ ) as tom:
1437
+ for index, row in dfRO.iterrows():
1438
+ object_type = row["Object Type"]
1439
+ if object_type == "Measure":
1440
+ dfRO.at[index, "Valid Semantic Model Object"] = any(
1441
+ o.Name == row["Object Name"] for o in tom.all_measures()
1442
+ )
1443
+ elif object_type == "Column":
1444
+ dfRO.at[index, "Valid Semantic Model Object"] = any(
1445
+ format_dax_object_name(c.Parent.Name, c.Name)
1446
+ == format_dax_object_name(row["Table Name"], row["Object Name"])
1447
+ for c in tom.all_columns()
1448
+ )
1449
+ elif object_type == "Hierarchy":
1450
+ dfRO.at[index, "Valid Semantic Model Object"] = any(
1451
+ format_dax_object_name(h.Parent.Name, h.Name)
1452
+ == format_dax_object_name(row["Table Name"], row["Object Name"])
1453
+ for h in tom.all_hierarchies()
1454
+ )
1455
+
1456
+ return dfRO
1457
+
1458
+
1459
+ def list_semantic_model_object_report_usage(
1460
+ dataset: str,
1461
+ workspace: Optional[str] = None,
1462
+ include_dependencies: bool = False,
1463
+ extended: bool = False,
1464
+ ) -> pd.DataFrame:
1465
+ """
1466
+ Shows a list of semantic model objects and how many times they are referenced in all reports which rely on this semantic model.
1467
+
1468
+ Requirement: Reports must be in the PBIR format.
1469
+
1470
+ Parameters
1471
+ ----------
1472
+ dataset : str
1473
+ Name of the semantic model.
1474
+ workspace : str, default=None
1475
+ The Fabric workspace name.
1476
+ Defaults to None which resolves to the workspace of the attached lakehouse
1477
+ or if no lakehouse attached, resolves to the workspace of the notebook.
1478
+ include_dependencies : bool, default=False
1479
+ If True, includes measure dependencies.
1480
+ extended: bool, default=False
1481
+ If True, adds columns 'Total Size', 'Data Size', 'Dictionary Size', 'Hierarchy Size' based on Vertipaq statistics.
1482
+
1483
+ Returns
1484
+ -------
1485
+ pandas.DataFrame
1486
+ A pandas dataframe showing a list of semantic model objects and how many times they are referenced in all reports which rely on this semantic model. By default, the dataframe
1487
+ is sorted descending by 'Report Usage Count'.
1488
+ """
1489
+
1490
+ from sempy_labs._model_dependencies import get_measure_dependencies
1491
+ from sempy_labs._helper_functions import format_dax_object_name
1492
+
1493
+ workspace = fabric.resolve_workspace_name(workspace)
1494
+
1495
+ dfR = list_report_semantic_model_objects(dataset=dataset, workspace=workspace)
1496
+ usage_column_name = "Report Usage Count"
1497
+
1498
+ if not include_dependencies:
1499
+ final_df = (
1500
+ dfR.groupby(["Table Name", "Object Name", "Object Type"])
1501
+ .size()
1502
+ .reset_index(name=usage_column_name)
1503
+ )
1504
+ else:
1505
+ df = pd.DataFrame(columns=["Table Name", "Object Name", "Object Type"])
1506
+ dep = get_measure_dependencies(dataset=dataset, workspace=workspace)
1507
+
1508
+ for i, r in dfR.iterrows():
1509
+ object_type = r["Object Type"]
1510
+ table_name = r["Table Name"]
1511
+ object_name = r["Object Name"]
1512
+ new_data = {
1513
+ "Table Name": table_name,
1514
+ "Object Name": object_name,
1515
+ "Object Type": object_type,
1516
+ }
1517
+ df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
1518
+ if object_type == "Measure":
1519
+ df_filt = dep[dep["Object Name"] == object_name][
1520
+ ["Referenced Table", "Referenced Object", "Referenced Object Type"]
1521
+ ]
1522
+ df_filt.rename(
1523
+ columns={
1524
+ "Referenced Table": "Table Name",
1525
+ "Referenced Object": "Object Name",
1526
+ "Referenced Object Type": "Object Type",
1527
+ },
1528
+ inplace=True,
1529
+ )
1530
+
1531
+ df = pd.concat([df, df_filt], ignore_index=True)
1532
+
1533
+ final_df = (
1534
+ df.groupby(["Table Name", "Object Name", "Object Type"])
1535
+ .size()
1536
+ .reset_index(name=usage_column_name)
1537
+ )
1538
+
1539
+ if extended:
1540
+ final_df["Object"] = format_dax_object_name(
1541
+ final_df["Table Name"], final_df["Object Name"]
1542
+ )
1543
+ dfC = fabric.list_columns(dataset=dataset, workspace=workspace, extended=True)
1544
+ dfC["Object"] = format_dax_object_name(dfC["Table Name"], dfC["Column Name"])
1545
+ final_df = pd.merge(
1546
+ final_df,
1547
+ dfC[
1548
+ [
1549
+ "Object",
1550
+ "Total Size",
1551
+ "Data Size",
1552
+ "Dictionary Size",
1553
+ "Hierarchy Size",
1554
+ ]
1555
+ ],
1556
+ on="Object",
1557
+ how="left",
1558
+ )
1559
+
1560
+ ext_int_cols = ["Total Size", "Data Size", "Dictionary Size", "Hierarchy Size"]
1561
+ final_df[ext_int_cols] = final_df[ext_int_cols].fillna(0).astype(int)
1562
+ final_df.drop("Object", axis=1, inplace=True)
1563
+
1564
+ int_cols = [usage_column_name]
1565
+ final_df[int_cols] = final_df[int_cols].astype(int)
1566
+
1567
+ final_df = final_df[final_df["Object Type"] != "Table"].sort_values(
1568
+ by=usage_column_name, ascending=False
1569
+ )
1570
+
1571
+ final_df.reset_index(drop=True, inplace=True)
1572
+
1573
+ return final_df