semantic-link-labs 0.12.8__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.
- semantic_link_labs-0.12.8.dist-info/METADATA +354 -0
- semantic_link_labs-0.12.8.dist-info/RECORD +243 -0
- semantic_link_labs-0.12.8.dist-info/WHEEL +5 -0
- semantic_link_labs-0.12.8.dist-info/licenses/LICENSE +21 -0
- semantic_link_labs-0.12.8.dist-info/top_level.txt +1 -0
- sempy_labs/__init__.py +606 -0
- sempy_labs/_a_lib_info.py +2 -0
- sempy_labs/_ai.py +437 -0
- sempy_labs/_authentication.py +264 -0
- sempy_labs/_bpa_translation/_model/_translations_am-ET.po +869 -0
- sempy_labs/_bpa_translation/_model/_translations_ar-AE.po +908 -0
- sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +968 -0
- sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +963 -0
- sempy_labs/_bpa_translation/_model/_translations_cs-CZ.po +943 -0
- sempy_labs/_bpa_translation/_model/_translations_da-DK.po +945 -0
- sempy_labs/_bpa_translation/_model/_translations_de-DE.po +988 -0
- sempy_labs/_bpa_translation/_model/_translations_el-GR.po +993 -0
- sempy_labs/_bpa_translation/_model/_translations_es-ES.po +971 -0
- sempy_labs/_bpa_translation/_model/_translations_fa-IR.po +933 -0
- sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +942 -0
- sempy_labs/_bpa_translation/_model/_translations_fr-FR.po +994 -0
- sempy_labs/_bpa_translation/_model/_translations_ga-IE.po +967 -0
- sempy_labs/_bpa_translation/_model/_translations_he-IL.po +902 -0
- sempy_labs/_bpa_translation/_model/_translations_hi-IN.po +944 -0
- sempy_labs/_bpa_translation/_model/_translations_hu-HU.po +963 -0
- sempy_labs/_bpa_translation/_model/_translations_id-ID.po +946 -0
- sempy_labs/_bpa_translation/_model/_translations_is-IS.po +939 -0
- sempy_labs/_bpa_translation/_model/_translations_it-IT.po +986 -0
- sempy_labs/_bpa_translation/_model/_translations_ja-JP.po +846 -0
- sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +839 -0
- sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +967 -0
- sempy_labs/_bpa_translation/_model/_translations_nl-NL.po +978 -0
- sempy_labs/_bpa_translation/_model/_translations_pl-PL.po +962 -0
- sempy_labs/_bpa_translation/_model/_translations_pt-BR.po +962 -0
- sempy_labs/_bpa_translation/_model/_translations_pt-PT.po +957 -0
- sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +968 -0
- sempy_labs/_bpa_translation/_model/_translations_ru-RU.po +964 -0
- sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +952 -0
- sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +950 -0
- sempy_labs/_bpa_translation/_model/_translations_sv-SE.po +942 -0
- sempy_labs/_bpa_translation/_model/_translations_ta-IN.po +976 -0
- sempy_labs/_bpa_translation/_model/_translations_te-IN.po +947 -0
- sempy_labs/_bpa_translation/_model/_translations_th-TH.po +924 -0
- sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +953 -0
- sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +961 -0
- sempy_labs/_bpa_translation/_model/_translations_zh-CN.po +804 -0
- sempy_labs/_bpa_translation/_model/_translations_zu-ZA.po +969 -0
- sempy_labs/_capacities.py +1198 -0
- sempy_labs/_capacity_migration.py +660 -0
- sempy_labs/_clear_cache.py +351 -0
- sempy_labs/_connections.py +610 -0
- sempy_labs/_dashboards.py +69 -0
- sempy_labs/_data_access_security.py +98 -0
- sempy_labs/_data_pipelines.py +162 -0
- sempy_labs/_dataflows.py +668 -0
- sempy_labs/_dax.py +501 -0
- sempy_labs/_daxformatter.py +80 -0
- sempy_labs/_delta_analyzer.py +467 -0
- sempy_labs/_delta_analyzer_history.py +301 -0
- sempy_labs/_dictionary_diffs.py +221 -0
- sempy_labs/_documentation.py +147 -0
- sempy_labs/_domains.py +51 -0
- sempy_labs/_eventhouses.py +182 -0
- sempy_labs/_external_data_shares.py +230 -0
- sempy_labs/_gateways.py +521 -0
- sempy_labs/_generate_semantic_model.py +521 -0
- sempy_labs/_get_connection_string.py +84 -0
- sempy_labs/_git.py +543 -0
- sempy_labs/_graphQL.py +90 -0
- sempy_labs/_helper_functions.py +2833 -0
- sempy_labs/_icons.py +149 -0
- sempy_labs/_job_scheduler.py +609 -0
- sempy_labs/_kql_databases.py +149 -0
- sempy_labs/_kql_querysets.py +124 -0
- sempy_labs/_kusto.py +137 -0
- sempy_labs/_labels.py +124 -0
- sempy_labs/_list_functions.py +1720 -0
- sempy_labs/_managed_private_endpoints.py +253 -0
- sempy_labs/_mirrored_databases.py +416 -0
- sempy_labs/_mirrored_warehouses.py +60 -0
- sempy_labs/_ml_experiments.py +113 -0
- sempy_labs/_model_auto_build.py +140 -0
- sempy_labs/_model_bpa.py +557 -0
- sempy_labs/_model_bpa_bulk.py +378 -0
- sempy_labs/_model_bpa_rules.py +859 -0
- sempy_labs/_model_dependencies.py +343 -0
- sempy_labs/_mounted_data_factories.py +123 -0
- sempy_labs/_notebooks.py +441 -0
- sempy_labs/_one_lake_integration.py +151 -0
- sempy_labs/_onelake.py +131 -0
- sempy_labs/_query_scale_out.py +433 -0
- sempy_labs/_refresh_semantic_model.py +435 -0
- sempy_labs/_semantic_models.py +468 -0
- sempy_labs/_spark.py +455 -0
- sempy_labs/_sql.py +241 -0
- sempy_labs/_sql_audit_settings.py +207 -0
- sempy_labs/_sql_endpoints.py +214 -0
- sempy_labs/_tags.py +201 -0
- sempy_labs/_translations.py +43 -0
- sempy_labs/_user_delegation_key.py +44 -0
- sempy_labs/_utils.py +79 -0
- sempy_labs/_vertipaq.py +1021 -0
- sempy_labs/_vpax.py +388 -0
- sempy_labs/_warehouses.py +234 -0
- sempy_labs/_workloads.py +140 -0
- sempy_labs/_workspace_identity.py +72 -0
- sempy_labs/_workspaces.py +595 -0
- sempy_labs/admin/__init__.py +170 -0
- sempy_labs/admin/_activities.py +167 -0
- sempy_labs/admin/_apps.py +145 -0
- sempy_labs/admin/_artifacts.py +65 -0
- sempy_labs/admin/_basic_functions.py +463 -0
- sempy_labs/admin/_capacities.py +508 -0
- sempy_labs/admin/_dataflows.py +45 -0
- sempy_labs/admin/_datasets.py +186 -0
- sempy_labs/admin/_domains.py +522 -0
- sempy_labs/admin/_external_data_share.py +100 -0
- sempy_labs/admin/_git.py +72 -0
- sempy_labs/admin/_items.py +265 -0
- sempy_labs/admin/_labels.py +211 -0
- sempy_labs/admin/_reports.py +241 -0
- sempy_labs/admin/_scanner.py +118 -0
- sempy_labs/admin/_shared.py +82 -0
- sempy_labs/admin/_sharing_links.py +110 -0
- sempy_labs/admin/_tags.py +131 -0
- sempy_labs/admin/_tenant.py +503 -0
- sempy_labs/admin/_tenant_keys.py +89 -0
- sempy_labs/admin/_users.py +140 -0
- sempy_labs/admin/_workspaces.py +236 -0
- sempy_labs/deployment_pipeline/__init__.py +23 -0
- sempy_labs/deployment_pipeline/_items.py +580 -0
- sempy_labs/directlake/__init__.py +57 -0
- sempy_labs/directlake/_autosync.py +58 -0
- sempy_labs/directlake/_directlake_schema_compare.py +120 -0
- sempy_labs/directlake/_directlake_schema_sync.py +161 -0
- sempy_labs/directlake/_dl_helper.py +274 -0
- sempy_labs/directlake/_generate_shared_expression.py +94 -0
- sempy_labs/directlake/_get_directlake_lakehouse.py +62 -0
- sempy_labs/directlake/_get_shared_expression.py +34 -0
- sempy_labs/directlake/_guardrails.py +96 -0
- sempy_labs/directlake/_list_directlake_model_calc_tables.py +70 -0
- sempy_labs/directlake/_show_unsupported_directlake_objects.py +90 -0
- sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +239 -0
- sempy_labs/directlake/_update_directlake_partition_entity.py +259 -0
- sempy_labs/directlake/_warm_cache.py +236 -0
- sempy_labs/dotnet_lib/dotnet.runtime.config.json +10 -0
- sempy_labs/environment/__init__.py +23 -0
- sempy_labs/environment/_items.py +212 -0
- sempy_labs/environment/_pubstage.py +223 -0
- sempy_labs/eventstream/__init__.py +37 -0
- sempy_labs/eventstream/_items.py +263 -0
- sempy_labs/eventstream/_topology.py +652 -0
- sempy_labs/graph/__init__.py +59 -0
- sempy_labs/graph/_groups.py +651 -0
- sempy_labs/graph/_sensitivity_labels.py +120 -0
- sempy_labs/graph/_teams.py +125 -0
- sempy_labs/graph/_user_licenses.py +96 -0
- sempy_labs/graph/_users.py +516 -0
- sempy_labs/graph_model/__init__.py +15 -0
- sempy_labs/graph_model/_background_jobs.py +63 -0
- sempy_labs/graph_model/_items.py +149 -0
- sempy_labs/lakehouse/__init__.py +67 -0
- sempy_labs/lakehouse/_blobs.py +247 -0
- sempy_labs/lakehouse/_get_lakehouse_columns.py +102 -0
- sempy_labs/lakehouse/_get_lakehouse_tables.py +274 -0
- sempy_labs/lakehouse/_helper.py +250 -0
- sempy_labs/lakehouse/_lakehouse.py +351 -0
- sempy_labs/lakehouse/_livy_sessions.py +143 -0
- sempy_labs/lakehouse/_materialized_lake_views.py +157 -0
- sempy_labs/lakehouse/_partitioning.py +165 -0
- sempy_labs/lakehouse/_schemas.py +217 -0
- sempy_labs/lakehouse/_shortcuts.py +440 -0
- sempy_labs/migration/__init__.py +35 -0
- sempy_labs/migration/_create_pqt_file.py +238 -0
- sempy_labs/migration/_direct_lake_to_import.py +105 -0
- sempy_labs/migration/_migrate_calctables_to_lakehouse.py +398 -0
- sempy_labs/migration/_migrate_calctables_to_semantic_model.py +148 -0
- sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +533 -0
- sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +172 -0
- sempy_labs/migration/_migration_validation.py +71 -0
- sempy_labs/migration/_refresh_calc_tables.py +131 -0
- sempy_labs/mirrored_azure_databricks_catalog/__init__.py +15 -0
- sempy_labs/mirrored_azure_databricks_catalog/_discover.py +213 -0
- sempy_labs/mirrored_azure_databricks_catalog/_refresh_catalog_metadata.py +45 -0
- sempy_labs/ml_model/__init__.py +23 -0
- sempy_labs/ml_model/_functions.py +427 -0
- sempy_labs/report/_BPAReportTemplate.json +232 -0
- sempy_labs/report/__init__.py +55 -0
- sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
- sempy_labs/report/_bpareporttemplate/.platform +11 -0
- sempy_labs/report/_bpareporttemplate/StaticResources/SharedResources/BaseThemes/CY24SU06.json +710 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/page.json +11 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/1b08bce3bebabb0a27a8/visual.json +191 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/2f22ddb70c301693c165/visual.json +438 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/3b1182230aa6c600b43a/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/58577ba6380c69891500/visual.json +576 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/a2a8fa5028b3b776c96c/visual.json +207 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/adfd47ef30652707b987/visual.json +506 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/b6a80ee459e716e170b1/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/ce3130a721c020cc3d81/visual.json +513 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/page.json +8 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/visuals/66e60dfb526437cd78d1/visual.json +112 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/page.json +11 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/07deb8bce824e1be37d7/visual.json +513 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0b1c68838818b32ad03b/visual.json +352 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0c171de9d2683d10b930/visual.json +37 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0efa01be0510e40a645e/visual.json +542 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/6bf2f0eb830ab53cc668/visual.json +221 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/88d8141cb8500b60030c/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/a753273590beed656a03/visual.json +576 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/b8fdc82cddd61ac447bc/visual.json +127 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/page.json +9 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/visuals/ce8532a7e25020271077/visual.json +38 -0
- sempy_labs/report/_bpareporttemplate/definition/pages/pages.json +10 -0
- sempy_labs/report/_bpareporttemplate/definition/report.json +176 -0
- sempy_labs/report/_bpareporttemplate/definition/version.json +4 -0
- sempy_labs/report/_bpareporttemplate/definition.pbir +14 -0
- sempy_labs/report/_download_report.py +76 -0
- sempy_labs/report/_export_report.py +257 -0
- sempy_labs/report/_generate_report.py +427 -0
- sempy_labs/report/_paginated.py +76 -0
- sempy_labs/report/_report_bpa.py +354 -0
- sempy_labs/report/_report_bpa_rules.py +115 -0
- sempy_labs/report/_report_functions.py +581 -0
- sempy_labs/report/_report_helper.py +227 -0
- sempy_labs/report/_report_list_functions.py +110 -0
- sempy_labs/report/_report_rebind.py +149 -0
- sempy_labs/report/_reportwrapper.py +3100 -0
- sempy_labs/report/_save_report.py +147 -0
- sempy_labs/snowflake_database/__init__.py +10 -0
- sempy_labs/snowflake_database/_items.py +105 -0
- sempy_labs/sql_database/__init__.py +21 -0
- sempy_labs/sql_database/_items.py +201 -0
- sempy_labs/sql_database/_mirroring.py +79 -0
- sempy_labs/theme/__init__.py +12 -0
- sempy_labs/theme/_org_themes.py +129 -0
- sempy_labs/tom/__init__.py +3 -0
- sempy_labs/tom/_model.py +5977 -0
- sempy_labs/variable_library/__init__.py +19 -0
- sempy_labs/variable_library/_functions.py +403 -0
- sempy_labs/warehouse/__init__.py +28 -0
- sempy_labs/warehouse/_items.py +234 -0
- sempy_labs/warehouse/_restore_points.py +309 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import sempy_labs._icons as icons
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
vis_type_mapping = {
|
|
6
|
+
"barChart": "Bar chart",
|
|
7
|
+
"columnChart": "Column chart",
|
|
8
|
+
"clusteredBarChart": "Clustered bar chart",
|
|
9
|
+
"clusteredColumnChart": "Clustered column chart",
|
|
10
|
+
"hundredPercentStackedBarChart": "100% Stacked bar chart",
|
|
11
|
+
"hundredPercentStackedColumnChart": "100% Stacked column chart",
|
|
12
|
+
"lineChart": "Line chart",
|
|
13
|
+
"areaChart": "Area chart",
|
|
14
|
+
"stackedAreaChart": "Stacked area chart",
|
|
15
|
+
"lineStackedColumnComboChart": "Line and stacked column chart",
|
|
16
|
+
"lineClusteredColumnComboChart": "Line and clustered column chart",
|
|
17
|
+
"ribbonChart": "Ribbon chart",
|
|
18
|
+
"waterfallChart": "Waterfall chart",
|
|
19
|
+
"funnel": "Funnel chart",
|
|
20
|
+
"scatterChart": "Scatter chart",
|
|
21
|
+
"pieChart": "Pie chart",
|
|
22
|
+
"donutChart": "Donut chart",
|
|
23
|
+
"treemap": "Treemap",
|
|
24
|
+
"map": "Map",
|
|
25
|
+
"filledMap": "Filled map",
|
|
26
|
+
"shapeMap": "Shape map",
|
|
27
|
+
"azureMap": "Azure map",
|
|
28
|
+
"gauge": "Gauge",
|
|
29
|
+
"card": "Card",
|
|
30
|
+
"multiRowCard": "Multi-row card",
|
|
31
|
+
"kpi": "KPI",
|
|
32
|
+
"slicer": "Slicer",
|
|
33
|
+
"tableEx": "Table",
|
|
34
|
+
"pivotTable": "Matrix",
|
|
35
|
+
"scriptVisual": "R script visual",
|
|
36
|
+
"pythonVisual": "Python visual",
|
|
37
|
+
"keyDriversVisual": "Key influencers",
|
|
38
|
+
"decompositionTreeVisual": "Decomposition tree",
|
|
39
|
+
"qnaVisual": "Q&A",
|
|
40
|
+
"aiNarratives": "Narrative",
|
|
41
|
+
"scorecard": "Goals (Preview)",
|
|
42
|
+
"rdlVisual": "Paginated report",
|
|
43
|
+
"cardVisual": "Card (new)",
|
|
44
|
+
"actionButton": "Button",
|
|
45
|
+
"bookmarkNavigator": "Bookmark navigator",
|
|
46
|
+
"image": "Image",
|
|
47
|
+
"textbox": "Textbox",
|
|
48
|
+
"pageNavigator": "Page navigator",
|
|
49
|
+
"shape": "Shape",
|
|
50
|
+
"Group": "Group",
|
|
51
|
+
"listSlicer": "List Slicer",
|
|
52
|
+
"advancedSlicerVisual": "Button Slicer",
|
|
53
|
+
"FlowVisual_C29F1DCC_81F5_4973_94AD_0517D44CC06A": "Power Automate for Power BI",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def generate_visual_file_path(page_file_path: str, visual_id: str) -> str:
|
|
58
|
+
|
|
59
|
+
return page_file_path.split("/page.json")[0] + f"/visuals/{visual_id}.json"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def resolve_visual_type(visual_type: str) -> str:
|
|
63
|
+
vt_lower = visual_type.lower()
|
|
64
|
+
|
|
65
|
+
vis_map_lower = {k.lower(): v for k, v in vis_type_mapping.items()}
|
|
66
|
+
flipped_lower = {v.lower(): k for k, v in vis_type_mapping.items()}
|
|
67
|
+
|
|
68
|
+
if vt_lower in vis_map_lower:
|
|
69
|
+
resolved = vis_map_lower.get(vt_lower)
|
|
70
|
+
elif vt_lower in flipped_lower:
|
|
71
|
+
resolved = flipped_lower.get(vt_lower)
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError(f"{icons.red_dot} Unknown visual type: {visual_type}")
|
|
74
|
+
|
|
75
|
+
return resolved
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
page_type_mapping = {
|
|
79
|
+
(320, 240): "Tooltip",
|
|
80
|
+
(816, 1056): "Letter",
|
|
81
|
+
(960, 720): "4:3",
|
|
82
|
+
(1280, 720): "16:9",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
page_types = ["Tooltip", "Letter", "4:3", "16:9"]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def populate_custom_visual_display_names():
|
|
89
|
+
|
|
90
|
+
url = "https://catalogapi.azure.com/offers?api-version=2018-08-01-beta&storefront=appsource&$filter=offerType+eq+%27PowerBIVisuals%27"
|
|
91
|
+
|
|
92
|
+
def fetch_all_pages(start_url):
|
|
93
|
+
combined_json = {}
|
|
94
|
+
current_url = start_url
|
|
95
|
+
|
|
96
|
+
while current_url:
|
|
97
|
+
# Send GET request to the current page URL
|
|
98
|
+
response = requests.get(current_url)
|
|
99
|
+
|
|
100
|
+
if response.status_code == 200:
|
|
101
|
+
data = response.json()
|
|
102
|
+
# Merge the current page JSON into the combined JSON
|
|
103
|
+
for key, value in data.items():
|
|
104
|
+
if key not in combined_json:
|
|
105
|
+
combined_json[key] = value
|
|
106
|
+
else:
|
|
107
|
+
# If the key already exists and is a list, extend it
|
|
108
|
+
if isinstance(value, list):
|
|
109
|
+
combined_json[key].extend(value)
|
|
110
|
+
# For other types (non-lists), update the value
|
|
111
|
+
else:
|
|
112
|
+
combined_json[key] = value
|
|
113
|
+
|
|
114
|
+
# Get the next page link if it exists
|
|
115
|
+
current_url = data.get("nextPageLink")
|
|
116
|
+
else:
|
|
117
|
+
print(f"Error fetching page: {response.status_code}")
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
return combined_json
|
|
121
|
+
|
|
122
|
+
cvJson = fetch_all_pages(url)
|
|
123
|
+
|
|
124
|
+
for i in cvJson.get("items", []):
|
|
125
|
+
vizId = i.get("powerBIVisualId")
|
|
126
|
+
displayName = i.get("displayName")
|
|
127
|
+
vis_type_mapping[vizId] = displayName
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def find_entity_property_pairs(data, result=None, keys_path=None):
|
|
131
|
+
|
|
132
|
+
if result is None:
|
|
133
|
+
result = {}
|
|
134
|
+
if keys_path is None:
|
|
135
|
+
keys_path = []
|
|
136
|
+
|
|
137
|
+
if isinstance(data, dict):
|
|
138
|
+
expression = data.get("Expression", {})
|
|
139
|
+
source_ref = (
|
|
140
|
+
expression.get("SourceRef", {}) if isinstance(expression, dict) else {}
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if (
|
|
144
|
+
isinstance(source_ref, dict)
|
|
145
|
+
and "Entity" in source_ref
|
|
146
|
+
and "Property" in data
|
|
147
|
+
):
|
|
148
|
+
entity = source_ref.get("Entity", "")
|
|
149
|
+
property_value = data.get("Property", "")
|
|
150
|
+
|
|
151
|
+
object_type = (
|
|
152
|
+
keys_path[-1].replace("HierarchyLevel", "Hierarchy")
|
|
153
|
+
if keys_path
|
|
154
|
+
else "Unknown"
|
|
155
|
+
)
|
|
156
|
+
result[property_value] = (entity, object_type)
|
|
157
|
+
if keys_path:
|
|
158
|
+
keys_path.pop()
|
|
159
|
+
|
|
160
|
+
# Recursively search the rest of the dictionary
|
|
161
|
+
for key, value in data.items():
|
|
162
|
+
keys_path.append(key)
|
|
163
|
+
find_entity_property_pairs(value, result, keys_path)
|
|
164
|
+
|
|
165
|
+
elif isinstance(data, list):
|
|
166
|
+
for item in data:
|
|
167
|
+
find_entity_property_pairs(item, result, keys_path)
|
|
168
|
+
|
|
169
|
+
return result
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _get_agg_type_mapping() -> dict:
|
|
173
|
+
"""
|
|
174
|
+
This function extracts a mapping dictionary like this:
|
|
175
|
+
{
|
|
176
|
+
"0": "Sum",
|
|
177
|
+
"1": "Average",
|
|
178
|
+
"2": "Distinct count",
|
|
179
|
+
}
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
schema_url = "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/semanticQuery/1.2.0/schema.json"
|
|
183
|
+
response = requests.get(schema_url)
|
|
184
|
+
schema = response.json()
|
|
185
|
+
aggtypes_schema = schema.get("definitions", {}).get("QueryAggregateFunction", {})
|
|
186
|
+
|
|
187
|
+
agg_type_map = {}
|
|
188
|
+
agg_type_map = {
|
|
189
|
+
a.get("const"): a.get("description")
|
|
190
|
+
for a in aggtypes_schema.get("anyOf", [])
|
|
191
|
+
if "const" in a and "description" in a
|
|
192
|
+
}
|
|
193
|
+
agg_type_map["-1"] = "Unknown"
|
|
194
|
+
|
|
195
|
+
return agg_type_map
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _get_expression(expr_json, agg_type_map):
|
|
199
|
+
|
|
200
|
+
expr_type = list(expr_json.keys())[0]
|
|
201
|
+
if expr_type == "Literal":
|
|
202
|
+
expr = expr_json.get("Literal", {}).get("Value")[1:-1]
|
|
203
|
+
elif expr_type == "Aggregation":
|
|
204
|
+
entity = (
|
|
205
|
+
expr_json.get("Aggregation", {})
|
|
206
|
+
.get("Expression", {})
|
|
207
|
+
.get("Column", {})
|
|
208
|
+
.get("Expression", {})
|
|
209
|
+
.get("SourceRef", {})
|
|
210
|
+
.get("Entity", "Unknown")
|
|
211
|
+
)
|
|
212
|
+
column = (
|
|
213
|
+
expr_json.get("Aggregation", {})
|
|
214
|
+
.get("Expression", {})
|
|
215
|
+
.get("Column", {})
|
|
216
|
+
.get("Property", "Unknown")
|
|
217
|
+
)
|
|
218
|
+
function_id = expr_json.get("Aggregation", {}).get("Function", "-1")
|
|
219
|
+
function = agg_type_map.get(function_id)
|
|
220
|
+
expr = f"{function}('{entity}'[{column}])"
|
|
221
|
+
elif expr_type == "Measure":
|
|
222
|
+
measure = expr_json.get("Measure", {}).get("Property", "Unknown")
|
|
223
|
+
expr = f"[{measure}]"
|
|
224
|
+
else:
|
|
225
|
+
expr = "Unknown"
|
|
226
|
+
|
|
227
|
+
return expr
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import sempy.fabric as fabric
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sempy_labs._helper_functions import (
|
|
5
|
+
format_dax_object_name,
|
|
6
|
+
resolve_workspace_name_and_id,
|
|
7
|
+
resolve_dataset_name_and_id,
|
|
8
|
+
)
|
|
9
|
+
from sempy_labs.report._reportwrapper import ReportWrapper
|
|
10
|
+
from sempy_labs._list_functions import list_reports_using_semantic_model
|
|
11
|
+
from uuid import UUID
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def list_unused_objects_in_reports(
|
|
15
|
+
dataset: str | UUID, workspace: Optional[str | UUID] = None
|
|
16
|
+
) -> pd.DataFrame:
|
|
17
|
+
"""
|
|
18
|
+
Shows a list of all columns in the semantic model which are not used in any related Power BI reports (including dependencies).
|
|
19
|
+
Note: As with all functions which rely on the ReportWrapper, this function requires the report to be in the 'PBIR' format.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
dataset : str | uuid.UUID
|
|
24
|
+
Name or ID of the semantic model.
|
|
25
|
+
workspace : str | uuid.UUID, default=None
|
|
26
|
+
The Fabric workspace name or ID.
|
|
27
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
28
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
pandas.DataFrame
|
|
33
|
+
A pandas dataframe showing a list of all columns in the semantic model which are not used in any related Power BI reports (including dependencies).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# TODO: what about relationships/RLS?
|
|
37
|
+
|
|
38
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
39
|
+
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
40
|
+
|
|
41
|
+
fabric.refresh_tom_cache(workspace=workspace)
|
|
42
|
+
|
|
43
|
+
dfR = _list_all_report_semantic_model_objects(
|
|
44
|
+
dataset=dataset_id, workspace=workspace_id
|
|
45
|
+
)
|
|
46
|
+
dfR_filt = (
|
|
47
|
+
dfR[dfR["Object Type"] == "Column"][["Table Name", "Object Name"]]
|
|
48
|
+
.drop_duplicates()
|
|
49
|
+
.reset_index(drop=True)
|
|
50
|
+
)
|
|
51
|
+
dfR_filt["Column Object"] = format_dax_object_name(
|
|
52
|
+
dfR_filt["Table Name"], dfR_filt["Object Name"]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
dfC = fabric.list_columns(dataset=dataset_id, workspace=workspace_id)
|
|
56
|
+
dfC["Column Object"] = format_dax_object_name(dfC["Table Name"], dfC["Column Name"])
|
|
57
|
+
|
|
58
|
+
df = dfC[~(dfC["Column Object"].isin(dfR_filt["Column Object"].values))]
|
|
59
|
+
df = df.drop("Column Object", axis=1)
|
|
60
|
+
|
|
61
|
+
return df
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _list_all_report_semantic_model_objects(
|
|
65
|
+
dataset: str | UUID, workspace: Optional[str | UUID] = None
|
|
66
|
+
) -> pd.DataFrame:
|
|
67
|
+
"""
|
|
68
|
+
Shows a unique list of all semantic model objects (columns, measures, hierarchies) which are used in all reports which leverage the semantic model.
|
|
69
|
+
Note: As with all functions which rely on the ReportWrapper, this function requires the report to be in the 'PBIR' format.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
dataset : str | uuid.UUID
|
|
74
|
+
Name or ID of the semantic model.
|
|
75
|
+
workspace : str | uuid.UUID, default=None
|
|
76
|
+
The Fabric workspace name or ID.
|
|
77
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
78
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
pandas.DataFrame
|
|
83
|
+
A pandas dataframe.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
87
|
+
(dataset_name, dataset_id) = resolve_dataset_name_and_id(dataset, workspace_id)
|
|
88
|
+
|
|
89
|
+
dfR = list_reports_using_semantic_model(dataset=dataset_id, workspace=workspace_id)
|
|
90
|
+
dfs = []
|
|
91
|
+
|
|
92
|
+
for _, r in dfR.iterrows():
|
|
93
|
+
report_name = r["Report Name"]
|
|
94
|
+
report_workspace = r["Report Workspace Name"]
|
|
95
|
+
|
|
96
|
+
rpt = ReportWrapper(report=report_name, workspace=report_workspace)
|
|
97
|
+
|
|
98
|
+
new_data = rpt._list_all_semantic_model_objects()
|
|
99
|
+
new_data["Report Name"] = report_name
|
|
100
|
+
new_data["Report Workspace"] = report_workspace
|
|
101
|
+
dfs.append(new_data)
|
|
102
|
+
|
|
103
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
104
|
+
|
|
105
|
+
colName = "Report Name"
|
|
106
|
+
df.insert(2, colName, df.pop(colName))
|
|
107
|
+
colName = "Report Workspace"
|
|
108
|
+
df.insert(3, colName, df.pop(colName))
|
|
109
|
+
|
|
110
|
+
return df
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from sempy_labs._helper_functions import (
|
|
2
|
+
resolve_item_id,
|
|
3
|
+
resolve_workspace_id,
|
|
4
|
+
resolve_workspace_name_and_id,
|
|
5
|
+
resolve_item_name_and_id,
|
|
6
|
+
_base_api,
|
|
7
|
+
)
|
|
8
|
+
from typing import Optional, List
|
|
9
|
+
from sempy._utils._log import log
|
|
10
|
+
import sempy_labs._icons as icons
|
|
11
|
+
from uuid import UUID
|
|
12
|
+
import sempy.fabric as fabric
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@log
|
|
16
|
+
def report_rebind(
|
|
17
|
+
report: str | UUID | List[str | UUID],
|
|
18
|
+
dataset: str | UUID,
|
|
19
|
+
report_workspace: Optional[str | UUID] = None,
|
|
20
|
+
dataset_workspace: Optional[str | UUID] = None,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Rebinds a report to a semantic model.
|
|
24
|
+
|
|
25
|
+
This is a wrapper function for the following API: `Reports - Rebind Report In Group <https://learn.microsoft.com/rest/api/power-bi/reports/rebind-report-in-group>`_.
|
|
26
|
+
|
|
27
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
report : str | uuid.UUID | List[str | uuid.UUID]
|
|
32
|
+
Name(s) or ID(s) of the Power BI report(s).
|
|
33
|
+
dataset : str | uuid.UUID
|
|
34
|
+
Name or ID of the semantic model.
|
|
35
|
+
report_workspace : str | uuid.UUID, default=None
|
|
36
|
+
The name or ID of the Fabric workspace in which the report resides.
|
|
37
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
38
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
39
|
+
dataset_workspace : str | uuid.UUID, default=None
|
|
40
|
+
The name or ID of the Fabric workspace in which the semantic model resides.
|
|
41
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
42
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
(report_workspace_name, report_workspace_id) = resolve_workspace_name_and_id(
|
|
46
|
+
report_workspace
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if dataset_workspace is None:
|
|
50
|
+
dataset_workspace = report_workspace_name
|
|
51
|
+
|
|
52
|
+
(dataset_workspace_name, dataset_workspace_id) = resolve_workspace_name_and_id(
|
|
53
|
+
dataset_workspace
|
|
54
|
+
)
|
|
55
|
+
if isinstance(report, str):
|
|
56
|
+
report = [report]
|
|
57
|
+
|
|
58
|
+
for rpt in report:
|
|
59
|
+
(report_name, report_id) = resolve_item_name_and_id(
|
|
60
|
+
item=rpt, type="Report", workspace=report_workspace_id
|
|
61
|
+
)
|
|
62
|
+
(dataset_name, dataset_id) = resolve_item_name_and_id(
|
|
63
|
+
item=dataset, type="SemanticModel", workspace=dataset_workspace
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
payload = {"datasetId": dataset_id}
|
|
67
|
+
|
|
68
|
+
_base_api(
|
|
69
|
+
request=f"v1.0/myorg/groups/{report_workspace_id}/reports/{report_id}/Rebind",
|
|
70
|
+
method="post",
|
|
71
|
+
payload=payload,
|
|
72
|
+
client="fabric_sp",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
print(
|
|
76
|
+
f"{icons.green_dot} The '{report_name}' report within the '{report_workspace_name}' workspace has been successfully rebinded to the '{dataset_name}' semantic model within the '{dataset_workspace_name}' workspace."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@log
|
|
81
|
+
def report_rebind_all(
|
|
82
|
+
dataset: str | UUID,
|
|
83
|
+
new_dataset: str | UUID,
|
|
84
|
+
dataset_workspace: Optional[str | UUID] = None,
|
|
85
|
+
new_dataset_workspace: Optional[str | UUID] = None,
|
|
86
|
+
report_workspace: Optional[str | UUID | List[str | UUID]] = None,
|
|
87
|
+
):
|
|
88
|
+
"""
|
|
89
|
+
Rebinds all reports across the provided report workspaces which are bound to a specific semantic model to a new semantic model.
|
|
90
|
+
|
|
91
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
dataset : str | uuid.UUID
|
|
96
|
+
Name of the semantic model currently binded to the reports.
|
|
97
|
+
new_dataset : str | uuid.UUID
|
|
98
|
+
Name of the semantic model to rebind to the reports.
|
|
99
|
+
dataset_workspace : str | uuid.UUID, default=None
|
|
100
|
+
The name of the Fabric workspace in which the original semantic model resides.
|
|
101
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
102
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
103
|
+
new_dataset_workspace : str | uuid.UUID, default=None
|
|
104
|
+
The name of the Fabric workspace in which the new semantic model resides.
|
|
105
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
106
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
107
|
+
report_workspace : str | uuid.UUID | List[str | uuid.UUID], default=None
|
|
108
|
+
The name(s) or IDs of the Fabric workspace(s) in which the report(s) reside(s).
|
|
109
|
+
Defaults to None which finds all reports in all workspaces which use the semantic model and rebinds them to
|
|
110
|
+
the new semantic model.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
(dataset_name, dataset_id) = resolve_item_name_and_id(
|
|
114
|
+
item=dataset, type="SemanticModel", workspace=dataset_workspace
|
|
115
|
+
)
|
|
116
|
+
new_dataset_id = resolve_item_id(
|
|
117
|
+
item=new_dataset, type="SemanticModel", workspace=new_dataset_workspace
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if dataset_id == new_dataset_id:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
f"{icons.red_dot} The 'dataset' and 'new_dataset' parameters are both set to the same semantic model within the same workspace. These parameters must be set to different values."
|
|
123
|
+
)
|
|
124
|
+
dataset_workspace_id = resolve_workspace_id(workspace=dataset_workspace)
|
|
125
|
+
|
|
126
|
+
if isinstance(report_workspace, str) or report_workspace is None:
|
|
127
|
+
report_workspace = [report_workspace]
|
|
128
|
+
|
|
129
|
+
for w in report_workspace:
|
|
130
|
+
dfR = fabric.list_reports(workspace=w)
|
|
131
|
+
dfR_filt = dfR[
|
|
132
|
+
(dfR["Dataset ID"] == dataset_id)
|
|
133
|
+
& (dfR["Dataset Workspace Id"] == dataset_workspace_id)
|
|
134
|
+
]
|
|
135
|
+
if dfR_filt.empty:
|
|
136
|
+
(wksp_name, _) = resolve_workspace_name_and_id(workspace=w)
|
|
137
|
+
print(
|
|
138
|
+
f"{icons.info} No reports found for the '{dataset_name}' semantic model within the '{wksp_name}' workspace."
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
# Rebind reports to new dataset
|
|
142
|
+
for _, r in dfR_filt.iterrows():
|
|
143
|
+
rpt_name = r["Name"]
|
|
144
|
+
report_rebind(
|
|
145
|
+
report=rpt_name,
|
|
146
|
+
dataset=new_dataset,
|
|
147
|
+
report_workspace=w,
|
|
148
|
+
dataset_workspace=new_dataset_workspace,
|
|
149
|
+
)
|