semantic-link-labs 0.12.3__py3-none-any.whl → 0.12.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of semantic-link-labs might be problematic. Click here for more details.
- {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/METADATA +5 -3
- {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/RECORD +45 -37
- sempy_labs/__init__.py +20 -16
- sempy_labs/_a_lib_info.py +1 -1
- sempy_labs/_authentication.py +1 -1
- sempy_labs/_capacities.py +1 -1
- sempy_labs/_dataflows.py +98 -10
- sempy_labs/_git.py +1 -1
- sempy_labs/_helper_functions.py +32 -5
- sempy_labs/_list_functions.py +55 -5
- sempy_labs/_managed_private_endpoints.py +63 -1
- sempy_labs/_model_bpa.py +6 -0
- sempy_labs/_notebooks.py +4 -2
- sempy_labs/_onelake.py +131 -0
- sempy_labs/_sql_audit_settings.py +208 -0
- sempy_labs/_sql_endpoints.py +18 -3
- sempy_labs/_utils.py +2 -0
- sempy_labs/admin/__init__.py +6 -0
- sempy_labs/admin/_basic_functions.py +17 -13
- sempy_labs/admin/_items.py +3 -3
- sempy_labs/admin/_labels.py +211 -0
- sempy_labs/admin/_workspaces.py +2 -2
- sempy_labs/deployment_pipeline/__init__.py +21 -0
- sempy_labs/deployment_pipeline/_items.py +486 -0
- sempy_labs/directlake/_update_directlake_partition_entity.py +73 -41
- sempy_labs/directlake/_warm_cache.py +3 -1
- 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 +10 -0
- sempy_labs/graph/_groups.py +123 -53
- sempy_labs/graph/_sensitivity_labels.py +39 -0
- sempy_labs/graph/_teams.py +19 -18
- sempy_labs/graph/_user_licenses.py +96 -0
- sempy_labs/graph/_users.py +69 -18
- sempy_labs/lakehouse/_get_lakehouse_tables.py +33 -1
- sempy_labs/lakehouse/_lakehouse.py +6 -2
- sempy_labs/lakehouse/_partitioning.py +165 -0
- sempy_labs/report/_export_report.py +0 -22
- sempy_labs/report/_report_rebind.py +29 -43
- sempy_labs/report/_reportwrapper.py +80 -35
- sempy_labs/tom/_model.py +81 -4
- sempy_labs/_deployment_pipelines.py +0 -209
- sempy_labs/_eventstreams.py +0 -123
- {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/licenses/LICENSE +0 -0
- {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/top_level.txt +0 -0
sempy_labs/graph/_groups.py
CHANGED
|
@@ -55,7 +55,7 @@ def list_groups() -> pd.DataFrame:
|
|
|
55
55
|
A pandas dataframe showing a list of groups and their properties.
|
|
56
56
|
"""
|
|
57
57
|
|
|
58
|
-
result = _base_api(request="groups", client="graph")
|
|
58
|
+
result = _base_api(request="groups", client="graph", uses_pagination=True)
|
|
59
59
|
|
|
60
60
|
columns = {
|
|
61
61
|
"Group Id": "string",
|
|
@@ -76,24 +76,25 @@ def list_groups() -> pd.DataFrame:
|
|
|
76
76
|
df = _create_dataframe(columns=columns)
|
|
77
77
|
|
|
78
78
|
rows = []
|
|
79
|
-
for
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
79
|
+
for r in result:
|
|
80
|
+
for v in r.get("value", []):
|
|
81
|
+
rows.append(
|
|
82
|
+
{
|
|
83
|
+
"Group Id": v.get("id"),
|
|
84
|
+
"Group Name": v.get("displayName"),
|
|
85
|
+
"Mail": v.get("mail"),
|
|
86
|
+
"Description": v.get("description"),
|
|
87
|
+
"Classification": v.get("classification"),
|
|
88
|
+
"Mail Enabled": v.get("mailEnabled"),
|
|
89
|
+
"Security Enabled": v.get("securityEnabled"),
|
|
90
|
+
"Created Date Time": v.get("createdDateTime"),
|
|
91
|
+
"Expiration Date Time": v.get("expirationDateTime"),
|
|
92
|
+
"Renewed Date Time": v.get("renewedDateTime"),
|
|
93
|
+
"Deleted Date Time": v.get("deletedDateTime"),
|
|
94
|
+
"Visibility": v.get("visibility"),
|
|
95
|
+
"Security Identifier": v.get("securityIdentifier"),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
97
98
|
|
|
98
99
|
if rows:
|
|
99
100
|
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
@@ -190,7 +191,9 @@ def list_group_members(group: str | UUID) -> pd.DataFrame:
|
|
|
190
191
|
|
|
191
192
|
group_id = resolve_group_id(group)
|
|
192
193
|
|
|
193
|
-
result = _base_api(
|
|
194
|
+
result = _base_api(
|
|
195
|
+
request=f"groups/{group_id}/members", client="graph", uses_pagination=True
|
|
196
|
+
)
|
|
194
197
|
|
|
195
198
|
columns = {
|
|
196
199
|
"Member Id": "string",
|
|
@@ -209,22 +212,86 @@ def list_group_members(group: str | UUID) -> pd.DataFrame:
|
|
|
209
212
|
df = _create_dataframe(columns=columns)
|
|
210
213
|
|
|
211
214
|
rows = []
|
|
212
|
-
for
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
215
|
+
for r in result:
|
|
216
|
+
for v in r.get("value", []):
|
|
217
|
+
rows.append(
|
|
218
|
+
{
|
|
219
|
+
"Member Id": v.get("id"),
|
|
220
|
+
"Member Name": v.get("displayName"),
|
|
221
|
+
"User Principal Name": v.get("userPrincipalName"),
|
|
222
|
+
"Mail": v.get("mail"),
|
|
223
|
+
"Job Title": v.get("jobTitle"),
|
|
224
|
+
"Office Location": v.get("officeLocation"),
|
|
225
|
+
"Mobile Phone": v.get("mobilePhone"),
|
|
226
|
+
"Business Phones": str(v.get("businessPhones")),
|
|
227
|
+
"Preferred Language": v.get("preferredLanguage"),
|
|
228
|
+
"Given Name": v.get("givenName"),
|
|
229
|
+
"Surname": v.get("surname"),
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if rows:
|
|
234
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
235
|
+
|
|
236
|
+
return df
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@log
|
|
240
|
+
def list_group_transitive_members(group: str | UUID) -> pd.DataFrame:
|
|
241
|
+
"""
|
|
242
|
+
Shows a list of the members of a group. This operation is transitive and returns a flat list of all nested members.
|
|
243
|
+
|
|
244
|
+
This is a wrapper function for the following API: `List group transitive members <https://learn.microsoft.com/graph/api/group-list-transitivemembers>`_.
|
|
245
|
+
|
|
246
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
group : str | uuid.UUID
|
|
251
|
+
The group name or ID.
|
|
252
|
+
|
|
253
|
+
Returns
|
|
254
|
+
-------
|
|
255
|
+
pandas.DataFrame
|
|
256
|
+
A pandas dataframe showing a list of the members of a group.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
group_id = resolve_group_id(group)
|
|
260
|
+
|
|
261
|
+
result = _base_api(
|
|
262
|
+
request=f"groups/{group_id}/transitiveMembers",
|
|
263
|
+
client="graph",
|
|
264
|
+
uses_pagination=True,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
columns = {
|
|
268
|
+
"Member Id": "string",
|
|
269
|
+
"Organization Id": "string",
|
|
270
|
+
"Description": "string",
|
|
271
|
+
"Member Name": "string",
|
|
272
|
+
"Group Types": "list",
|
|
273
|
+
"Mail": "string",
|
|
274
|
+
"Mail Enabled": "bool",
|
|
275
|
+
"Mail Nickname": "string",
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
df = _create_dataframe(columns=columns)
|
|
279
|
+
|
|
280
|
+
rows = []
|
|
281
|
+
for r in result:
|
|
282
|
+
for v in r.get("value", []):
|
|
283
|
+
rows.append(
|
|
284
|
+
{
|
|
285
|
+
"Member Id": v.get("id"),
|
|
286
|
+
"Organization Id": v.get("organizationId"),
|
|
287
|
+
"Description": v.get("description"),
|
|
288
|
+
"Member Name": v.get("displayName"),
|
|
289
|
+
"Group Types": v.get("groupTypes"),
|
|
290
|
+
"Mail": v.get("mail"),
|
|
291
|
+
"Mail Enabled": v.get("mailEnabled"),
|
|
292
|
+
"Mail Nickname": v.get("mailNickname"),
|
|
293
|
+
}
|
|
294
|
+
)
|
|
228
295
|
|
|
229
296
|
if rows:
|
|
230
297
|
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
@@ -254,7 +321,9 @@ def list_group_owners(group: str | UUID) -> pd.DataFrame:
|
|
|
254
321
|
|
|
255
322
|
group_id = resolve_group_id(group)
|
|
256
323
|
|
|
257
|
-
result = _base_api(
|
|
324
|
+
result = _base_api(
|
|
325
|
+
request=f"groups/{group_id}/owners", client="graph", uses_pagination=True
|
|
326
|
+
)
|
|
258
327
|
|
|
259
328
|
columns = {
|
|
260
329
|
"Owner Id": "string",
|
|
@@ -273,22 +342,23 @@ def list_group_owners(group: str | UUID) -> pd.DataFrame:
|
|
|
273
342
|
df = _create_dataframe(columns=columns)
|
|
274
343
|
|
|
275
344
|
rows = []
|
|
276
|
-
for
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
345
|
+
for r in result:
|
|
346
|
+
for v in r.get("value", []):
|
|
347
|
+
rows.append(
|
|
348
|
+
{
|
|
349
|
+
"Owner Id": v.get("id"),
|
|
350
|
+
"Owner Name": v.get("displayName"),
|
|
351
|
+
"User Principal Name": v.get("userPrincipalName"),
|
|
352
|
+
"Mail": v.get("mail"),
|
|
353
|
+
"Job Title": v.get("jobTitle"),
|
|
354
|
+
"Office Location": v.get("officeLocation"),
|
|
355
|
+
"Mobile Phone": v.get("mobilePhone"),
|
|
356
|
+
"Business Phones": str(v.get("businessPhones")),
|
|
357
|
+
"Preferred Language": v.get("preferredLanguage"),
|
|
358
|
+
"Given Name": v.get("givenName"),
|
|
359
|
+
"Surname": v.get("surname"),
|
|
360
|
+
}
|
|
361
|
+
)
|
|
292
362
|
|
|
293
363
|
if rows:
|
|
294
364
|
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
@@ -5,6 +5,7 @@ from sempy_labs._helper_functions import (
|
|
|
5
5
|
_base_api,
|
|
6
6
|
_create_dataframe,
|
|
7
7
|
_update_dataframe_datatypes,
|
|
8
|
+
_is_valid_uuid,
|
|
8
9
|
)
|
|
9
10
|
from sempy._utils._log import log
|
|
10
11
|
|
|
@@ -79,3 +80,41 @@ def list_sensitivity_labels(user: Optional[str | UUID] = None) -> pd.DataFrame:
|
|
|
79
80
|
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
80
81
|
|
|
81
82
|
return df
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@log
|
|
86
|
+
def resolve_sensitivity_label_id(
|
|
87
|
+
label: str | UUID, user: Optional[str | UUID] = None
|
|
88
|
+
) -> UUID | None:
|
|
89
|
+
"""
|
|
90
|
+
Resolve a sensitivity label name or ID to its corresponding sensitivity label ID.
|
|
91
|
+
|
|
92
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
label : str | uuid.UUID
|
|
97
|
+
The name or ID of the sensitivity label.
|
|
98
|
+
user : str | uuid.UUID, default=None
|
|
99
|
+
The user ID or user principal name.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
uuid.UUID | None
|
|
104
|
+
The ID of the sensitivity label if found, otherwise None.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
if _is_valid_uuid(label):
|
|
108
|
+
return str(label)
|
|
109
|
+
|
|
110
|
+
df = list_sensitivity_labels(user=user)
|
|
111
|
+
|
|
112
|
+
if df.empty:
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
# Try to find the label by name
|
|
116
|
+
label_row = df[df["Sensitivity Label Name"] == label]
|
|
117
|
+
if not label_row.empty:
|
|
118
|
+
return label_row["Sensitivity Label Id"].iloc[0]
|
|
119
|
+
|
|
120
|
+
return None
|
sempy_labs/graph/_teams.py
CHANGED
|
@@ -23,7 +23,7 @@ def list_teams() -> pd.DataFrame:
|
|
|
23
23
|
A pandas dataframe showing a list of teams and their properties.
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
-
result = _base_api(request="teams", client="graph")
|
|
26
|
+
result = _base_api(request="teams", client="graph", uses_pagination=True)
|
|
27
27
|
|
|
28
28
|
columns = {
|
|
29
29
|
"Team Id": "str",
|
|
@@ -43,23 +43,24 @@ def list_teams() -> pd.DataFrame:
|
|
|
43
43
|
df = _create_dataframe(columns=columns)
|
|
44
44
|
|
|
45
45
|
rows = []
|
|
46
|
-
for
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
for r in result:
|
|
47
|
+
for v in r.get("value", []):
|
|
48
|
+
rows.append(
|
|
49
|
+
{
|
|
50
|
+
"Team Id": v.get("id"),
|
|
51
|
+
"Team Name": v.get("displayName"),
|
|
52
|
+
"Description": v.get("description"),
|
|
53
|
+
"Creation Date Time": v.get("createdDateTime"),
|
|
54
|
+
"Classification": v.get("classification"),
|
|
55
|
+
"Specialization": v.get("specialization"),
|
|
56
|
+
"Visibility": v.get("visibility"),
|
|
57
|
+
"Web Url": v.get("webUrl"),
|
|
58
|
+
"Archived": v.get("isArchived"),
|
|
59
|
+
"Favorite By Me": v.get("isFavoriteByMe"),
|
|
60
|
+
"Discoverable By Me": v.get("isDiscoverableByMe"),
|
|
61
|
+
"Member Count": v.get("memberCount"),
|
|
62
|
+
}
|
|
63
|
+
)
|
|
63
64
|
|
|
64
65
|
if rows:
|
|
65
66
|
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from uuid import UUID
|
|
2
|
+
import sempy_labs._icons as icons
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from sempy_labs._helper_functions import (
|
|
5
|
+
_base_api,
|
|
6
|
+
)
|
|
7
|
+
from sempy._utils._log import log
|
|
8
|
+
from sempy_labs.graph._users import resolve_user_id
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@log
|
|
12
|
+
def add_user_license(
|
|
13
|
+
user: str | UUID, sku_id: UUID, disabled_plans: Optional[UUID | List[UUID]] = None
|
|
14
|
+
):
|
|
15
|
+
"""
|
|
16
|
+
Assigns a license to a user.
|
|
17
|
+
|
|
18
|
+
This is a wrapper function for the following API: `user: assignLicense <https://learn.microsoft.com/graph/api/user-assignlicense>`_.
|
|
19
|
+
|
|
20
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
user : str | uuid.UUID
|
|
25
|
+
The user ID or user principal name.
|
|
26
|
+
sku_id : uuid.UUID
|
|
27
|
+
The SKU ID of the license to assign.
|
|
28
|
+
disabled_plans : Optional[uuid.UUID | List[uuid.UUID]], default=None
|
|
29
|
+
A single service plan ID or a list of service plan IDs to disable within the assigned license.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
user_id = resolve_user_id(user)
|
|
33
|
+
|
|
34
|
+
payload = {
|
|
35
|
+
"addLicenses": [
|
|
36
|
+
{
|
|
37
|
+
"skuId": sku_id,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
"removeLicenses": [],
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if disabled_plans:
|
|
44
|
+
if isinstance(disabled_plans, str):
|
|
45
|
+
disabled_plans = [disabled_plans]
|
|
46
|
+
payload["addLicenses"][0]["disabledPlans"] = disabled_plans
|
|
47
|
+
|
|
48
|
+
_base_api(
|
|
49
|
+
request=f"users/{user_id}/assignLicense",
|
|
50
|
+
client="graph",
|
|
51
|
+
method="post",
|
|
52
|
+
payload=payload,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
print(
|
|
56
|
+
f"{icons.green_dot} The '{sku_id}' license has been assigned to the user '{user}'."
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@log
|
|
61
|
+
def remove_user_license(user: str | UUID, sku_ids: UUID | List[UUID]):
|
|
62
|
+
"""
|
|
63
|
+
Removes a license from a user.
|
|
64
|
+
|
|
65
|
+
This is a wrapper function for the following API: `user: assignLicense <https://learn.microsoft.com/graph/api/user-assignlicense>`_.
|
|
66
|
+
|
|
67
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
user : str | uuid.UUID
|
|
72
|
+
The user ID or user principal name.
|
|
73
|
+
sku_id : uuid.UUID
|
|
74
|
+
The SKU ID of the license to remove.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
user_id = resolve_user_id(user)
|
|
78
|
+
|
|
79
|
+
if isinstance(sku_ids, str):
|
|
80
|
+
sku_ids = [sku_ids]
|
|
81
|
+
|
|
82
|
+
payload = {
|
|
83
|
+
"addLicenses": [],
|
|
84
|
+
"removeLicenses": sku_ids,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_base_api(
|
|
88
|
+
request=f"users/{user_id}/assignLicense",
|
|
89
|
+
client="graph",
|
|
90
|
+
method="post",
|
|
91
|
+
payload=payload,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
print(
|
|
95
|
+
f"{icons.green_dot} The '{', '.join([str(s) for s in sku_ids])}' license(s) have been removed from the user '{user}'."
|
|
96
|
+
)
|
sempy_labs/graph/_users.py
CHANGED
|
@@ -8,6 +8,7 @@ from .._helper_functions import (
|
|
|
8
8
|
_is_valid_uuid,
|
|
9
9
|
_base_api,
|
|
10
10
|
_create_dataframe,
|
|
11
|
+
_update_dataframe_datatypes,
|
|
11
12
|
_mount,
|
|
12
13
|
)
|
|
13
14
|
from sempy._utils._log import log
|
|
@@ -39,7 +40,7 @@ def resolve_user_id(user: str | UUID) -> UUID:
|
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
@log
|
|
42
|
-
def get_user(user: str | UUID) -> pd.DataFrame:
|
|
43
|
+
def get_user(user: str | UUID, show_manager: bool = False) -> pd.DataFrame:
|
|
43
44
|
"""
|
|
44
45
|
Shows properties of a given user.
|
|
45
46
|
|
|
@@ -51,6 +52,8 @@ def get_user(user: str | UUID) -> pd.DataFrame:
|
|
|
51
52
|
----------
|
|
52
53
|
user : str | uuid.UUID
|
|
53
54
|
The user ID or user principal name.
|
|
55
|
+
show_manager : bool, default=False
|
|
56
|
+
Whether to include the user's manager information.
|
|
54
57
|
|
|
55
58
|
Returns
|
|
56
59
|
-------
|
|
@@ -58,7 +61,11 @@ def get_user(user: str | UUID) -> pd.DataFrame:
|
|
|
58
61
|
A pandas dataframe showing properties of a given user.
|
|
59
62
|
"""
|
|
60
63
|
|
|
61
|
-
|
|
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()
|
|
62
69
|
|
|
63
70
|
new_data = {
|
|
64
71
|
"User Id": result.get("id"),
|
|
@@ -71,13 +78,22 @@ def get_user(user: str | UUID) -> pd.DataFrame:
|
|
|
71
78
|
"Business Phones": str(result.get("businessPhones")),
|
|
72
79
|
"Preferred Language": result.get("preferredLanguage"),
|
|
73
80
|
"Surname": result.get("surname"),
|
|
81
|
+
"Department": result.get("department"),
|
|
74
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
|
+
}
|
|
75
91
|
|
|
76
92
|
return pd.DataFrame([new_data])
|
|
77
93
|
|
|
78
94
|
|
|
79
95
|
@log
|
|
80
|
-
def list_users() -> pd.DataFrame:
|
|
96
|
+
def list_users(show_manager: bool = False) -> pd.DataFrame:
|
|
81
97
|
"""
|
|
82
98
|
Shows a list of users and their properties.
|
|
83
99
|
|
|
@@ -85,13 +101,21 @@ def list_users() -> pd.DataFrame:
|
|
|
85
101
|
|
|
86
102
|
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
87
103
|
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
show_manager : bool, default=False
|
|
107
|
+
Whether to include the user's manager information.
|
|
108
|
+
|
|
88
109
|
Returns
|
|
89
110
|
-------
|
|
90
111
|
pandas.DataFrame
|
|
91
112
|
A pandas dataframe showing a list of users and their properties.
|
|
92
113
|
"""
|
|
93
114
|
|
|
94
|
-
|
|
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)
|
|
95
119
|
|
|
96
120
|
columns = {
|
|
97
121
|
"User Id": "string",
|
|
@@ -104,25 +128,52 @@ def list_users() -> pd.DataFrame:
|
|
|
104
128
|
"Business Phones": "string",
|
|
105
129
|
"Preferred Language": "string",
|
|
106
130
|
"Surname": "string",
|
|
131
|
+
"Department": "string",
|
|
107
132
|
}
|
|
108
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
|
+
|
|
109
144
|
df = _create_dataframe(columns=columns)
|
|
110
145
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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)
|
|
124
173
|
|
|
125
|
-
|
|
174
|
+
if rows:
|
|
175
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
176
|
+
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
126
177
|
|
|
127
178
|
return df
|
|
128
179
|
|
|
@@ -33,6 +33,7 @@ def get_lakehouse_tables(
|
|
|
33
33
|
extended: bool = False,
|
|
34
34
|
count_rows: bool = False,
|
|
35
35
|
export: bool = False,
|
|
36
|
+
exclude_shortcuts: bool = False,
|
|
36
37
|
) -> pd.DataFrame:
|
|
37
38
|
"""
|
|
38
39
|
Shows the tables of a lakehouse and their respective properties. Option to include additional properties relevant to Direct Lake guardrails.
|
|
@@ -60,6 +61,8 @@ def get_lakehouse_tables(
|
|
|
60
61
|
Obtains a row count for each lakehouse table.
|
|
61
62
|
export : bool, default=False
|
|
62
63
|
Exports the resulting dataframe to a delta table in the lakehouse.
|
|
64
|
+
exclude_shortcuts : bool, default=False
|
|
65
|
+
If True, excludes shortcuts.
|
|
63
66
|
|
|
64
67
|
Returns
|
|
65
68
|
-------
|
|
@@ -83,6 +86,9 @@ def get_lakehouse_tables(
|
|
|
83
86
|
lakehouse=lakehouse, workspace=workspace_id
|
|
84
87
|
)
|
|
85
88
|
|
|
89
|
+
# Test if valid lakehouse:
|
|
90
|
+
x = _base_api(f"v1/workspaces/{workspace_id}/lakehouses/{lakehouse_id}")
|
|
91
|
+
|
|
86
92
|
if count_rows: # Setting countrows defaults to extended=True
|
|
87
93
|
extended = True
|
|
88
94
|
|
|
@@ -94,7 +100,7 @@ def get_lakehouse_tables(
|
|
|
94
100
|
client="fabric_sp",
|
|
95
101
|
)
|
|
96
102
|
|
|
97
|
-
except Exception
|
|
103
|
+
except Exception:
|
|
98
104
|
API_called = False
|
|
99
105
|
|
|
100
106
|
rows = []
|
|
@@ -246,6 +252,32 @@ def get_lakehouse_tables(
|
|
|
246
252
|
df["Row Count"] = df["Row Count"].astype(int)
|
|
247
253
|
df["Row Count Guardrail Hit"] = df["Row Count"] > df["Row Count Guardrail"]
|
|
248
254
|
|
|
255
|
+
if exclude_shortcuts:
|
|
256
|
+
from sempy_labs.lakehouse._shortcuts import list_shortcuts
|
|
257
|
+
|
|
258
|
+
# Exclude shortcuts
|
|
259
|
+
shortcuts = (
|
|
260
|
+
list_shortcuts(lakehouse=lakehouse, workspace=workspace)
|
|
261
|
+
.query("`Shortcut Path`.str.startswith('/Tables')", engine="python")
|
|
262
|
+
.assign(
|
|
263
|
+
FullPath=lambda df: df["Shortcut Path"].str.rstrip("/")
|
|
264
|
+
+ "/"
|
|
265
|
+
+ df["Shortcut Name"]
|
|
266
|
+
)["FullPath"]
|
|
267
|
+
.tolist()
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
df["FullPath"] = df.apply(
|
|
271
|
+
lambda x: (
|
|
272
|
+
f"/Tables/{x['Table Name']}"
|
|
273
|
+
if pd.isna(x["Schema Name"]) or x["Schema Name"] == ""
|
|
274
|
+
else f"/Tables/{x['Schema Name']}/{x['Table Name']}"
|
|
275
|
+
),
|
|
276
|
+
axis=1,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
df = df[~df["FullPath"].isin(shortcuts)].reset_index(drop=True)
|
|
280
|
+
|
|
249
281
|
if export:
|
|
250
282
|
if not lakehouse_attached():
|
|
251
283
|
raise ValueError(
|
|
@@ -93,7 +93,9 @@ def optimize_lakehouse_tables(
|
|
|
93
93
|
|
|
94
94
|
from sempy_labs.lakehouse._get_lakehouse_tables import get_lakehouse_tables
|
|
95
95
|
|
|
96
|
-
df = get_lakehouse_tables(
|
|
96
|
+
df = get_lakehouse_tables(
|
|
97
|
+
lakehouse=lakehouse, workspace=workspace, exclude_shortcuts=True
|
|
98
|
+
)
|
|
97
99
|
df_delta = df[df["Format"] == "delta"]
|
|
98
100
|
|
|
99
101
|
if isinstance(tables, str):
|
|
@@ -142,7 +144,9 @@ def vacuum_lakehouse_tables(
|
|
|
142
144
|
|
|
143
145
|
from sempy_labs.lakehouse._get_lakehouse_tables import get_lakehouse_tables
|
|
144
146
|
|
|
145
|
-
df = get_lakehouse_tables(
|
|
147
|
+
df = get_lakehouse_tables(
|
|
148
|
+
lakehouse=lakehouse, workspace=workspace, exclude_shortcuts=True
|
|
149
|
+
)
|
|
146
150
|
df_delta = df[df["Format"] == "delta"]
|
|
147
151
|
|
|
148
152
|
if isinstance(tables, str):
|