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.

Files changed (47) hide show
  1. {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/METADATA +5 -3
  2. {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/RECORD +45 -37
  3. sempy_labs/__init__.py +20 -16
  4. sempy_labs/_a_lib_info.py +1 -1
  5. sempy_labs/_authentication.py +1 -1
  6. sempy_labs/_capacities.py +1 -1
  7. sempy_labs/_dataflows.py +98 -10
  8. sempy_labs/_git.py +1 -1
  9. sempy_labs/_helper_functions.py +32 -5
  10. sempy_labs/_list_functions.py +55 -5
  11. sempy_labs/_managed_private_endpoints.py +63 -1
  12. sempy_labs/_model_bpa.py +6 -0
  13. sempy_labs/_notebooks.py +4 -2
  14. sempy_labs/_onelake.py +131 -0
  15. sempy_labs/_sql_audit_settings.py +208 -0
  16. sempy_labs/_sql_endpoints.py +18 -3
  17. sempy_labs/_utils.py +2 -0
  18. sempy_labs/admin/__init__.py +6 -0
  19. sempy_labs/admin/_basic_functions.py +17 -13
  20. sempy_labs/admin/_items.py +3 -3
  21. sempy_labs/admin/_labels.py +211 -0
  22. sempy_labs/admin/_workspaces.py +2 -2
  23. sempy_labs/deployment_pipeline/__init__.py +21 -0
  24. sempy_labs/deployment_pipeline/_items.py +486 -0
  25. sempy_labs/directlake/_update_directlake_partition_entity.py +73 -41
  26. sempy_labs/directlake/_warm_cache.py +3 -1
  27. sempy_labs/eventstream/__init__.py +37 -0
  28. sempy_labs/eventstream/_items.py +263 -0
  29. sempy_labs/eventstream/_topology.py +652 -0
  30. sempy_labs/graph/__init__.py +10 -0
  31. sempy_labs/graph/_groups.py +123 -53
  32. sempy_labs/graph/_sensitivity_labels.py +39 -0
  33. sempy_labs/graph/_teams.py +19 -18
  34. sempy_labs/graph/_user_licenses.py +96 -0
  35. sempy_labs/graph/_users.py +69 -18
  36. sempy_labs/lakehouse/_get_lakehouse_tables.py +33 -1
  37. sempy_labs/lakehouse/_lakehouse.py +6 -2
  38. sempy_labs/lakehouse/_partitioning.py +165 -0
  39. sempy_labs/report/_export_report.py +0 -22
  40. sempy_labs/report/_report_rebind.py +29 -43
  41. sempy_labs/report/_reportwrapper.py +80 -35
  42. sempy_labs/tom/_model.py +81 -4
  43. sempy_labs/_deployment_pipelines.py +0 -209
  44. sempy_labs/_eventstreams.py +0 -123
  45. {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/WHEEL +0 -0
  46. {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/licenses/LICENSE +0 -0
  47. {semantic_link_labs-0.12.3.dist-info → semantic_link_labs-0.12.5.dist-info}/top_level.txt +0 -0
@@ -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").json()
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 v in result.get("value"):
80
- rows.append(
81
- {
82
- "Group Id": v.get("id"),
83
- "Group Name": v.get("displayName"),
84
- "Mail": v.get("mail"),
85
- "Description": v.get("description"),
86
- "Classification": v.get("classification"),
87
- "Mail Enabled": v.get("mailEnabled"),
88
- "Security Enabled": v.get("securityEnabled"),
89
- "Created Date Time": v.get("createdDateTime"),
90
- "Expiration Date Time": v.get("expirationDateTime"),
91
- "Renewed Date Time": v.get("renewedDateTime"),
92
- "Deleted Date Time": v.get("deletedDateTime"),
93
- "Visibility": v.get("visibility"),
94
- "Security Identifier": v.get("securityIdentifier"),
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(request=f"groups/{group_id}/members", client="graph").json()
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 v in result.get("value"):
213
- rows.append(
214
- {
215
- "Member Id": v.get("id"),
216
- "Member Name": v.get("displayName"),
217
- "User Principal Name": v.get("userPrincipalName"),
218
- "Mail": v.get("mail"),
219
- "Job Title": v.get("jobTitle"),
220
- "Office Location": v.get("officeLocation"),
221
- "Mobile Phone": v.get("mobilePhone"),
222
- "Business Phones": str(v.get("businessPhones")),
223
- "Preferred Language": v.get("preferredLanguage"),
224
- "Given Name": v.get("givenName"),
225
- "Surname": v.get("surname"),
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(request=f"groups/{group_id}/owners", client="graph").json()
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 v in result.get("value"):
277
- rows.append(
278
- {
279
- "Owner Id": v.get("id"),
280
- "Owner Name": v.get("displayName"),
281
- "User Principal Name": v.get("userPrincipalName"),
282
- "Mail": v.get("mail"),
283
- "Job Title": v.get("jobTitle"),
284
- "Office Location": v.get("officeLocation"),
285
- "Mobile Phone": v.get("mobilePhone"),
286
- "Business Phones": str(v.get("businessPhones")),
287
- "Preferred Language": v.get("preferredLanguage"),
288
- "Given Name": v.get("givenName"),
289
- "Surname": v.get("surname"),
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
@@ -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").json()
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 v in result.get("value"):
47
- rows.append(
48
- {
49
- "Team Id": v.get("id"),
50
- "Team Name": v.get("displayName"),
51
- "Description": v.get("description"),
52
- "Creation Date Time": v.get("createdDateTime"),
53
- "Classification": v.get("classification"),
54
- "Specialization": v.get("specialization"),
55
- "Visibility": v.get("visibility"),
56
- "Web Url": v.get("webUrl"),
57
- "Archived": v.get("isArchived"),
58
- "Favorite By Me": v.get("isFavoriteByMe"),
59
- "Discoverable By Me": v.get("isDiscoverableByMe"),
60
- "Member Count": v.get("memberCount"),
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
+ )
@@ -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
- result = _base_api(request=f"users/{user}", client="graph").json()
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
- result = _base_api(request="users", client="graph").json()
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
- for v in result.get("value"):
112
- new_data = {
113
- "User Id": v.get("id"),
114
- "User Principal Name": v.get("userPrincipalName"),
115
- "User Name": v.get("displayName"),
116
- "Mail": v.get("mail"),
117
- "Job Title": v.get("jobTitle"),
118
- "Office Location": v.get("officeLocation"),
119
- "Mobile Phone": v.get("mobilePhone"),
120
- "Business Phones": str(v.get("businessPhones")),
121
- "Preferred Language": v.get("preferredLanguage"),
122
- "Surname": v.get("surname"),
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
- df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)
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 as e:
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(lakehouse=lakehouse, workspace=workspace)
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(lakehouse=lakehouse, workspace=workspace)
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):