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,516 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import os
|
|
3
|
+
import base64
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
import sempy_labs._icons as icons
|
|
6
|
+
from typing import List, Literal, Optional
|
|
7
|
+
from sempy_labs._helper_functions import (
|
|
8
|
+
_is_valid_uuid,
|
|
9
|
+
_base_api,
|
|
10
|
+
_create_dataframe,
|
|
11
|
+
_update_dataframe_datatypes,
|
|
12
|
+
_mount,
|
|
13
|
+
)
|
|
14
|
+
from sempy._utils._log import log
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@log
|
|
18
|
+
def resolve_user_id(user: str | UUID) -> UUID:
|
|
19
|
+
"""
|
|
20
|
+
Resolves the user ID from the user principal name or ID.
|
|
21
|
+
|
|
22
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
user : str | uuid.UUID
|
|
27
|
+
The user ID or user principal name.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
uuid.UUID
|
|
32
|
+
The user ID.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
if _is_valid_uuid(user):
|
|
36
|
+
return user
|
|
37
|
+
else:
|
|
38
|
+
result = _base_api(request=f"users/{user}", client="graph").json()
|
|
39
|
+
return result.get("id")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@log
|
|
43
|
+
def get_user(user: str | UUID, show_manager: bool = False) -> pd.DataFrame:
|
|
44
|
+
"""
|
|
45
|
+
Shows properties of a given user.
|
|
46
|
+
|
|
47
|
+
This is a wrapper function for the following API: `Get a user <https://learn.microsoft.com/graph/api/user-get>`_.
|
|
48
|
+
|
|
49
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
user : str | uuid.UUID
|
|
54
|
+
The user ID or user principal name.
|
|
55
|
+
show_manager : bool, default=False
|
|
56
|
+
Whether to include the user's manager information.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
pandas.DataFrame
|
|
61
|
+
A pandas dataframe showing properties of a given user.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
url = f"users/{user}?$select=id,userPrincipalName,displayName,mail,jobTitle,officeLocation,mobilePhone,businessPhones,preferredLanguage,surname,department"
|
|
65
|
+
if show_manager:
|
|
66
|
+
url += "&$expand=manager($select=displayName,id,mail,jobTitle)"
|
|
67
|
+
|
|
68
|
+
result = _base_api(request=url, client="graph").json()
|
|
69
|
+
|
|
70
|
+
new_data = {
|
|
71
|
+
"User Id": result.get("id"),
|
|
72
|
+
"User Principal Name": result.get("userPrincipalName"),
|
|
73
|
+
"User Name": result.get("displayName"),
|
|
74
|
+
"Mail": result.get("mail"),
|
|
75
|
+
"Job Title": result.get("jobTitle"),
|
|
76
|
+
"Office Location": result.get("officeLocation"),
|
|
77
|
+
"Mobile Phone": result.get("mobilePhone"),
|
|
78
|
+
"Business Phones": str(result.get("businessPhones")),
|
|
79
|
+
"Preferred Language": result.get("preferredLanguage"),
|
|
80
|
+
"Surname": result.get("surname"),
|
|
81
|
+
"Department": result.get("department"),
|
|
82
|
+
}
|
|
83
|
+
if show_manager:
|
|
84
|
+
manager = result.get("manager", {})
|
|
85
|
+
new_data |= {
|
|
86
|
+
"Manager Id": manager.get("id"),
|
|
87
|
+
"Manager Name": manager.get("displayName"),
|
|
88
|
+
"Manager Mail": manager.get("mail"),
|
|
89
|
+
"Manager Job Title": manager.get("jobTitle"),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return pd.DataFrame([new_data])
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@log
|
|
96
|
+
def list_users(show_manager: bool = False) -> pd.DataFrame:
|
|
97
|
+
"""
|
|
98
|
+
Shows a list of users and their properties.
|
|
99
|
+
|
|
100
|
+
This is a wrapper function for the following API: `List users <https://learn.microsoft.com/graph/api/user-list>`_.
|
|
101
|
+
|
|
102
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
show_manager : bool, default=False
|
|
107
|
+
Whether to include the user's manager information.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
pandas.DataFrame
|
|
112
|
+
A pandas dataframe showing a list of users and their properties.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
url = "users?$select=id,userPrincipalName,displayName,mail,jobTitle,officeLocation,mobilePhone,businessPhones,preferredLanguage,surname,department"
|
|
116
|
+
if show_manager:
|
|
117
|
+
url += "&$expand=manager($select=displayName,id,mail,jobTitle)"
|
|
118
|
+
result = _base_api(request=url, client="graph", uses_pagination=True)
|
|
119
|
+
|
|
120
|
+
columns = {
|
|
121
|
+
"User Id": "string",
|
|
122
|
+
"User Principal Name": "string",
|
|
123
|
+
"User Name": "string",
|
|
124
|
+
"Mail": "string",
|
|
125
|
+
"Job Title": "string",
|
|
126
|
+
"Office Location": "string",
|
|
127
|
+
"Mobile Phone": "string",
|
|
128
|
+
"Business Phones": "string",
|
|
129
|
+
"Preferred Language": "string",
|
|
130
|
+
"Surname": "string",
|
|
131
|
+
"Department": "string",
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if show_manager:
|
|
135
|
+
columns.update(
|
|
136
|
+
{
|
|
137
|
+
"Manager Id": "string",
|
|
138
|
+
"Manager Name": "string",
|
|
139
|
+
"Manager Mail": "string",
|
|
140
|
+
"Manager Job Title": "string",
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
df = _create_dataframe(columns=columns)
|
|
145
|
+
|
|
146
|
+
rows = []
|
|
147
|
+
for r in result:
|
|
148
|
+
for v in r.get("value", []):
|
|
149
|
+
user_data = {
|
|
150
|
+
"User Id": v.get("id"),
|
|
151
|
+
"User Principal Name": v.get("userPrincipalName"),
|
|
152
|
+
"User Name": v.get("displayName"),
|
|
153
|
+
"Mail": v.get("mail"),
|
|
154
|
+
"Job Title": v.get("jobTitle"),
|
|
155
|
+
"Office Location": v.get("officeLocation"),
|
|
156
|
+
"Mobile Phone": v.get("mobilePhone"),
|
|
157
|
+
"Business Phones": str(v.get("businessPhones")),
|
|
158
|
+
"Preferred Language": v.get("preferredLanguage"),
|
|
159
|
+
"Surname": v.get("surname"),
|
|
160
|
+
"Department": v.get("department"),
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if show_manager:
|
|
164
|
+
manager = v.get("manager", {})
|
|
165
|
+
user_data |= {
|
|
166
|
+
"Manager Id": manager.get("id"),
|
|
167
|
+
"Manager Name": manager.get("displayName"),
|
|
168
|
+
"Manager Mail": manager.get("mail"),
|
|
169
|
+
"Manager Job Title": manager.get("jobTitle"),
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
rows.append(user_data)
|
|
173
|
+
|
|
174
|
+
if rows:
|
|
175
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
176
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
177
|
+
|
|
178
|
+
return df
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@log
|
|
182
|
+
def send_mail(
|
|
183
|
+
user: UUID | str,
|
|
184
|
+
subject: str,
|
|
185
|
+
to_recipients: str | List[str],
|
|
186
|
+
content: str,
|
|
187
|
+
content_type: Literal["Text", "HTML"] = "Text",
|
|
188
|
+
cc_recipients: Optional[str | List[str]] = None,
|
|
189
|
+
bcc_recipients: Optional[str | List[str]] = None,
|
|
190
|
+
priority: Literal["Normal", "High", "Low"] = "Normal",
|
|
191
|
+
attachments: Optional[str | List[str]] = None,
|
|
192
|
+
):
|
|
193
|
+
"""
|
|
194
|
+
Sends an email to the specified recipients.
|
|
195
|
+
|
|
196
|
+
This is a wrapper function for the following API: `user: sendMail <https://learn.microsoft.com/graph/api/user-sendmail>`_.
|
|
197
|
+
|
|
198
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
user : uuid.UUID | str
|
|
203
|
+
The user ID or user principal name.
|
|
204
|
+
subject : str
|
|
205
|
+
The email subject.
|
|
206
|
+
to_recipients : str | List[str]
|
|
207
|
+
The email address of the recipients.
|
|
208
|
+
content : str
|
|
209
|
+
The email content.
|
|
210
|
+
content_type : Literal["Text", "HTML"], default="Text"
|
|
211
|
+
The email content type. Options: "Text" or "HTML".
|
|
212
|
+
cc_recipients : str | List[str], default=None
|
|
213
|
+
The email address of the CC recipients.
|
|
214
|
+
bcc_recipients : str | List[str], default=None
|
|
215
|
+
The email address of the BCC recipients.
|
|
216
|
+
priority : Literal["Normal", "High", "Low"], default="Normal"
|
|
217
|
+
The email priority.
|
|
218
|
+
attachments : str | List[str], default=None
|
|
219
|
+
The abfss path or a list of the abfss paths of the attachments to include in the email.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
content_type = "HTML" if content_type.lower() == "html" else "Text"
|
|
223
|
+
|
|
224
|
+
priority = priority.capitalize()
|
|
225
|
+
if priority not in ["Normal", "High", "Low"]:
|
|
226
|
+
raise ValueError(
|
|
227
|
+
f"{icons.red_dot} Invalid priority: {priority}. Options are: Normal, High, Low."
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
user_id = resolve_user_id(user=user)
|
|
231
|
+
|
|
232
|
+
if isinstance(to_recipients, str):
|
|
233
|
+
to_recipients = [to_recipients]
|
|
234
|
+
|
|
235
|
+
if isinstance(cc_recipients, str):
|
|
236
|
+
cc_recipients = [cc_recipients]
|
|
237
|
+
|
|
238
|
+
to_email_addresses = [
|
|
239
|
+
{"emailAddress": {"address": email}} for email in to_recipients
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
cc_email_addresses = (
|
|
243
|
+
[{"emailAddress": {"address": email}} for email in cc_recipients]
|
|
244
|
+
if cc_recipients
|
|
245
|
+
else None
|
|
246
|
+
)
|
|
247
|
+
bcc_email_addresses = (
|
|
248
|
+
[{"emailAddress": {"address": email}} for email in bcc_recipients]
|
|
249
|
+
if bcc_recipients
|
|
250
|
+
else None
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
payload = {
|
|
254
|
+
"message": {
|
|
255
|
+
"subject": subject,
|
|
256
|
+
"body": {
|
|
257
|
+
"contentType": content_type,
|
|
258
|
+
"content": content,
|
|
259
|
+
},
|
|
260
|
+
"toRecipients": to_email_addresses,
|
|
261
|
+
"importance": priority,
|
|
262
|
+
},
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if cc_email_addresses:
|
|
266
|
+
payload["message"]["ccRecipients"] = cc_email_addresses
|
|
267
|
+
|
|
268
|
+
if bcc_email_addresses:
|
|
269
|
+
payload["message"]["bccRecipients"] = bcc_email_addresses
|
|
270
|
+
|
|
271
|
+
# if follow_up_flag:
|
|
272
|
+
# payload["message"]["flag"] = {"flagStatus": "flagged"}
|
|
273
|
+
|
|
274
|
+
content_types = {
|
|
275
|
+
".txt": "text/plain",
|
|
276
|
+
".pdf": "application/pdf",
|
|
277
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
278
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
279
|
+
".csv": "text/csv",
|
|
280
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
281
|
+
".jpg": "image/jpeg",
|
|
282
|
+
".jpeg": "image/jpeg",
|
|
283
|
+
".png": "image/png",
|
|
284
|
+
".gif": "image/gif",
|
|
285
|
+
".bmp": "image/bmp",
|
|
286
|
+
".zip": "application/zip",
|
|
287
|
+
".json": "application/json",
|
|
288
|
+
".xml": "application/xml",
|
|
289
|
+
".html": "text/html",
|
|
290
|
+
".bim": "application/json",
|
|
291
|
+
".pbix": "application/vnd.ms-powerbi.report",
|
|
292
|
+
".pbip": "application/vnd.ms-powerbi.report",
|
|
293
|
+
".pbit": "application/vnd.ms-powerbi.report",
|
|
294
|
+
".vpax": "application/zip",
|
|
295
|
+
".geojson": "application/geo+json",
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
def file_path_to_content_bytes(file_path):
|
|
299
|
+
|
|
300
|
+
path_parts = file_path.split("abfss://")[1].split("@")
|
|
301
|
+
workspace = path_parts[0]
|
|
302
|
+
|
|
303
|
+
rest = path_parts[1].split(".microsoft.com/")[1]
|
|
304
|
+
lakehouse, *file_parts = rest.split("/")
|
|
305
|
+
if lakehouse.endswith(".Lakehouse"):
|
|
306
|
+
lakehouse = lakehouse.removesuffix(".Lakehouse")
|
|
307
|
+
relative_path = os.path.join(*file_parts)
|
|
308
|
+
|
|
309
|
+
local_path = _mount(lakehouse, workspace)
|
|
310
|
+
full_path = os.path.join(local_path, relative_path)
|
|
311
|
+
|
|
312
|
+
with open(full_path, "rb") as file:
|
|
313
|
+
return base64.b64encode(file.read()).decode("utf-8")
|
|
314
|
+
|
|
315
|
+
if isinstance(attachments, str):
|
|
316
|
+
attachments = [attachments]
|
|
317
|
+
if attachments:
|
|
318
|
+
attachments_list = []
|
|
319
|
+
for attach_path in attachments:
|
|
320
|
+
content_bytes = file_path_to_content_bytes(attach_path)
|
|
321
|
+
file_extension = os.path.splitext(attach_path)[1]
|
|
322
|
+
content_type = content_types.get(file_extension)
|
|
323
|
+
if not content_type:
|
|
324
|
+
raise ValueError(
|
|
325
|
+
f"{icons.red_dot} Unsupported file type: {file_extension}. Supported types are: {', '.join(content_types.keys())}."
|
|
326
|
+
)
|
|
327
|
+
attachments_list.append(
|
|
328
|
+
{
|
|
329
|
+
"@odata.type": "#microsoft.graph.fileAttachment",
|
|
330
|
+
"name": attach_path.split("/")[-1],
|
|
331
|
+
"contentType": content_type,
|
|
332
|
+
"contentBytes": content_bytes,
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Add to payload
|
|
337
|
+
payload["message"]["attachments"] = attachments_list
|
|
338
|
+
|
|
339
|
+
_base_api(
|
|
340
|
+
request=f"users/{user_id}/sendMail",
|
|
341
|
+
client="graph",
|
|
342
|
+
status_codes=202,
|
|
343
|
+
payload=payload,
|
|
344
|
+
method="post",
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
printout = f"{icons.green_dot} The email has been sent to {to_recipients}"
|
|
348
|
+
if cc_recipients:
|
|
349
|
+
printout += f" and CCed to {cc_recipients}"
|
|
350
|
+
if bcc_recipients:
|
|
351
|
+
printout += f" and BCCed to {bcc_recipients}"
|
|
352
|
+
if attachments:
|
|
353
|
+
printout += f" with {len(attachments)} attachment(s)"
|
|
354
|
+
print(f"{printout}.")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@log
|
|
358
|
+
def create_user(
|
|
359
|
+
display_name: str,
|
|
360
|
+
user_principal_name: str,
|
|
361
|
+
mail_nickname: str,
|
|
362
|
+
password: str,
|
|
363
|
+
account_enabled: bool = True,
|
|
364
|
+
force_change_password_next_sign_in: bool = True,
|
|
365
|
+
):
|
|
366
|
+
"""
|
|
367
|
+
Creates a new user.
|
|
368
|
+
|
|
369
|
+
This is a wrapper function for the following API: `Create User <https://learn.microsoft.com/graph/api/user-post-users>`_.
|
|
370
|
+
|
|
371
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
372
|
+
|
|
373
|
+
Parameters
|
|
374
|
+
----------
|
|
375
|
+
display_name : str
|
|
376
|
+
The name to display in the address book for the user.
|
|
377
|
+
user_principal_name : str
|
|
378
|
+
The user principal name (someuser@contoso.com).
|
|
379
|
+
mail_nickname : str
|
|
380
|
+
The mail alias for the user.
|
|
381
|
+
password : str
|
|
382
|
+
The initial password for the user.
|
|
383
|
+
account_enabled : bool, default=True
|
|
384
|
+
Whether the account is enabled. Default is True.
|
|
385
|
+
force_change_password_next_sign_in : bool, default=True
|
|
386
|
+
Whether the user must change their password on next sign-in. Default is True.
|
|
387
|
+
"""
|
|
388
|
+
|
|
389
|
+
payload = {
|
|
390
|
+
"accountEnabled": account_enabled,
|
|
391
|
+
"displayName": display_name,
|
|
392
|
+
"mailNickname": mail_nickname,
|
|
393
|
+
"userPrincipalName": user_principal_name,
|
|
394
|
+
"passwordProfile": {
|
|
395
|
+
"forceChangePasswordNextSignIn": force_change_password_next_sign_in,
|
|
396
|
+
"password": password,
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
_base_api(
|
|
401
|
+
request="users",
|
|
402
|
+
client="graph",
|
|
403
|
+
status_codes=201,
|
|
404
|
+
payload=payload,
|
|
405
|
+
method="post",
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
print(f"{icons.green_dot} The '{display_name}' user has been created successfully.")
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@log
|
|
412
|
+
def delete_user(user: str | UUID):
|
|
413
|
+
"""
|
|
414
|
+
Deletes a user.
|
|
415
|
+
|
|
416
|
+
This is a wrapper function for the following API: `Delete User <https://learn.microsoft.com/graph/api/user-delete>`_.
|
|
417
|
+
|
|
418
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
419
|
+
|
|
420
|
+
Parameters
|
|
421
|
+
----------
|
|
422
|
+
user : str | uuid.UUID
|
|
423
|
+
The user name or ID.
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
user_id = resolve_user_id(user)
|
|
427
|
+
|
|
428
|
+
_base_api(
|
|
429
|
+
request=f"users/{user_id}",
|
|
430
|
+
client="graph",
|
|
431
|
+
status_codes=204,
|
|
432
|
+
method="delete",
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
print(f"{icons.green_dot} The '{user}' user has been deleted successfully.")
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
@log
|
|
439
|
+
def update_user(
|
|
440
|
+
user: str | UUID,
|
|
441
|
+
display_name: Optional[str] = None,
|
|
442
|
+
user_principal_name: Optional[str] = None,
|
|
443
|
+
given_name: Optional[str] = None,
|
|
444
|
+
surname: Optional[str] = None,
|
|
445
|
+
job_title: Optional[str] = None,
|
|
446
|
+
mail_nickname: Optional[str] = None,
|
|
447
|
+
my_site: Optional[str] = None,
|
|
448
|
+
office_location: Optional[str] = None,
|
|
449
|
+
account_enabled: Optional[bool] = None,
|
|
450
|
+
):
|
|
451
|
+
"""
|
|
452
|
+
Updates a user's properties.
|
|
453
|
+
|
|
454
|
+
This is a wrapper function for the following API: `Update user <https://learn.microsoft.com/graph/api/user-update>`_.
|
|
455
|
+
|
|
456
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
457
|
+
|
|
458
|
+
Parameters
|
|
459
|
+
----------
|
|
460
|
+
user : str | uuid.UUID
|
|
461
|
+
The user name or ID.
|
|
462
|
+
display_name : str, default=None
|
|
463
|
+
The name displayed in the address book for the user.
|
|
464
|
+
user_principal_name : str, default=None
|
|
465
|
+
The user principal name (UPN) of the user.
|
|
466
|
+
given_name : str, default=None
|
|
467
|
+
The given name (first name) of the user.
|
|
468
|
+
surname : str, default=None
|
|
469
|
+
The user's surname (family name or last name).
|
|
470
|
+
job_title : str, default=None
|
|
471
|
+
The user's job title.
|
|
472
|
+
mail_nickname : str, default=None
|
|
473
|
+
The mail alias for the user. This property must be specified when a user is created.
|
|
474
|
+
my_site : str, default=None
|
|
475
|
+
The URL for the user's personal site.
|
|
476
|
+
office_location : str, default=None
|
|
477
|
+
The office location in the user's place of business.
|
|
478
|
+
account_enabled : bool, default=None
|
|
479
|
+
Whether the account is enabled. If None, the property will not be updated.
|
|
480
|
+
"""
|
|
481
|
+
|
|
482
|
+
user_id = resolve_user_id(user)
|
|
483
|
+
|
|
484
|
+
payload = {}
|
|
485
|
+
if display_name is not None:
|
|
486
|
+
payload["displayName"] = display_name
|
|
487
|
+
if mail_nickname is not None:
|
|
488
|
+
payload["mailNickname"] = mail_nickname
|
|
489
|
+
if user_principal_name is not None:
|
|
490
|
+
payload["userPrincipalName"] = user_principal_name
|
|
491
|
+
if given_name is not None:
|
|
492
|
+
payload["givenName"] = given_name
|
|
493
|
+
if job_title is not None:
|
|
494
|
+
payload["jobTitle"] = job_title
|
|
495
|
+
if my_site is not None:
|
|
496
|
+
payload["mySite"] = my_site
|
|
497
|
+
if office_location is not None:
|
|
498
|
+
payload["officeLocation"] = office_location
|
|
499
|
+
if surname is not None:
|
|
500
|
+
payload["surname"] = surname
|
|
501
|
+
if account_enabled is not None and isinstance(account_enabled, bool):
|
|
502
|
+
payload["accountEnabled"] = account_enabled
|
|
503
|
+
|
|
504
|
+
if not payload:
|
|
505
|
+
print(f"{icons.info} No properties to update.")
|
|
506
|
+
return
|
|
507
|
+
|
|
508
|
+
_base_api(
|
|
509
|
+
request=f"users/{user_id}",
|
|
510
|
+
client="graph",
|
|
511
|
+
status_codes=204,
|
|
512
|
+
payload=payload,
|
|
513
|
+
method="patch",
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
print(f"{icons.green_dot} The '{user}' user has been updated successfully.")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from ._items import (
|
|
2
|
+
list_graph_models,
|
|
3
|
+
execute_query,
|
|
4
|
+
get_queryable_graph_type,
|
|
5
|
+
)
|
|
6
|
+
from ._background_jobs import (
|
|
7
|
+
refresh_graph,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"list_graph_models",
|
|
12
|
+
"execute_query",
|
|
13
|
+
"get_queryable_graph_type",
|
|
14
|
+
"refresh_graph",
|
|
15
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from sempy._utils._log import log
|
|
5
|
+
from sempy_labs._helper_functions import (
|
|
6
|
+
_base_api,
|
|
7
|
+
resolve_item_name_and_id,
|
|
8
|
+
resolve_workspace_name_and_id,
|
|
9
|
+
)
|
|
10
|
+
import sempy_labs._icons as icons
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@log
|
|
14
|
+
def refresh_graph(
|
|
15
|
+
graph_model: str | UUID, workspace: Optional[str | UUID] = None
|
|
16
|
+
) -> pd.DataFrame:
|
|
17
|
+
"""
|
|
18
|
+
Refreshes the graph model.
|
|
19
|
+
|
|
20
|
+
This is a wrapper function for the following API: `Background Jobs - Run On Demand Refresh Graph <https://learn.microsoft.com/rest/api/fabric/graphmodel/background-jobs/run-on-demand-refresh-graph>`_.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
graph_model : str | uuid.UUID
|
|
25
|
+
The graph model name or ID.
|
|
26
|
+
workspace : str | uuid.UUID, default=None
|
|
27
|
+
The Fabric workspace name or ID.
|
|
28
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
29
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
pandas.DataFrame
|
|
34
|
+
A pandas dataframe showing the result of the refresh operation.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
(workspace_name, workspace_id) = resolve_workspace_name_and_id(workspace)
|
|
38
|
+
(item_name, item_id) = resolve_item_name_and_id(
|
|
39
|
+
item=graph_model, type="GraphModel", workspace=workspace_id
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
print(
|
|
43
|
+
f"{icons.in_progress} The refresh graph job for the '{item_name}' graph model within the '{workspace_name}' workspace has been initiated."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
df = _base_api(
|
|
47
|
+
request=f"/v1/workspaces/{workspace_id}/GraphModels/{item_id}/jobs/instances?jobType=RefreshGraph",
|
|
48
|
+
method="post",
|
|
49
|
+
lro_return_df=True,
|
|
50
|
+
)
|
|
51
|
+
status = df["Status"].iloc[0]
|
|
52
|
+
|
|
53
|
+
if status == "Completed":
|
|
54
|
+
print(
|
|
55
|
+
f"{icons.green_dot} The refresh graph job for the '{item_name}' graph model within the '{workspace_name}' workspace has succeeded."
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
print(status)
|
|
59
|
+
print(
|
|
60
|
+
f"{icons.red_dot} The refresh graph job for the '{item_name}' graph model within the '{workspace_name}' workspace has failed."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return df
|