tableauserverclient 0.32__py3-none-any.whl → 0.34__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.
Files changed (96) hide show
  1. tableauserverclient/__init__.py +34 -18
  2. tableauserverclient/_version.py +3 -3
  3. tableauserverclient/config.py +20 -6
  4. tableauserverclient/models/__init__.py +12 -0
  5. tableauserverclient/models/column_item.py +1 -1
  6. tableauserverclient/models/connection_credentials.py +1 -1
  7. tableauserverclient/models/connection_item.py +10 -8
  8. tableauserverclient/models/custom_view_item.py +29 -6
  9. tableauserverclient/models/data_acceleration_report_item.py +2 -2
  10. tableauserverclient/models/data_alert_item.py +5 -5
  11. tableauserverclient/models/data_freshness_policy_item.py +6 -6
  12. tableauserverclient/models/database_item.py +8 -2
  13. tableauserverclient/models/datasource_item.py +10 -10
  14. tableauserverclient/models/dqw_item.py +1 -1
  15. tableauserverclient/models/favorites_item.py +5 -6
  16. tableauserverclient/models/fileupload_item.py +1 -1
  17. tableauserverclient/models/flow_item.py +12 -12
  18. tableauserverclient/models/flow_run_item.py +3 -3
  19. tableauserverclient/models/group_item.py +4 -4
  20. tableauserverclient/models/groupset_item.py +53 -0
  21. tableauserverclient/models/interval_item.py +36 -23
  22. tableauserverclient/models/job_item.py +26 -10
  23. tableauserverclient/models/linked_tasks_item.py +102 -0
  24. tableauserverclient/models/metric_item.py +5 -5
  25. tableauserverclient/models/pagination_item.py +1 -1
  26. tableauserverclient/models/permissions_item.py +19 -14
  27. tableauserverclient/models/project_item.py +35 -19
  28. tableauserverclient/models/property_decorators.py +12 -11
  29. tableauserverclient/models/reference_item.py +2 -2
  30. tableauserverclient/models/revision_item.py +3 -3
  31. tableauserverclient/models/schedule_item.py +2 -2
  32. tableauserverclient/models/server_info_item.py +26 -6
  33. tableauserverclient/models/site_item.py +69 -3
  34. tableauserverclient/models/subscription_item.py +3 -3
  35. tableauserverclient/models/table_item.py +1 -1
  36. tableauserverclient/models/tableau_auth.py +115 -5
  37. tableauserverclient/models/tableau_types.py +11 -9
  38. tableauserverclient/models/tag_item.py +3 -4
  39. tableauserverclient/models/task_item.py +4 -4
  40. tableauserverclient/models/user_item.py +47 -17
  41. tableauserverclient/models/view_item.py +11 -10
  42. tableauserverclient/models/virtual_connection_item.py +78 -0
  43. tableauserverclient/models/webhook_item.py +6 -6
  44. tableauserverclient/models/workbook_item.py +90 -12
  45. tableauserverclient/namespace.py +1 -1
  46. tableauserverclient/server/__init__.py +2 -1
  47. tableauserverclient/server/endpoint/__init__.py +8 -0
  48. tableauserverclient/server/endpoint/auth_endpoint.py +68 -11
  49. tableauserverclient/server/endpoint/custom_views_endpoint.py +124 -19
  50. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
  51. tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
  52. tableauserverclient/server/endpoint/databases_endpoint.py +32 -17
  53. tableauserverclient/server/endpoint/datasources_endpoint.py +150 -59
  54. tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
  55. tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
  56. tableauserverclient/server/endpoint/endpoint.py +47 -31
  57. tableauserverclient/server/endpoint/exceptions.py +23 -7
  58. tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
  59. tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -13
  60. tableauserverclient/server/endpoint/flow_runs_endpoint.py +59 -17
  61. tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
  62. tableauserverclient/server/endpoint/flows_endpoint.py +73 -35
  63. tableauserverclient/server/endpoint/groups_endpoint.py +96 -27
  64. tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
  65. tableauserverclient/server/endpoint/jobs_endpoint.py +79 -12
  66. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
  67. tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
  68. tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
  69. tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
  70. tableauserverclient/server/endpoint/projects_endpoint.py +124 -30
  71. tableauserverclient/server/endpoint/resource_tagger.py +139 -6
  72. tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
  73. tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
  74. tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
  75. tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
  76. tableauserverclient/server/endpoint/tables_endpoint.py +33 -19
  77. tableauserverclient/server/endpoint/tasks_endpoint.py +8 -8
  78. tableauserverclient/server/endpoint/users_endpoint.py +405 -19
  79. tableauserverclient/server/endpoint/views_endpoint.py +111 -25
  80. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +174 -0
  81. tableauserverclient/server/endpoint/webhooks_endpoint.py +11 -11
  82. tableauserverclient/server/endpoint/workbooks_endpoint.py +735 -68
  83. tableauserverclient/server/filter.py +2 -2
  84. tableauserverclient/server/pager.py +8 -10
  85. tableauserverclient/server/query.py +70 -20
  86. tableauserverclient/server/request_factory.py +213 -41
  87. tableauserverclient/server/request_options.py +125 -145
  88. tableauserverclient/server/server.py +73 -9
  89. tableauserverclient/server/sort.py +2 -2
  90. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/METADATA +17 -17
  91. tableauserverclient-0.34.dist-info/RECORD +106 -0
  92. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/WHEEL +1 -1
  93. tableauserverclient-0.32.dist-info/RECORD +0 -100
  94. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE +0 -0
  95. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE.versioneer +0 -0
  96. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,8 @@
1
1
  import copy
2
2
  import logging
3
- from typing import List, Optional, Tuple
3
+ from typing import Optional
4
+
5
+ from tableauserverclient.server.query import QuerySet
4
6
 
5
7
  from .endpoint import QuerysetEndpoint, api
6
8
  from .exceptions import MissingRequiredFieldError, ServerResponseError
@@ -12,13 +14,75 @@ from tableauserverclient.helpers.logging import logger
12
14
 
13
15
 
14
16
  class Users(QuerysetEndpoint[UserItem]):
17
+ """
18
+ The user resources for Tableau Server are defined in the UserItem class.
19
+ The class corresponds to the user resources you can access using the
20
+ Tableau Server REST API. The user methods are based upon the endpoints for
21
+ users in the REST API and operate on the UserItem class. Only server and
22
+ site administrators can access the user resources.
23
+ """
24
+
15
25
  @property
16
26
  def baseurl(self) -> str:
17
- return "{0}/sites/{1}/users".format(self.parent_srv.baseurl, self.parent_srv.site_id)
27
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/users"
18
28
 
19
29
  # Gets all users
20
30
  @api(version="2.0")
21
- def get(self, req_options: Optional[RequestOptions] = None) -> Tuple[List[UserItem], PaginationItem]:
31
+ def get(self, req_options: Optional[RequestOptions] = None) -> tuple[list[UserItem], PaginationItem]:
32
+ """
33
+ Query all users on the site. Request is paginated and returns a subset of users.
34
+ By default, the request returns the first 100 users on the site.
35
+
36
+ Parameters
37
+ ----------
38
+ req_options : Optional[RequestOptions]
39
+ Optional request options to filter and sort the results.
40
+
41
+ Returns
42
+ -------
43
+ tuple[list[UserItem], PaginationItem]
44
+ Returns a tuple with a list of UserItem objects and a PaginationItem object.
45
+
46
+ Raises
47
+ ------
48
+ ServerResponseError
49
+ code: 400006
50
+ summary: Invalid page number
51
+ detail: The page number is not an integer, is less than one, or is
52
+ greater than the final page number for users at the requested
53
+ page size.
54
+
55
+ ServerResponseError
56
+ code: 400007
57
+ summary: Invalid page size
58
+ detail: The page size parameter is not an integer, is less than one.
59
+
60
+ ServerResponseError
61
+ code: 403014
62
+ summary: Page size limit exceeded
63
+ detail: The specified page size is larger than the maximum page size
64
+
65
+ ServerResponseError
66
+ code: 404000
67
+ summary: Site not found
68
+ detail: The site ID in the URI doesn't correspond to an existing site.
69
+
70
+ ServerResponseError
71
+ code: 405000
72
+ summary: Invalid request method
73
+ detail: Request type was not GET.
74
+
75
+ Examples
76
+ --------
77
+ >>> import tableauserverclient as TSC
78
+ >>> tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD')
79
+ >>> server = TSC.Server('https://SERVERURL')
80
+
81
+ >>> with server.auth.sign_in(tableau_auth):
82
+ >>> users_page, pagination_item = server.users.get()
83
+ >>> print("\nThere are {} user on site: ".format(pagination_item.total_available))
84
+ >>> print([user.name for user in users_page])
85
+ """
22
86
  logger.info("Querying all users on site")
23
87
 
24
88
  if req_options is None:
@@ -34,55 +98,253 @@ class Users(QuerysetEndpoint[UserItem]):
34
98
  # Gets 1 user by id
35
99
  @api(version="2.0")
36
100
  def get_by_id(self, user_id: str) -> UserItem:
101
+ """
102
+ Query a single user by ID.
103
+
104
+ Parameters
105
+ ----------
106
+ user_id : str
107
+ The ID of the user to query.
108
+
109
+ Returns
110
+ -------
111
+ UserItem
112
+ The user item that was queried.
113
+
114
+ Raises
115
+ ------
116
+ ValueError
117
+ If the user ID is not specified.
118
+
119
+ ServerResponseError
120
+ code: 404000
121
+ summary: Site not found
122
+ detail: The site ID in the URI doesn't correspond to an existing site.
123
+
124
+ ServerResponseError
125
+ code: 403133
126
+ summary: Query user permissions forbidden
127
+ detail: The user does not have permissions to query user information
128
+ for other users
129
+
130
+ ServerResponseError
131
+ code: 404002
132
+ summary: User not found
133
+ detail: The user ID in the URI doesn't correspond to an existing user.
134
+
135
+ ServerResponseError
136
+ code: 405000
137
+ summary: Invalid request method
138
+ detail: Request type was not GET.
139
+
140
+ Examples
141
+ --------
142
+ >>> user1 = server.users.get_by_id('9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d')
143
+ """
37
144
  if not user_id:
38
145
  error = "User ID undefined."
39
146
  raise ValueError(error)
40
- logger.info("Querying single user (ID: {0})".format(user_id))
41
- url = "{0}/{1}".format(self.baseurl, user_id)
147
+ logger.info(f"Querying single user (ID: {user_id})")
148
+ url = f"{self.baseurl}/{user_id}"
42
149
  server_response = self.get_request(url)
43
150
  return UserItem.from_response(server_response.content, self.parent_srv.namespace).pop()
44
151
 
45
152
  # Update user
46
153
  @api(version="2.0")
47
154
  def update(self, user_item: UserItem, password: Optional[str] = None) -> UserItem:
155
+ """
156
+ Modifies information about the specified user.
157
+
158
+ If Tableau Server is configured to use local authentication, you can
159
+ update the user's name, email address, password, or site role.
160
+
161
+ If Tableau Server is configured to use Active Directory
162
+ authentication, you can change the user's display name (full name),
163
+ email address, and site role. However, if you synchronize the user with
164
+ Active Directory, the display name and email address will be
165
+ overwritten with the information that's in Active Directory.
166
+
167
+ For Tableau Cloud, you can update the site role for a user, but you
168
+ cannot update or change a user's password, user name (email address),
169
+ or full name.
170
+
171
+ Parameters
172
+ ----------
173
+ user_item : UserItem
174
+ The user item to update.
175
+
176
+ password : Optional[str]
177
+ The new password for the user.
178
+
179
+ Returns
180
+ -------
181
+ UserItem
182
+ The user item that was updated.
183
+
184
+ Raises
185
+ ------
186
+ MissingRequiredFieldError
187
+ If the user item is missing an ID.
188
+
189
+ Examples
190
+ --------
191
+ >>> user = server.users.get_by_id('9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d')
192
+ >>> user.fullname = 'New Full Name'
193
+ >>> updated_user = server.users.update(user)
194
+
195
+ """
48
196
  if not user_item.id:
49
197
  error = "User item missing ID."
50
198
  raise MissingRequiredFieldError(error)
51
199
 
52
- url = "{0}/{1}".format(self.baseurl, user_item.id)
200
+ url = f"{self.baseurl}/{user_item.id}"
53
201
  update_req = RequestFactory.User.update_req(user_item, password)
54
202
  server_response = self.put_request(url, update_req)
55
- logger.info("Updated user item (ID: {0})".format(user_item.id))
203
+ logger.info(f"Updated user item (ID: {user_item.id})")
56
204
  updated_item = copy.copy(user_item)
57
205
  return updated_item._parse_common_tags(server_response.content, self.parent_srv.namespace)
58
206
 
59
207
  # Delete 1 user by id
60
208
  @api(version="2.0")
61
209
  def remove(self, user_id: str, map_assets_to: Optional[str] = None) -> None:
210
+ """
211
+ Removes a user from the site. You can also specify a user to map the
212
+ assets to when you remove the user.
213
+
214
+ Parameters
215
+ ----------
216
+ user_id : str
217
+ The ID of the user to remove.
218
+
219
+ map_assets_to : Optional[str]
220
+ The ID of the user to map the assets to when you remove the user.
221
+
222
+ Returns
223
+ -------
224
+ None
225
+
226
+ Raises
227
+ ------
228
+ ValueError
229
+ If the user ID is not specified.
230
+
231
+ Examples
232
+ --------
233
+ >>> server.users.remove('9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d')
234
+ """
62
235
  if not user_id:
63
236
  error = "User ID undefined."
64
237
  raise ValueError(error)
65
- url = "{0}/{1}".format(self.baseurl, user_id)
238
+ url = f"{self.baseurl}/{user_id}"
66
239
  if map_assets_to is not None:
67
240
  url += f"?mapAssetsTo={map_assets_to}"
68
241
  self.delete_request(url)
69
- logger.info("Removed single user (ID: {0})".format(user_id))
242
+ logger.info(f"Removed single user (ID: {user_id})")
70
243
 
71
244
  # Add new user to site
72
245
  @api(version="2.0")
73
246
  def add(self, user_item: UserItem) -> UserItem:
247
+ """
248
+ Adds the user to the site.
249
+
250
+ To add a new user to the site you need to first create a new user_item
251
+ (from UserItem class). When you create a new user, you specify the name
252
+ of the user and their site role. For Tableau Cloud, you also specify
253
+ the auth_setting attribute in your request. When you add user to
254
+ Tableau Cloud, the name of the user must be the email address that is
255
+ used to sign in to Tableau Cloud. After you add a user, Tableau Cloud
256
+ sends the user an email invitation. The user can click the link in the
257
+ invitation to sign in and update their full name and password.
258
+
259
+ Parameters
260
+ ----------
261
+ user_item : UserItem
262
+ The user item to add to the site.
263
+
264
+ Returns
265
+ -------
266
+ UserItem
267
+ The user item that was added to the site with attributes from the
268
+ site populated.
269
+
270
+ Raises
271
+ ------
272
+ ValueError
273
+ If the user item is missing a name
274
+
275
+ ValueError
276
+ If the user item is missing a site role
277
+
278
+ ServerResponseError
279
+ code: 400000
280
+ summary: Bad Request
281
+ detail: The content of the request body is missing or incomplete, or
282
+ contains malformed XML.
283
+
284
+ ServerResponseError
285
+ code: 400003
286
+ summary: Bad Request
287
+ detail: The user authentication setting ServerDefault is not
288
+ supported for you site. Try again using TableauIDWithMFA instead.
289
+
290
+ ServerResponseError
291
+ code: 400013
292
+ summary: Invalid site role
293
+ detail: The value of the siteRole attribute must be Explorer,
294
+ ExplorerCanPublish, SiteAdministratorCreator,
295
+ SiteAdministratorExplorer, Unlicensed, or Viewer.
296
+
297
+ ServerResponseError
298
+ code: 404000
299
+ summary: Site not found
300
+ detail: The site ID in the URI doesn't correspond to an existing site.
301
+
302
+ ServerResponseError
303
+ code: 404002
304
+ summary: User not found
305
+ detail: The server is configured to use Active Directory for
306
+ authentication, and the username specified in the request body
307
+ doesn't match an existing user in Active Directory.
308
+
309
+ ServerResponseError
310
+ code: 405000
311
+ summary: Invalid request method
312
+ detail: Request type was not POST.
313
+
314
+ ServerResponseError
315
+ code: 409000
316
+ summary: User conflict
317
+ detail: The specified user already exists on the site.
318
+
319
+ ServerResponseError
320
+ code: 409005
321
+ summary: Guest user conflict
322
+ detail: The Tableau Server API doesn't allow adding a user with the
323
+ guest role to a site.
324
+
325
+
326
+ Examples
327
+ --------
328
+ >>> import tableauserverclient as TSC
329
+ >>> server = TSC.Server('https://SERVERURL')
330
+ >>> # Login to the server
331
+
332
+ >>> new_user = TSC.UserItem(name='new_user', site_role=TSC.UserItem.Role.Unlicensed)
333
+ >>> new_user = server.users.add(new_user)
334
+
335
+ """
74
336
  url = self.baseurl
75
- logger.info("Add user {}".format(user_item.name))
337
+ logger.info(f"Add user {user_item.name}")
76
338
  add_req = RequestFactory.User.add_req(user_item)
77
339
  server_response = self.post_request(url, add_req)
78
340
  logger.info(server_response)
79
341
  new_user = UserItem.from_response(server_response.content, self.parent_srv.namespace).pop()
80
- logger.info("Added new user (ID: {0})".format(new_user.id))
342
+ logger.info(f"Added new user (ID: {new_user.id})")
81
343
  return new_user
82
344
 
83
345
  # Add new users to site. This does not actually perform a bulk action, it's syntactic sugar
84
346
  @api(version="2.0")
85
- def add_all(self, users: List[UserItem]):
347
+ def add_all(self, users: list[UserItem]):
86
348
  created = []
87
349
  failed = []
88
350
  for user in users:
@@ -96,7 +358,7 @@ class Users(QuerysetEndpoint[UserItem]):
96
358
  # helping the user by parsing a file they could have used to add users through the UI
97
359
  # line format: Username [required], password, display name, license, admin, publish
98
360
  @api(version="2.0")
99
- def create_from_file(self, filepath: str) -> Tuple[List[UserItem], List[Tuple[UserItem, ServerResponseError]]]:
361
+ def create_from_file(self, filepath: str) -> tuple[list[UserItem], list[tuple[UserItem, ServerResponseError]]]:
100
362
  created = []
101
363
  failed = []
102
364
  if not filepath.find("csv"):
@@ -120,6 +382,42 @@ class Users(QuerysetEndpoint[UserItem]):
120
382
  # Get workbooks for user
121
383
  @api(version="2.0")
122
384
  def populate_workbooks(self, user_item: UserItem, req_options: Optional[RequestOptions] = None) -> None:
385
+ """
386
+ Returns information about the workbooks that the specified user owns
387
+ and has Read (view) permissions for.
388
+
389
+ This method retrieves the workbook information for the specified user.
390
+ The REST API is designed to return only the information you ask for
391
+ explicitly. When you query for all the users, the workbook information
392
+ for each user is not included. Use this method to retrieve information
393
+ about the workbooks that the user owns or has Read (view) permissions.
394
+ The method adds the list of workbooks to the user item object
395
+ (user_item.workbooks).
396
+
397
+ Parameters
398
+ ----------
399
+ user_item : UserItem
400
+ The user item to populate workbooks for.
401
+
402
+ req_options : Optional[RequestOptions]
403
+ Optional request options to filter and sort the results.
404
+
405
+ Returns
406
+ -------
407
+ None
408
+
409
+ Raises
410
+ ------
411
+ MissingRequiredFieldError
412
+ If the user item is missing an ID.
413
+
414
+ Examples
415
+ --------
416
+ >>> user = server.users.get_by_id('9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d')
417
+ >>> server.users.populate_workbooks(user)
418
+ >>> for wb in user.workbooks:
419
+ >>> print(wb.name)
420
+ """
123
421
  if not user_item.id:
124
422
  error = "User item missing ID."
125
423
  raise MissingRequiredFieldError(error)
@@ -131,20 +429,71 @@ class Users(QuerysetEndpoint[UserItem]):
131
429
 
132
430
  def _get_wbs_for_user(
133
431
  self, user_item: UserItem, req_options: Optional[RequestOptions] = None
134
- ) -> Tuple[List[WorkbookItem], PaginationItem]:
135
- url = "{0}/{1}/workbooks".format(self.baseurl, user_item.id)
432
+ ) -> tuple[list[WorkbookItem], PaginationItem]:
433
+ url = f"{self.baseurl}/{user_item.id}/workbooks"
136
434
  server_response = self.get_request(url, req_options)
137
- logger.info("Populated workbooks for user (ID: {0})".format(user_item.id))
435
+ logger.info(f"Populated workbooks for user (ID: {user_item.id})")
138
436
  workbook_item = WorkbookItem.from_response(server_response.content, self.parent_srv.namespace)
139
437
  pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
140
438
  return workbook_item, pagination_item
141
439
 
142
440
  def populate_favorites(self, user_item: UserItem) -> None:
441
+ """
442
+ Populate the favorites for the user.
443
+
444
+ Parameters
445
+ ----------
446
+ user_item : UserItem
447
+ The user item to populate favorites for.
448
+
449
+ Returns
450
+ -------
451
+ None
452
+
453
+ Examples
454
+ --------
455
+ >>> import tableauserverclient as TSC
456
+ >>> server = TSC.Server('https://SERVERURL')
457
+ >>> # Login to the server
458
+
459
+ >>> user = server.users.get_by_id('9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d')
460
+ >>> server.users.populate_favorites(user)
461
+ >>> for obj_type, items in user.favorites.items():
462
+ >>> print(f"Favorites for {obj_type}:")
463
+ >>> for item in items:
464
+ >>> print(item.name)
465
+ """
143
466
  self.parent_srv.favorites.get(user_item)
144
467
 
145
468
  # Get groups for user
146
469
  @api(version="3.7")
147
470
  def populate_groups(self, user_item: UserItem, req_options: Optional[RequestOptions] = None) -> None:
471
+ """
472
+ Populate the groups for the user.
473
+
474
+ Parameters
475
+ ----------
476
+ user_item : UserItem
477
+ The user item to populate groups for.
478
+
479
+ req_options : Optional[RequestOptions]
480
+ Optional request options to filter and sort the results.
481
+
482
+ Returns
483
+ -------
484
+ None
485
+
486
+ Raises
487
+ ------
488
+ MissingRequiredFieldError
489
+ If the user item is missing an ID.
490
+
491
+ Examples
492
+ --------
493
+ >>> server.users.populate_groups(user)
494
+ >>> for group in user.groups:
495
+ >>> print(group.name)
496
+ """
148
497
  if not user_item.id:
149
498
  error = "User item missing ID."
150
499
  raise MissingRequiredFieldError(error)
@@ -159,10 +508,47 @@ class Users(QuerysetEndpoint[UserItem]):
159
508
 
160
509
  def _get_groups_for_user(
161
510
  self, user_item: UserItem, req_options: Optional[RequestOptions] = None
162
- ) -> Tuple[List[GroupItem], PaginationItem]:
163
- url = "{0}/{1}/groups".format(self.baseurl, user_item.id)
511
+ ) -> tuple[list[GroupItem], PaginationItem]:
512
+ url = f"{self.baseurl}/{user_item.id}/groups"
164
513
  server_response = self.get_request(url, req_options)
165
- logger.info("Populated groups for user (ID: {0})".format(user_item.id))
514
+ logger.info(f"Populated groups for user (ID: {user_item.id})")
166
515
  group_item = GroupItem.from_response(server_response.content, self.parent_srv.namespace)
167
516
  pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
168
517
  return group_item, pagination_item
518
+
519
+ def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[UserItem]:
520
+ """
521
+ Queries the Tableau Server for items using the specified filters. Page
522
+ size can be specified to limit the number of items returned in a single
523
+ request. If not specified, the default page size is 100. Page size can
524
+ be an integer between 1 and 1000.
525
+
526
+ No positional arguments are allowed. All filters must be specified as
527
+ keyword arguments. If you use the equality operator, you can specify it
528
+ through <field_name>=<value>. If you want to use a different operator,
529
+ you can specify it through <field_name>__<operator>=<value>. Field
530
+ names can either be in snake_case or camelCase.
531
+
532
+ This endpoint supports the following fields and operators:
533
+
534
+
535
+ domain_name=...
536
+ domain_name__in=...
537
+ friendly_name=...
538
+ friendly_name__in=...
539
+ is_local=...
540
+ last_login=...
541
+ last_login__gt=...
542
+ last_login__gte=...
543
+ last_login__lt=...
544
+ last_login__lte=...
545
+ luid=...
546
+ luid__in=...
547
+ name__cieq=...
548
+ name=...
549
+ name__in=...
550
+ site_role=...
551
+ site_role__in=...
552
+ """
553
+
554
+ return super().filter(*invalid, page_size=page_size, **kwargs)