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
sempy_labs/_dataflows.py
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from sempy_labs._helper_functions import (
|
|
3
|
+
resolve_workspace_name_and_id,
|
|
4
|
+
_is_valid_uuid,
|
|
5
|
+
_update_dataframe_datatypes,
|
|
6
|
+
_base_api,
|
|
7
|
+
_create_dataframe,
|
|
8
|
+
resolve_workspace_name,
|
|
9
|
+
resolve_workspace_id,
|
|
10
|
+
_decode_b64,
|
|
11
|
+
_conv_b64,
|
|
12
|
+
get_jsonpath_value,
|
|
13
|
+
resolve_item_id,
|
|
14
|
+
)
|
|
15
|
+
from typing import Optional, Tuple
|
|
16
|
+
import sempy_labs._icons as icons
|
|
17
|
+
from uuid import UUID
|
|
18
|
+
from jsonpath_ng.ext import parse
|
|
19
|
+
import json
|
|
20
|
+
from sempy._utils._log import log
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@log
|
|
24
|
+
def list_dataflows(workspace: Optional[str | UUID] = None):
|
|
25
|
+
"""
|
|
26
|
+
Shows a list of all dataflows which exist within a workspace.
|
|
27
|
+
|
|
28
|
+
This is a wrapper function for the following API: `Items - List Dataflows <https://learn.microsoft.com/rest/api/fabric/dataflow/items/list-dataflows>`_.
|
|
29
|
+
|
|
30
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
workspace : str | uuid.UUID, default=None
|
|
35
|
+
The Fabric workspace name or ID.
|
|
36
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
37
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
pandas.DataFrame
|
|
42
|
+
A pandas dataframe showing the dataflows which exist within a workspace.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
46
|
+
|
|
47
|
+
columns = {
|
|
48
|
+
"Dataflow Id": "string",
|
|
49
|
+
"Dataflow Name": "string",
|
|
50
|
+
"Description": "string",
|
|
51
|
+
"Configured By": "string",
|
|
52
|
+
"Users": "string",
|
|
53
|
+
"Generation": "string",
|
|
54
|
+
}
|
|
55
|
+
df = _create_dataframe(columns=columns)
|
|
56
|
+
|
|
57
|
+
response = _base_api(
|
|
58
|
+
request=f"/v1.0/myorg/groups/{workspace_id}/dataflows", client="fabric_sp"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
rows = []
|
|
62
|
+
for v in response.json().get("value", []):
|
|
63
|
+
gen = v.get("generation")
|
|
64
|
+
rows.append(
|
|
65
|
+
{
|
|
66
|
+
"Dataflow Id": v.get("objectId"),
|
|
67
|
+
"Dataflow Name": v.get("name"),
|
|
68
|
+
"Description": "",
|
|
69
|
+
"Configured By": v.get("configuredBy"),
|
|
70
|
+
"Users": ", ".join(v.get("users", [])),
|
|
71
|
+
"Generation": "Gen2" if gen == 2 else "Gen1",
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
responses = _base_api(
|
|
76
|
+
request=f"/v1/workspaces/{workspace_id}/dataflows",
|
|
77
|
+
client="fabric_sp",
|
|
78
|
+
uses_pagination=True,
|
|
79
|
+
)
|
|
80
|
+
for r in responses:
|
|
81
|
+
for v in r.get("value", []):
|
|
82
|
+
gen = v.get("generation")
|
|
83
|
+
rows.append(
|
|
84
|
+
{
|
|
85
|
+
"Dataflow Id": v.get("id"),
|
|
86
|
+
"Dataflow Name": v.get("displayName"),
|
|
87
|
+
"Description": v.get("description"),
|
|
88
|
+
"Configured By": "",
|
|
89
|
+
"Users": "",
|
|
90
|
+
"Generation": "Gen2 CI/CD",
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if rows:
|
|
95
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
96
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
97
|
+
|
|
98
|
+
return df
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@log
|
|
102
|
+
def assign_workspace_to_dataflow_storage(
|
|
103
|
+
dataflow_storage_account: str, workspace: Optional[str | UUID] = None
|
|
104
|
+
):
|
|
105
|
+
"""
|
|
106
|
+
Assigns a dataflow storage account to a workspace.
|
|
107
|
+
|
|
108
|
+
This is a wrapper function for the following API: `Dataflow Storage Accounts - Groups AssignToDataflowStorage <https://learn.microsoft.com/rest/api/power-bi/dataflow-storage-accounts/groups-assign-to-dataflow-storage>`_.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
dataflow_storage_account : str
|
|
113
|
+
The name of the dataflow storage account.
|
|
114
|
+
workspace : str | uuid.UUID, default=None
|
|
115
|
+
The name or ID of the workspace.
|
|
116
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
117
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
121
|
+
|
|
122
|
+
df = list_dataflow_storage_accounts()
|
|
123
|
+
df_filt = df[df["Dataflow Storage Account Name"] == dataflow_storage_account]
|
|
124
|
+
|
|
125
|
+
if len(df_filt) == 0:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"{icons.red_dot} The '{dataflow_storage_account}' does not exist."
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
dataflow_storage_id = df_filt["Dataflow Storage Account ID"].iloc[0]
|
|
131
|
+
payload = {"dataflowStorageId": dataflow_storage_id}
|
|
132
|
+
|
|
133
|
+
_base_api(
|
|
134
|
+
request=f"/v1.0/myorg/groups/{workspace_id}/AssignToDataflowStorage",
|
|
135
|
+
method="post",
|
|
136
|
+
payload=payload,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
print(
|
|
140
|
+
f"{icons.green_dot} The '{dataflow_storage_account}' dataflow storage account has been assigned to the '{workspace_name}' workspacce."
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@log
|
|
145
|
+
def list_dataflow_storage_accounts() -> pd.DataFrame:
|
|
146
|
+
"""
|
|
147
|
+
Shows the accessible dataflow storage accounts.
|
|
148
|
+
|
|
149
|
+
This is a wrapper function for the following API: `Dataflow Storage Accounts - Get Dataflow Storage Accounts <https://learn.microsoft.com/rest/api/power-bi/dataflow-storage-accounts/get-dataflow-storage-accounts>`_.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
pandas.DataFrame
|
|
154
|
+
A pandas dataframe showing the accessible dataflow storage accounts.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
columns = {
|
|
158
|
+
"Dataflow Storage Account ID": "string",
|
|
159
|
+
"Dataflow Storage Account Name": "string",
|
|
160
|
+
"Enabled": "bool",
|
|
161
|
+
}
|
|
162
|
+
df = _create_dataframe(columns=columns)
|
|
163
|
+
|
|
164
|
+
response = _base_api(request="/v1.0/myorg/dataflowStorageAccounts")
|
|
165
|
+
|
|
166
|
+
rows = []
|
|
167
|
+
for v in response.json().get("value", []):
|
|
168
|
+
rows.append(
|
|
169
|
+
{
|
|
170
|
+
"Dataflow Storage Account ID": v.get("id"),
|
|
171
|
+
"Dataflow Storage Account Name": v.get("name"),
|
|
172
|
+
"Enabled": v.get("isEnabled"),
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if rows:
|
|
177
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
178
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
179
|
+
|
|
180
|
+
return df
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@log
|
|
184
|
+
def list_upstream_dataflows(
|
|
185
|
+
dataflow: str | UUID, workspace: Optional[str | UUID] = None
|
|
186
|
+
) -> pd.DataFrame:
|
|
187
|
+
"""
|
|
188
|
+
Shows a list of upstream dataflows for the specified dataflow.
|
|
189
|
+
|
|
190
|
+
This is a wrapper function for the following API: `Dataflows - Get Upstream Dataflows In Group <https://learn.microsoft.com/rest/api/power-bi/dataflows/get-upstream-dataflows-in-group>`_.
|
|
191
|
+
|
|
192
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
dataflow : str | uuid.UUID
|
|
197
|
+
Name or UUID of the dataflow.
|
|
198
|
+
workspace : str | uuid.UUID, default=None
|
|
199
|
+
The Fabric workspace name or ID.
|
|
200
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
201
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
202
|
+
|
|
203
|
+
Returns
|
|
204
|
+
-------
|
|
205
|
+
pandas.DataFrame
|
|
206
|
+
A pandas dataframe showing a list of upstream dataflows for the specified dataflow.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
210
|
+
(dataflow_name, dataflow_id, dataflow_generation) = (
|
|
211
|
+
_resolve_dataflow_name_and_id_and_generation(
|
|
212
|
+
dataflow=dataflow, workspace=workspace_id
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
columns = {
|
|
217
|
+
"Dataflow Name": "string",
|
|
218
|
+
"Dataflow Id": "string",
|
|
219
|
+
"Workspace Name": "string",
|
|
220
|
+
"Workspace Id": "string",
|
|
221
|
+
"Upstream Dataflow Name": "string",
|
|
222
|
+
"Upstream Dataflow Id": "string",
|
|
223
|
+
"Upstream Workspace Name": "string",
|
|
224
|
+
"Upstream Workspace Id": "string",
|
|
225
|
+
}
|
|
226
|
+
df = _create_dataframe(columns=columns)
|
|
227
|
+
|
|
228
|
+
def collect_upstreams(dataflow_id, dataflow_name, workspace_id, workspace_name):
|
|
229
|
+
response = _base_api(
|
|
230
|
+
request=f"/v1.0/myorg/groups/{workspace_id}/dataflows/{dataflow_id}/upstreamDataflows",
|
|
231
|
+
client="fabric_sp",
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
values = response.json().get("value", [])
|
|
235
|
+
for v in values:
|
|
236
|
+
tgt_dataflow_id = v.get("targetDataflowId")
|
|
237
|
+
tgt_workspace_id = v.get("groupId")
|
|
238
|
+
tgt_workspace_name = resolve_workspace_name(workspace_id=tgt_workspace_id)
|
|
239
|
+
(tgt_dataflow_name, _, _) = _resolve_dataflow_name_and_id_and_generation(
|
|
240
|
+
dataflow=tgt_dataflow_id, workspace=tgt_workspace_id
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
df.loc[len(df)] = {
|
|
244
|
+
"Dataflow Name": dataflow_name,
|
|
245
|
+
"Dataflow Id": dataflow_id,
|
|
246
|
+
"Workspace Name": workspace_name,
|
|
247
|
+
"Workspace Id": workspace_id,
|
|
248
|
+
"Upstream Dataflow Name": tgt_dataflow_name,
|
|
249
|
+
"Upstream Dataflow Id": tgt_dataflow_id,
|
|
250
|
+
"Upstream Workspace Name": tgt_workspace_name,
|
|
251
|
+
"Upstream Workspace Id": tgt_workspace_id,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
collect_upstreams(
|
|
255
|
+
tgt_dataflow_id,
|
|
256
|
+
tgt_dataflow_name,
|
|
257
|
+
tgt_workspace_id,
|
|
258
|
+
tgt_workspace_name,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
collect_upstreams(dataflow_id, dataflow_name, workspace_id, workspace_name)
|
|
262
|
+
|
|
263
|
+
return df
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@log
|
|
267
|
+
def _resolve_dataflow_name_and_id_and_generation(
|
|
268
|
+
dataflow: str | UUID, workspace: Optional[str | UUID] = None
|
|
269
|
+
) -> Tuple[str, UUID, str]:
|
|
270
|
+
|
|
271
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
272
|
+
|
|
273
|
+
dfD = list_dataflows(workspace=workspace_id)
|
|
274
|
+
|
|
275
|
+
if _is_valid_uuid(dataflow):
|
|
276
|
+
dfD_filt = dfD[dfD["Dataflow Id"] == dataflow]
|
|
277
|
+
else:
|
|
278
|
+
dfD_filt = dfD[dfD["Dataflow Name"] == dataflow]
|
|
279
|
+
|
|
280
|
+
if dfD_filt.empty:
|
|
281
|
+
raise ValueError(
|
|
282
|
+
f"{icons.red_dot} The '{dataflow}' dataflow does not exist within the '{workspace_name}' workspace."
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
dataflow_id = dfD_filt["Dataflow Id"].iloc[0]
|
|
286
|
+
dataflow_name = dfD_filt["Dataflow Name"].iloc[0]
|
|
287
|
+
dataflow_generation = dfD_filt["Generation"].iloc[0]
|
|
288
|
+
|
|
289
|
+
return (dataflow_name, dataflow_id, dataflow_generation)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@log
|
|
293
|
+
def get_dataflow_definition(
|
|
294
|
+
dataflow: str | UUID,
|
|
295
|
+
workspace: Optional[str | UUID] = None,
|
|
296
|
+
decode: bool = True,
|
|
297
|
+
) -> dict:
|
|
298
|
+
"""
|
|
299
|
+
Obtains the definition of a dataflow. This supports Gen1, Gen2 and Gen 2 CI/CD dataflows.
|
|
300
|
+
|
|
301
|
+
This is a wrapper function for the following API: `Dataflows - Get Dataflow <https://learn.microsoft.com/rest/api/power-bi/dataflows/get-dataflow>`_.
|
|
302
|
+
|
|
303
|
+
Parameters
|
|
304
|
+
----------
|
|
305
|
+
dataflow : str | uuid.UUID
|
|
306
|
+
The name or ID of the dataflow.
|
|
307
|
+
workspace : str | uuid.UUID, default=None
|
|
308
|
+
The Fabric workspace name.
|
|
309
|
+
Defaults to None, which resolves to the workspace of the attached lakehouse
|
|
310
|
+
or if no lakehouse is attached, resolves to the workspace of the notebook.
|
|
311
|
+
decode : bool, optional
|
|
312
|
+
If True, decodes the dataflow definition file.
|
|
313
|
+
|
|
314
|
+
Returns
|
|
315
|
+
-------
|
|
316
|
+
dict
|
|
317
|
+
The dataflow definition.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
321
|
+
|
|
322
|
+
(dataflow_name, dataflow_id, dataflow_generation) = (
|
|
323
|
+
_resolve_dataflow_name_and_id_and_generation(
|
|
324
|
+
dataflow=dataflow, workspace=workspace_id
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
if dataflow_generation == "Gen2 CI/CD":
|
|
329
|
+
result = _base_api(
|
|
330
|
+
request=f"/v1/workspaces/{workspace_id}/items/{dataflow_id}/getDefinition",
|
|
331
|
+
client="fabric_sp",
|
|
332
|
+
method="post",
|
|
333
|
+
lro_return_json=True,
|
|
334
|
+
status_codes=[200, 202],
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
if decode:
|
|
338
|
+
# Decode the payload from base64
|
|
339
|
+
definition = {"definition": {"parts": []}}
|
|
340
|
+
|
|
341
|
+
for part in result.get("definition", {}).get("parts", []):
|
|
342
|
+
path = part.get("path")
|
|
343
|
+
payload = part.get("payload")
|
|
344
|
+
decoded_payload = _decode_b64(payload)
|
|
345
|
+
definition["definition"]["parts"].append(
|
|
346
|
+
{"path": path, "payload": decoded_payload}
|
|
347
|
+
)
|
|
348
|
+
return definition
|
|
349
|
+
else:
|
|
350
|
+
return result
|
|
351
|
+
else:
|
|
352
|
+
result = _base_api(
|
|
353
|
+
request=f"/v1.0/myorg/groups/{workspace_id}/dataflows/{dataflow_id}",
|
|
354
|
+
client="fabric_sp",
|
|
355
|
+
).json()
|
|
356
|
+
|
|
357
|
+
return result
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@log
|
|
361
|
+
def upgrade_dataflow(
|
|
362
|
+
dataflow: str | UUID,
|
|
363
|
+
workspace: Optional[str | UUID] = None,
|
|
364
|
+
new_dataflow_name: Optional[str] = None,
|
|
365
|
+
new_dataflow_workspace: Optional[str | UUID] = None,
|
|
366
|
+
):
|
|
367
|
+
"""
|
|
368
|
+
Creates a Dataflow Gen2 CI/CD item based on the mashup definition from an existing Gen1/Gen2 dataflow. After running this function, update the connections in the dataflow to ensure the data can be properly refreshed.
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
dataflow : str | uuid.UUID
|
|
373
|
+
The name or ID of the dataflow.
|
|
374
|
+
workspace : str | uuid.UUID, default=None
|
|
375
|
+
The workspace name or ID.
|
|
376
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
377
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
378
|
+
new_dataflow_name: str, default=None
|
|
379
|
+
Name of the new dataflow.
|
|
380
|
+
new_dataflow_workspace : str | uuid.UUID, default=None
|
|
381
|
+
The Fabric workspace name or ID of the dataflow to be created.
|
|
382
|
+
Defaults to None which resolves to the existing workspace of the attached lakehouse
|
|
383
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
# Resolve the workspace name and ID
|
|
387
|
+
(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
388
|
+
|
|
389
|
+
# Resolve the dataflow name and ID
|
|
390
|
+
(dataflow_name, dataflow_id, dataflow_generation) = (
|
|
391
|
+
_resolve_dataflow_name_and_id_and_generation(dataflow, workspace_id)
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
if dataflow_generation == "Gen2 CI/CD":
|
|
395
|
+
# Print an error message that the dataflow is already a native Fabric item
|
|
396
|
+
print(
|
|
397
|
+
f"{icons.info} The dataflow '{dataflow_name}' is already a Fabric native Dataflow Gen2 item. No changes made."
|
|
398
|
+
)
|
|
399
|
+
return
|
|
400
|
+
|
|
401
|
+
(new_dataflow_workspace, new_dataflow_workspace_id) = resolve_workspace_name_and_id(
|
|
402
|
+
new_dataflow_workspace
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# If no new dataflow name is provided, use the existing dataflow name
|
|
406
|
+
if not new_dataflow_name:
|
|
407
|
+
new_dataflow_name = dataflow_name
|
|
408
|
+
|
|
409
|
+
# Get dataflow definition
|
|
410
|
+
definition = get_dataflow_definition(dataflow, workspace_id)
|
|
411
|
+
|
|
412
|
+
# Check for linked table references
|
|
413
|
+
matches = (
|
|
414
|
+
parse("$['pbi:mashup'].connectionOverrides[*].kind").find(definition) or []
|
|
415
|
+
)
|
|
416
|
+
if any(match.value in {"PowerPlatformDataflows", "PowerBI"} for match in matches):
|
|
417
|
+
print(
|
|
418
|
+
f"""{icons.red_dot} The dataflow '{dataflow_name}' contains a linked table reference to an existing dataflow as a connection source and will not be upgraded. No changes were made.
|
|
419
|
+
- To track the upstream lineage of linked tables across dataflows use the list_upstream_dataflows function.
|
|
420
|
+
- To automatically remove the tables and upgrade the existing dataflow use the upgrade_powerbippdf_dataflow function."""
|
|
421
|
+
)
|
|
422
|
+
return
|
|
423
|
+
|
|
424
|
+
description = get_jsonpath_value(data=definition, path="$.description")
|
|
425
|
+
|
|
426
|
+
payload = {
|
|
427
|
+
"displayName": new_dataflow_name,
|
|
428
|
+
}
|
|
429
|
+
if description:
|
|
430
|
+
payload["description"] = description
|
|
431
|
+
|
|
432
|
+
# Query Groups
|
|
433
|
+
matches = parse("$.annotations[?(@.name=='pbi:QueryGroups')].value").find(
|
|
434
|
+
definition
|
|
435
|
+
)
|
|
436
|
+
query_groups_value = json.loads(matches[0].value) if matches else []
|
|
437
|
+
|
|
438
|
+
queries_metadata = get_jsonpath_value(
|
|
439
|
+
data=definition, path="$['pbi:mashup'].queriesMetadata"
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
default_staging = True if "DefaultStaging" in queries_metadata else False
|
|
443
|
+
|
|
444
|
+
# Collect keys to delete
|
|
445
|
+
keys_to_delete = [
|
|
446
|
+
key
|
|
447
|
+
for key in queries_metadata
|
|
448
|
+
if key.endswith("_DataDestination")
|
|
449
|
+
or key.endswith("_WriteToDataDestination")
|
|
450
|
+
or key.endswith("_TransformForWriteToDataDestination")
|
|
451
|
+
or key == "FastCopyStaging"
|
|
452
|
+
]
|
|
453
|
+
|
|
454
|
+
# Delete them
|
|
455
|
+
for key in keys_to_delete:
|
|
456
|
+
del queries_metadata[key]
|
|
457
|
+
|
|
458
|
+
# Set load enabled and isHidden
|
|
459
|
+
for key, items in queries_metadata.items():
|
|
460
|
+
items["loadEnabled"] = False
|
|
461
|
+
if key in ["DefaultDestination", "DefaultStaging"]:
|
|
462
|
+
items["isHidden"] = True
|
|
463
|
+
|
|
464
|
+
# Prepare the dataflow definition
|
|
465
|
+
query_metadata = {
|
|
466
|
+
"formatVersion": "202502",
|
|
467
|
+
"computeEngineSettings": {}, # How to set this?
|
|
468
|
+
"name": new_dataflow_name,
|
|
469
|
+
"queryGroups": query_groups_value,
|
|
470
|
+
"documentLocale": get_jsonpath_value(data=definition, path="$.culture"),
|
|
471
|
+
"queriesMetadata": queries_metadata,
|
|
472
|
+
"fastCombine": get_jsonpath_value(
|
|
473
|
+
data=definition, path="$['pbi:mashup'].fastCombine", default=False
|
|
474
|
+
),
|
|
475
|
+
"allowNativeQueries": get_jsonpath_value(
|
|
476
|
+
data=definition, path="$['pbi:mashup'].allowNativeQueries", default=False
|
|
477
|
+
),
|
|
478
|
+
# "connections": [],
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
fast_copy = get_jsonpath_value(
|
|
482
|
+
data=definition, path="$['ppdf:fastCopy']", default=False
|
|
483
|
+
)
|
|
484
|
+
max_concurrency = get_jsonpath_value(
|
|
485
|
+
data=definition, path="$['ppdf:maxConcurrency']"
|
|
486
|
+
)
|
|
487
|
+
if fast_copy:
|
|
488
|
+
query_metadata["computeEngineSettings"] = {}
|
|
489
|
+
|
|
490
|
+
if max_concurrency:
|
|
491
|
+
query_metadata["computeEngineSettings"]["maxConcurrency"] = max_concurrency
|
|
492
|
+
|
|
493
|
+
mashup_doc = get_jsonpath_value(data=definition, path="$['pbi:mashup'].document")
|
|
494
|
+
|
|
495
|
+
# Remove the FastCopyStaging section if it exists
|
|
496
|
+
new_mashup_doc = ""
|
|
497
|
+
if default_staging and fast_copy:
|
|
498
|
+
new_mashup_doc = '[DefaultOutputDestinationSettings = [DestinationDefinition = [Kind = "Reference", QueryName = "DefaultDestination", IsNewTarget = true], UpdateMethod = [Kind = "Replace"]], StagingDefinition = [Kind = "FastCopy"]]\r\nsection Section1'
|
|
499
|
+
elif default_staging and not fast_copy:
|
|
500
|
+
new_mashup_doc = '[DefaultOutputDestinationSettings = [DestinationDefinition = [Kind = "Reference", QueryName = "DefaultDestination", IsNewTarget = true], UpdateMethod = [Kind = "Replace"]]\r\nsection Section1'
|
|
501
|
+
elif not default_staging and fast_copy:
|
|
502
|
+
new_mashup_doc = '[StagingDefinition = [Kind = "FastCopy"]]\r\nsection Section1'
|
|
503
|
+
else:
|
|
504
|
+
new_mashup_doc = "section Section1"
|
|
505
|
+
for i in mashup_doc.split(";\r\nshared "):
|
|
506
|
+
# if 'IsParameterQuery=true' in i:
|
|
507
|
+
# Add to queries_metadata
|
|
508
|
+
if not (
|
|
509
|
+
"FastCopyStaging = let" in i
|
|
510
|
+
or '_WriteToDataDestination" = let' in i
|
|
511
|
+
or "_WriteToDataDestination = let" in i
|
|
512
|
+
or '_DataDestination" = let' in i
|
|
513
|
+
or "_DataDestination = let" in i
|
|
514
|
+
or '_TransformForWriteToDataDestination" = let' in i
|
|
515
|
+
or "_TransformForWriteToDataDestination = let" in i
|
|
516
|
+
):
|
|
517
|
+
if i != "section Section1":
|
|
518
|
+
if default_staging and (
|
|
519
|
+
"IsParameterQuery=true" not in i
|
|
520
|
+
and not i.startswith("DefaultStaging")
|
|
521
|
+
and not i.startswith("DefaultDestination")
|
|
522
|
+
):
|
|
523
|
+
new_mashup_doc += (
|
|
524
|
+
";\r\n[BindToDefaultDestination = true]\r\nshared " + i
|
|
525
|
+
)
|
|
526
|
+
else:
|
|
527
|
+
new_mashup_doc += ";\r\nshared " + i
|
|
528
|
+
new_mashup_doc = f"{new_mashup_doc};"
|
|
529
|
+
|
|
530
|
+
# Add the dataflow definition to the payload
|
|
531
|
+
new_definition = {
|
|
532
|
+
"parts": [
|
|
533
|
+
{
|
|
534
|
+
"path": "queryMetadata.json",
|
|
535
|
+
"payload": _conv_b64(query_metadata),
|
|
536
|
+
"payloadType": "InlineBase64",
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"path": "mashup.pq",
|
|
540
|
+
"payload": _conv_b64(new_mashup_doc, json_dumps=False),
|
|
541
|
+
"payloadType": "InlineBase64",
|
|
542
|
+
},
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
create_dataflow(
|
|
547
|
+
name=new_dataflow_name,
|
|
548
|
+
workspace=new_dataflow_workspace,
|
|
549
|
+
definition=new_definition,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
@log
|
|
554
|
+
def create_dataflow(
|
|
555
|
+
name: str,
|
|
556
|
+
workspace: Optional[str | UUID] = None,
|
|
557
|
+
description: Optional[str] = None,
|
|
558
|
+
definition: Optional[dict] = None,
|
|
559
|
+
):
|
|
560
|
+
"""
|
|
561
|
+
Creates a native Fabric Dataflow Gen2 CI/CD item.
|
|
562
|
+
|
|
563
|
+
This is a wrapper function for the following API: `Items - Create Dataflow <https://learn.microsoft.com/rest/api/fabric/dataflow/items/create-dataflow>`_.
|
|
564
|
+
|
|
565
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
566
|
+
|
|
567
|
+
Parameters
|
|
568
|
+
----------
|
|
569
|
+
name : str
|
|
570
|
+
The name the dataflow.
|
|
571
|
+
workspace : str | uuid.UUID, default=None
|
|
572
|
+
The workspace name or ID.
|
|
573
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
574
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
575
|
+
description : str, default=None
|
|
576
|
+
The description of the dataflow.
|
|
577
|
+
definition : dict, default=None
|
|
578
|
+
The definition of the dataflow in the form of a dictionary.
|
|
579
|
+
"""
|
|
580
|
+
|
|
581
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
582
|
+
|
|
583
|
+
payload = {
|
|
584
|
+
"displayName": name,
|
|
585
|
+
}
|
|
586
|
+
if description:
|
|
587
|
+
payload["description"] = description
|
|
588
|
+
|
|
589
|
+
if definition:
|
|
590
|
+
payload["definition"] = definition
|
|
591
|
+
|
|
592
|
+
_base_api(
|
|
593
|
+
request=f"/v1/workspaces/{workspace_id}/dataflows",
|
|
594
|
+
method="post",
|
|
595
|
+
payload=payload,
|
|
596
|
+
client="fabric_sp",
|
|
597
|
+
lro_return_json=True,
|
|
598
|
+
status_codes=[201, 202],
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
print(
|
|
602
|
+
f"{icons.green_dot} The dataflow '{name}' has been created within the '{workspace_name}' workspace."
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
@log
|
|
607
|
+
def discover_dataflow_parameters(
|
|
608
|
+
dataflow: str | UUID, workspace: str | UUID
|
|
609
|
+
) -> pd.DataFrame:
|
|
610
|
+
"""
|
|
611
|
+
Retrieves all parameters defined in the specified Dataflow.
|
|
612
|
+
|
|
613
|
+
This is a wrapper function for the following API: `Items - Discover Dataflow Parameters <https://learn.microsoft.com/rest/api/fabric/dataflow/items/discover-dataflow-parameters>`_.
|
|
614
|
+
|
|
615
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
616
|
+
|
|
617
|
+
Parameters
|
|
618
|
+
----------
|
|
619
|
+
dataflow : str | uuid.UUID
|
|
620
|
+
Name or ID of the dataflow.
|
|
621
|
+
workspace : str | uuid.UUID, default=None
|
|
622
|
+
The Fabric workspace name or ID.
|
|
623
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
624
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
625
|
+
|
|
626
|
+
Returns
|
|
627
|
+
-------
|
|
628
|
+
pandas.DataFrame
|
|
629
|
+
A pandas dataframe showing all parameters defined in the specified Dataflow.
|
|
630
|
+
"""
|
|
631
|
+
|
|
632
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
633
|
+
dataflow_id = resolve_item_id(
|
|
634
|
+
item=dataflow, type="Dataflow", workspace=workspace_id
|
|
635
|
+
)
|
|
636
|
+
responses = _base_api(
|
|
637
|
+
request=f"/v1/workspaces/{workspace_id}/dataflows/{dataflow_id}/parameters",
|
|
638
|
+
client="fabric_sp",
|
|
639
|
+
uses_pagination=True,
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
columns = {
|
|
643
|
+
"Parameter Name": "string",
|
|
644
|
+
"Is Required": "bool",
|
|
645
|
+
"Description": "string",
|
|
646
|
+
"Parameter Type": "string",
|
|
647
|
+
"Default Value": "string",
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
df = _create_dataframe(columns=columns)
|
|
651
|
+
rows = []
|
|
652
|
+
for r in responses:
|
|
653
|
+
for v in r.get("value", []):
|
|
654
|
+
rows.append(
|
|
655
|
+
{
|
|
656
|
+
"Parameter Name": v.get("name"),
|
|
657
|
+
"Is Required": v.get("isRequired"),
|
|
658
|
+
"Description": v.get("description"),
|
|
659
|
+
"Parameter Type": v.get("type"),
|
|
660
|
+
"Default Value": v.get("defaultValue"),
|
|
661
|
+
}
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
if rows:
|
|
665
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
666
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
667
|
+
|
|
668
|
+
return df
|