tableauserverclient 0.33__py3-none-any.whl → 0.35__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.
- tableauserverclient/__init__.py +33 -23
- tableauserverclient/{_version.py → bin/_version.py} +3 -3
- tableauserverclient/config.py +5 -3
- tableauserverclient/models/column_item.py +1 -1
- tableauserverclient/models/connection_credentials.py +18 -2
- tableauserverclient/models/connection_item.py +44 -6
- tableauserverclient/models/custom_view_item.py +78 -11
- tableauserverclient/models/data_acceleration_report_item.py +2 -2
- tableauserverclient/models/data_alert_item.py +5 -5
- tableauserverclient/models/data_freshness_policy_item.py +6 -6
- tableauserverclient/models/database_item.py +3 -3
- tableauserverclient/models/datasource_item.py +10 -10
- tableauserverclient/models/dqw_item.py +1 -1
- tableauserverclient/models/favorites_item.py +5 -6
- tableauserverclient/models/fileupload_item.py +1 -1
- tableauserverclient/models/flow_item.py +54 -9
- tableauserverclient/models/flow_run_item.py +3 -3
- tableauserverclient/models/group_item.py +44 -4
- tableauserverclient/models/groupset_item.py +4 -4
- tableauserverclient/models/interval_item.py +9 -9
- tableauserverclient/models/job_item.py +73 -8
- tableauserverclient/models/linked_tasks_item.py +5 -5
- tableauserverclient/models/metric_item.py +5 -5
- tableauserverclient/models/pagination_item.py +1 -1
- tableauserverclient/models/permissions_item.py +12 -10
- tableauserverclient/models/project_item.py +73 -19
- tableauserverclient/models/property_decorators.py +12 -11
- tableauserverclient/models/reference_item.py +2 -2
- tableauserverclient/models/revision_item.py +3 -3
- tableauserverclient/models/schedule_item.py +2 -2
- tableauserverclient/models/server_info_item.py +26 -6
- tableauserverclient/models/site_item.py +69 -3
- tableauserverclient/models/subscription_item.py +3 -3
- tableauserverclient/models/table_item.py +1 -1
- tableauserverclient/models/tableau_auth.py +115 -5
- tableauserverclient/models/tableau_types.py +2 -2
- tableauserverclient/models/tag_item.py +3 -4
- tableauserverclient/models/task_item.py +34 -4
- tableauserverclient/models/user_item.py +47 -17
- tableauserverclient/models/view_item.py +66 -13
- tableauserverclient/models/virtual_connection_item.py +6 -5
- tableauserverclient/models/webhook_item.py +39 -6
- tableauserverclient/models/workbook_item.py +116 -13
- tableauserverclient/namespace.py +1 -1
- tableauserverclient/server/__init__.py +2 -1
- tableauserverclient/server/endpoint/auth_endpoint.py +69 -10
- tableauserverclient/server/endpoint/custom_views_endpoint.py +258 -29
- tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
- tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
- tableauserverclient/server/endpoint/databases_endpoint.py +13 -12
- tableauserverclient/server/endpoint/datasources_endpoint.py +61 -62
- tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
- tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
- tableauserverclient/server/endpoint/endpoint.py +19 -21
- tableauserverclient/server/endpoint/exceptions.py +23 -7
- tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
- tableauserverclient/server/endpoint/fileuploads_endpoint.py +9 -11
- tableauserverclient/server/endpoint/flow_runs_endpoint.py +15 -13
- tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
- tableauserverclient/server/endpoint/flows_endpoint.py +344 -29
- tableauserverclient/server/endpoint/groups_endpoint.py +342 -27
- tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
- tableauserverclient/server/endpoint/jobs_endpoint.py +116 -7
- tableauserverclient/server/endpoint/linked_tasks_endpoint.py +2 -2
- tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
- tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
- tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
- tableauserverclient/server/endpoint/projects_endpoint.py +681 -30
- tableauserverclient/server/endpoint/resource_tagger.py +14 -13
- tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
- tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
- tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
- tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
- tableauserverclient/server/endpoint/tables_endpoint.py +15 -14
- tableauserverclient/server/endpoint/tasks_endpoint.py +86 -8
- tableauserverclient/server/endpoint/users_endpoint.py +366 -19
- tableauserverclient/server/endpoint/views_endpoint.py +262 -20
- tableauserverclient/server/endpoint/virtual_connections_endpoint.py +6 -5
- tableauserverclient/server/endpoint/webhooks_endpoint.py +88 -11
- tableauserverclient/server/endpoint/workbooks_endpoint.py +653 -65
- tableauserverclient/server/filter.py +2 -2
- tableauserverclient/server/pager.py +29 -6
- tableauserverclient/server/query.py +68 -19
- tableauserverclient/server/request_factory.py +57 -37
- tableauserverclient/server/request_options.py +243 -141
- tableauserverclient/server/server.py +76 -10
- tableauserverclient/server/sort.py +16 -2
- {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/METADATA +7 -7
- tableauserverclient-0.35.dist-info/RECORD +106 -0
- {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/WHEEL +1 -1
- tableauserverclient-0.33.dist-info/RECORD +0 -106
- {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE +0 -0
- {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,8 @@ from tableauserverclient.server.pager import Pager
|
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.helpers.logging import logger
|
|
10
10
|
|
|
11
|
-
from typing import
|
|
11
|
+
from typing import Literal, Optional, TYPE_CHECKING, Union, overload
|
|
12
|
+
from collections.abc import Iterable
|
|
12
13
|
|
|
13
14
|
from tableauserverclient.server.query import QuerySet
|
|
14
15
|
|
|
@@ -17,13 +18,56 @@ if TYPE_CHECKING:
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class Groups(QuerysetEndpoint[GroupItem]):
|
|
21
|
+
"""
|
|
22
|
+
Groups endpoint for creating, reading, updating, and deleting groups on
|
|
23
|
+
Tableau Server.
|
|
24
|
+
"""
|
|
25
|
+
|
|
20
26
|
@property
|
|
21
27
|
def baseurl(self) -> str:
|
|
22
|
-
return "{
|
|
28
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/groups"
|
|
23
29
|
|
|
24
30
|
@api(version="2.0")
|
|
25
|
-
def get(self, req_options: Optional["RequestOptions"] = None) ->
|
|
26
|
-
"""
|
|
31
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[GroupItem], PaginationItem]:
|
|
32
|
+
"""
|
|
33
|
+
Returns information about the groups on the site.
|
|
34
|
+
|
|
35
|
+
To get information about the users in a group, you must first populate
|
|
36
|
+
the GroupItem with user information using the groups.populate_users
|
|
37
|
+
method.
|
|
38
|
+
|
|
39
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#query_groups
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
req_options : Optional[RequestOptions]
|
|
44
|
+
(Optional) You can pass the method a request object that contains
|
|
45
|
+
additional parameters to filter the request. For example, if you
|
|
46
|
+
were searching for a specific group, you could specify the name of
|
|
47
|
+
the group or the group id.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
tuple[list[GroupItem], PaginationItem]
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> # import tableauserverclient as TSC
|
|
56
|
+
>>> # tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD')
|
|
57
|
+
>>> # server = TSC.Server('https://SERVERURL')
|
|
58
|
+
|
|
59
|
+
>>> with server.auth.sign_in(tableau_auth):
|
|
60
|
+
|
|
61
|
+
>>> # get the groups on the server
|
|
62
|
+
>>> all_groups, pagination_item = server.groups.get()
|
|
63
|
+
|
|
64
|
+
>>> # print the names of the first 100 groups
|
|
65
|
+
>>> for group in all_groups :
|
|
66
|
+
>>> print(group.name, group.id)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
"""
|
|
27
71
|
logger.info("Querying all groups on site")
|
|
28
72
|
url = self.baseurl
|
|
29
73
|
server_response = self.get_request(url, req_options)
|
|
@@ -33,7 +77,42 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
33
77
|
|
|
34
78
|
@api(version="2.0")
|
|
35
79
|
def populate_users(self, group_item: GroupItem, req_options: Optional["RequestOptions"] = None) -> None:
|
|
36
|
-
"""
|
|
80
|
+
"""
|
|
81
|
+
Populates the group_item with the list of users.
|
|
82
|
+
|
|
83
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#get_users_in_group
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
group_item : GroupItem
|
|
88
|
+
The group item to populate with user information.
|
|
89
|
+
|
|
90
|
+
req_options : Optional[RequestOptions]
|
|
91
|
+
(Optional) You can pass the method a request object that contains
|
|
92
|
+
page size and page number.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
None
|
|
97
|
+
|
|
98
|
+
Raises
|
|
99
|
+
------
|
|
100
|
+
MissingRequiredFieldError
|
|
101
|
+
If the group item does not have an ID, the method raises an error.
|
|
102
|
+
|
|
103
|
+
Examples
|
|
104
|
+
--------
|
|
105
|
+
>>> # Get the group item from the server
|
|
106
|
+
>>> groups, pagination_item = server.groups.get()
|
|
107
|
+
>>> group = groups[1]
|
|
108
|
+
|
|
109
|
+
>>> # Populate the group with user information
|
|
110
|
+
>>> server.groups.populate_users(group)
|
|
111
|
+
>>> for user in group.users:
|
|
112
|
+
>>> print(user.name)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
"""
|
|
37
116
|
if not group_item.id:
|
|
38
117
|
error = "Group item missing ID. Group must be retrieved from server first."
|
|
39
118
|
raise MissingRequiredFieldError(error)
|
|
@@ -50,27 +129,86 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
50
129
|
|
|
51
130
|
def _get_users_for_group(
|
|
52
131
|
self, group_item: GroupItem, req_options: Optional["RequestOptions"] = None
|
|
53
|
-
) ->
|
|
54
|
-
url = "{
|
|
132
|
+
) -> tuple[list[UserItem], PaginationItem]:
|
|
133
|
+
url = f"{self.baseurl}/{group_item.id}/users"
|
|
55
134
|
server_response = self.get_request(url, req_options)
|
|
56
135
|
user_item = UserItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
57
136
|
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
58
|
-
logger.info("Populated users for group (ID: {
|
|
137
|
+
logger.info(f"Populated users for group (ID: {group_item.id})")
|
|
59
138
|
return user_item, pagination_item
|
|
60
139
|
|
|
61
140
|
@api(version="2.0")
|
|
62
141
|
def delete(self, group_id: str) -> None:
|
|
63
|
-
"""
|
|
142
|
+
"""
|
|
143
|
+
Deletes the group on the site.
|
|
144
|
+
|
|
145
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#delete_group
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
group_id: str
|
|
150
|
+
The id for the group you want to remove from the server
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
None
|
|
155
|
+
|
|
156
|
+
Raises
|
|
157
|
+
------
|
|
158
|
+
ValueError
|
|
159
|
+
If the group_id is not provided, the method raises an error.
|
|
160
|
+
|
|
161
|
+
Examples
|
|
162
|
+
--------
|
|
163
|
+
>>> groups, pagination_item = server.groups.get()
|
|
164
|
+
>>> group = groups[1]
|
|
165
|
+
>>> server.groups.delete(group.id)
|
|
166
|
+
|
|
167
|
+
"""
|
|
64
168
|
if not group_id:
|
|
65
169
|
error = "Group ID undefined."
|
|
66
170
|
raise ValueError(error)
|
|
67
|
-
url = "{
|
|
171
|
+
url = f"{self.baseurl}/{group_id}"
|
|
68
172
|
self.delete_request(url)
|
|
69
|
-
logger.info("Deleted single group (ID: {
|
|
173
|
+
logger.info(f"Deleted single group (ID: {group_id})")
|
|
174
|
+
|
|
175
|
+
@overload
|
|
176
|
+
def update(self, group_item: GroupItem, as_job: Literal[False]) -> GroupItem: ...
|
|
177
|
+
|
|
178
|
+
@overload
|
|
179
|
+
def update(self, group_item: GroupItem, as_job: Literal[True]) -> JobItem: ...
|
|
70
180
|
|
|
71
181
|
@api(version="2.0")
|
|
72
|
-
def update(self, group_item
|
|
73
|
-
|
|
182
|
+
def update(self, group_item, as_job=False):
|
|
183
|
+
"""
|
|
184
|
+
Updates a group on the site.
|
|
185
|
+
|
|
186
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#update_group
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
group_item : GroupItem
|
|
191
|
+
The group item to update.
|
|
192
|
+
|
|
193
|
+
as_job : bool
|
|
194
|
+
(Optional) If this value is set to True, the update operation will
|
|
195
|
+
be asynchronous and return a JobItem. This is only supported for
|
|
196
|
+
Active Directory groups. By default, this value is set to False.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
Union[GroupItem, JobItem]
|
|
201
|
+
|
|
202
|
+
Raises
|
|
203
|
+
------
|
|
204
|
+
MissingRequiredFieldError
|
|
205
|
+
If the group_item does not have an ID, the method raises an error.
|
|
206
|
+
|
|
207
|
+
ValueError
|
|
208
|
+
If the group_item is a local group and as_job is set to True, the
|
|
209
|
+
method raises an error.
|
|
210
|
+
"""
|
|
211
|
+
url = f"{self.baseurl}/{group_item.id}"
|
|
74
212
|
|
|
75
213
|
if not group_item.id:
|
|
76
214
|
error = "Group item missing ID."
|
|
@@ -83,7 +221,7 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
83
221
|
|
|
84
222
|
update_req = RequestFactory.Group.update_req(group_item)
|
|
85
223
|
server_response = self.put_request(url, update_req)
|
|
86
|
-
logger.info("Updated group item (ID: {
|
|
224
|
+
logger.info(f"Updated group item (ID: {group_item.id})")
|
|
87
225
|
if as_job:
|
|
88
226
|
return JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
89
227
|
else:
|
|
@@ -91,15 +229,71 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
91
229
|
|
|
92
230
|
@api(version="2.0")
|
|
93
231
|
def create(self, group_item: GroupItem) -> GroupItem:
|
|
94
|
-
"""
|
|
232
|
+
"""
|
|
233
|
+
Create a 'local' Tableau group
|
|
234
|
+
|
|
235
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#create_group
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
group_item : GroupItem
|
|
240
|
+
The group item to create. The group_item specifies the group to add.
|
|
241
|
+
You first create a new instance of a GroupItem and pass that to this
|
|
242
|
+
method.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
GroupItem
|
|
247
|
+
|
|
248
|
+
Examples
|
|
249
|
+
--------
|
|
250
|
+
>>> new_group = TSC.GroupItem('new_group')
|
|
251
|
+
>>> new_group.minimum_site_role = TSC.UserItem.Role.ExplorerCanPublish
|
|
252
|
+
>>> new_group = server.groups.create(new_group)
|
|
253
|
+
|
|
254
|
+
"""
|
|
95
255
|
url = self.baseurl
|
|
96
256
|
create_req = RequestFactory.Group.create_local_req(group_item)
|
|
97
257
|
server_response = self.post_request(url, create_req)
|
|
98
258
|
return GroupItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
99
259
|
|
|
260
|
+
@overload
|
|
261
|
+
def create_AD_group(self, group_item: GroupItem, asJob: Literal[False]) -> GroupItem: ...
|
|
262
|
+
|
|
263
|
+
@overload
|
|
264
|
+
def create_AD_group(self, group_item: GroupItem, asJob: Literal[True]) -> JobItem: ...
|
|
265
|
+
|
|
100
266
|
@api(version="2.0")
|
|
101
|
-
def create_AD_group(self, group_item
|
|
102
|
-
"""
|
|
267
|
+
def create_AD_group(self, group_item, asJob=False):
|
|
268
|
+
"""
|
|
269
|
+
Create a group based on Active Directory.
|
|
270
|
+
|
|
271
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#create_group
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
group_item : GroupItem
|
|
276
|
+
The group item to create. The group_item specifies the group to add.
|
|
277
|
+
You first create a new instance of a GroupItem and pass that to this
|
|
278
|
+
method.
|
|
279
|
+
|
|
280
|
+
asJob : bool
|
|
281
|
+
(Optional) If this value is set to True, the create operation will
|
|
282
|
+
be asynchronous and return a JobItem. This is only supported for
|
|
283
|
+
Active Directory groups. By default, this value is set to False.
|
|
284
|
+
|
|
285
|
+
Returns
|
|
286
|
+
-------
|
|
287
|
+
Union[GroupItem, JobItem]
|
|
288
|
+
|
|
289
|
+
Examples
|
|
290
|
+
--------
|
|
291
|
+
>>> new_ad_group = TSC.GroupItem('new_ad_group')
|
|
292
|
+
>>> new_ad_group.domain_name = 'example.com'
|
|
293
|
+
>>> new_ad_group.minimum_site_role = TSC.UserItem.Role.ExplorerCanPublish
|
|
294
|
+
>>> new_ad_group.license_mode = TSC.GroupItem.LicenseMode.onSync
|
|
295
|
+
>>> new_ad_group = server.groups.create_AD_group(new_ad_group)
|
|
296
|
+
"""
|
|
103
297
|
asJobparameter = "?asJob=true" if asJob else ""
|
|
104
298
|
url = self.baseurl + asJobparameter
|
|
105
299
|
create_req = RequestFactory.Group.create_ad_req(group_item)
|
|
@@ -111,20 +305,80 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
111
305
|
|
|
112
306
|
@api(version="2.0")
|
|
113
307
|
def remove_user(self, group_item: GroupItem, user_id: str) -> None:
|
|
114
|
-
"""
|
|
308
|
+
"""
|
|
309
|
+
Removes 1 user from 1 group
|
|
310
|
+
|
|
311
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#remove_user_to_group
|
|
312
|
+
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
group_item : GroupItem
|
|
316
|
+
The group item from which to remove the user.
|
|
317
|
+
|
|
318
|
+
user_id : str
|
|
319
|
+
The ID of the user to remove from the group.
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
None
|
|
324
|
+
|
|
325
|
+
Raises
|
|
326
|
+
------
|
|
327
|
+
MissingRequiredFieldError
|
|
328
|
+
If the group_item does not have an ID, the method raises an error.
|
|
329
|
+
|
|
330
|
+
ValueError
|
|
331
|
+
If the user_id is not provided, the method raises an error.
|
|
332
|
+
|
|
333
|
+
Examples
|
|
334
|
+
--------
|
|
335
|
+
>>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
336
|
+
>>> server.groups.populate_users(group)
|
|
337
|
+
>>> server.groups.remove_user(group, group.users[0].id)
|
|
338
|
+
"""
|
|
115
339
|
if not group_item.id:
|
|
116
340
|
error = "Group item missing ID."
|
|
117
341
|
raise MissingRequiredFieldError(error)
|
|
118
342
|
if not user_id:
|
|
119
343
|
error = "User ID undefined."
|
|
120
344
|
raise ValueError(error)
|
|
121
|
-
url = "{
|
|
345
|
+
url = f"{self.baseurl}/{group_item.id}/users/{user_id}"
|
|
122
346
|
self.delete_request(url)
|
|
123
|
-
logger.info("Removed user (id: {
|
|
347
|
+
logger.info(f"Removed user (id: {user_id}) from group (ID: {group_item.id})")
|
|
124
348
|
|
|
125
349
|
@api(version="3.21")
|
|
126
350
|
def remove_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]) -> None:
|
|
127
|
-
"""
|
|
351
|
+
"""
|
|
352
|
+
Removes multiple users from 1 group. This makes a single API call to
|
|
353
|
+
remove the provided users.
|
|
354
|
+
|
|
355
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#remove_users_to_group
|
|
356
|
+
|
|
357
|
+
Parameters
|
|
358
|
+
----------
|
|
359
|
+
group_item : GroupItem
|
|
360
|
+
The group item from which to remove the user.
|
|
361
|
+
|
|
362
|
+
users : Iterable[Union[str, UserItem]]
|
|
363
|
+
The IDs or UserItems with IDs of the users to remove from the group.
|
|
364
|
+
|
|
365
|
+
Returns
|
|
366
|
+
-------
|
|
367
|
+
None
|
|
368
|
+
|
|
369
|
+
Raises
|
|
370
|
+
------
|
|
371
|
+
ValueError
|
|
372
|
+
If the group_item is not a GroupItem or str, the method raises an error.
|
|
373
|
+
|
|
374
|
+
Examples
|
|
375
|
+
--------
|
|
376
|
+
>>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
377
|
+
>>> server.groups.populate_users(group)
|
|
378
|
+
>>> users = [u for u in group.users if u.domain_name == 'example.com']
|
|
379
|
+
>>> server.groups.remove_users(group, users)
|
|
380
|
+
|
|
381
|
+
"""
|
|
128
382
|
group_id = group_item.id if hasattr(group_item, "id") else group_item
|
|
129
383
|
if not isinstance(group_id, str):
|
|
130
384
|
raise ValueError(f"Invalid group provided: {group_item}")
|
|
@@ -132,27 +386,88 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
132
386
|
url = f"{self.baseurl}/{group_id}/users/remove"
|
|
133
387
|
add_req = RequestFactory.Group.remove_users_req(users)
|
|
134
388
|
_ = self.put_request(url, add_req)
|
|
135
|
-
logger.info("Removed users to group (ID: {
|
|
389
|
+
logger.info(f"Removed users to group (ID: {group_item.id})")
|
|
136
390
|
return None
|
|
137
391
|
|
|
138
392
|
@api(version="2.0")
|
|
139
393
|
def add_user(self, group_item: GroupItem, user_id: str) -> UserItem:
|
|
140
|
-
"""
|
|
394
|
+
"""
|
|
395
|
+
Adds 1 user to 1 group
|
|
396
|
+
|
|
397
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#add_user_to_group
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
----------
|
|
401
|
+
group_item : GroupItem
|
|
402
|
+
The group item to which to add the user.
|
|
403
|
+
|
|
404
|
+
user_id : str
|
|
405
|
+
The ID of the user to add to the group.
|
|
406
|
+
|
|
407
|
+
Returns
|
|
408
|
+
-------
|
|
409
|
+
UserItem
|
|
410
|
+
UserItem for the user that was added to the group.
|
|
411
|
+
|
|
412
|
+
Raises
|
|
413
|
+
------
|
|
414
|
+
MissingRequiredFieldError
|
|
415
|
+
If the group_item does not have an ID, the method raises an error.
|
|
416
|
+
|
|
417
|
+
ValueError
|
|
418
|
+
If the user_id is not provided, the method raises an error.
|
|
419
|
+
|
|
420
|
+
Examples
|
|
421
|
+
--------
|
|
422
|
+
>>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
423
|
+
>>> server.groups.add_user(group, '1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
424
|
+
"""
|
|
141
425
|
if not group_item.id:
|
|
142
426
|
error = "Group item missing ID."
|
|
143
427
|
raise MissingRequiredFieldError(error)
|
|
144
428
|
if not user_id:
|
|
145
429
|
error = "User ID undefined."
|
|
146
430
|
raise ValueError(error)
|
|
147
|
-
url = "{
|
|
431
|
+
url = f"{self.baseurl}/{group_item.id}/users"
|
|
148
432
|
add_req = RequestFactory.Group.add_user_req(user_id)
|
|
149
433
|
server_response = self.post_request(url, add_req)
|
|
150
434
|
user = UserItem.from_response(server_response.content, self.parent_srv.namespace).pop()
|
|
151
|
-
logger.info("Added user (id: {
|
|
435
|
+
logger.info(f"Added user (id: {user_id}) to group (ID: {group_item.id})")
|
|
152
436
|
return user
|
|
153
437
|
|
|
154
438
|
@api(version="3.21")
|
|
155
|
-
def add_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]) ->
|
|
439
|
+
def add_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]) -> list[UserItem]:
|
|
440
|
+
"""
|
|
441
|
+
Adds 1 or more user to 1 group
|
|
442
|
+
|
|
443
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#add_user_to_group
|
|
444
|
+
|
|
445
|
+
Parameters
|
|
446
|
+
----------
|
|
447
|
+
group_item : GroupItem
|
|
448
|
+
The group item to which to add the user.
|
|
449
|
+
|
|
450
|
+
user_id : Iterable[Union[str, UserItem]]
|
|
451
|
+
User IDs or UserItems with IDs to add to the group.
|
|
452
|
+
|
|
453
|
+
Returns
|
|
454
|
+
-------
|
|
455
|
+
list[UserItem]
|
|
456
|
+
UserItem for the user that was added to the group.
|
|
457
|
+
|
|
458
|
+
Raises
|
|
459
|
+
------
|
|
460
|
+
MissingRequiredFieldError
|
|
461
|
+
If the group_item does not have an ID, the method raises an error.
|
|
462
|
+
|
|
463
|
+
ValueError
|
|
464
|
+
If the user_id is not provided, the method raises an error.
|
|
465
|
+
|
|
466
|
+
Examples
|
|
467
|
+
--------
|
|
468
|
+
>>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
469
|
+
>>> added_users = server.groups.add_users(group, '1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
470
|
+
"""
|
|
156
471
|
"""Adds multiple users to 1 group"""
|
|
157
472
|
group_id = group_item.id if hasattr(group_item, "id") else group_item
|
|
158
473
|
if not isinstance(group_id, str):
|
|
@@ -162,7 +477,7 @@ class Groups(QuerysetEndpoint[GroupItem]):
|
|
|
162
477
|
add_req = RequestFactory.Group.add_users_req(users)
|
|
163
478
|
server_response = self.post_request(url, add_req)
|
|
164
479
|
users = UserItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
165
|
-
logger.info("Added users to group (ID: {
|
|
480
|
+
logger.info(f"Added users to group (ID: {group_item.id})")
|
|
166
481
|
return users
|
|
167
482
|
|
|
168
483
|
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[GroupItem]:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Literal, Optional, TYPE_CHECKING, Union
|
|
2
2
|
|
|
3
3
|
from tableauserverclient.helpers.logging import logger
|
|
4
4
|
from tableauserverclient.models.group_item import GroupItem
|
|
@@ -27,7 +27,7 @@ class GroupSets(QuerysetEndpoint[GroupSetItem]):
|
|
|
27
27
|
self,
|
|
28
28
|
request_options: Optional[RequestOptions] = None,
|
|
29
29
|
result_level: Optional[Literal["members", "local"]] = None,
|
|
30
|
-
) ->
|
|
30
|
+
) -> tuple[list[GroupSetItem], PaginationItem]:
|
|
31
31
|
logger.info("Querying all group sets on site")
|
|
32
32
|
url = self.baseurl
|
|
33
33
|
if result_level:
|
|
@@ -11,28 +11,54 @@ from tableauserverclient.exponential_backoff import ExponentialBackoffTimer
|
|
|
11
11
|
|
|
12
12
|
from tableauserverclient.helpers.logging import logger
|
|
13
13
|
|
|
14
|
-
from typing import
|
|
14
|
+
from typing import Optional, Union
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class Jobs(QuerysetEndpoint[BackgroundJobItem]):
|
|
18
18
|
@property
|
|
19
19
|
def baseurl(self):
|
|
20
|
-
return "{
|
|
20
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/jobs"
|
|
21
21
|
|
|
22
22
|
@overload # type: ignore[override]
|
|
23
23
|
def get(self: Self, job_id: str, req_options: Optional[RequestOptionsBase] = None) -> JobItem: # type: ignore[override]
|
|
24
24
|
...
|
|
25
25
|
|
|
26
26
|
@overload # type: ignore[override]
|
|
27
|
-
def get(self: Self, job_id: RequestOptionsBase, req_options: None) ->
|
|
27
|
+
def get(self: Self, job_id: RequestOptionsBase, req_options: None) -> tuple[list[BackgroundJobItem], PaginationItem]: # type: ignore[override]
|
|
28
28
|
...
|
|
29
29
|
|
|
30
30
|
@overload # type: ignore[override]
|
|
31
|
-
def get(self: Self, job_id: None, req_options: Optional[RequestOptionsBase]) ->
|
|
31
|
+
def get(self: Self, job_id: None, req_options: Optional[RequestOptionsBase]) -> tuple[list[BackgroundJobItem], PaginationItem]: # type: ignore[override]
|
|
32
32
|
...
|
|
33
33
|
|
|
34
34
|
@api(version="2.6")
|
|
35
35
|
def get(self, job_id=None, req_options=None):
|
|
36
|
+
"""
|
|
37
|
+
Retrieve jobs for the site. Endpoint is paginated and will return a
|
|
38
|
+
list of jobs and pagination information. If a job_id is provided, the
|
|
39
|
+
method will return information about that specific job. Specifying a
|
|
40
|
+
job_id is deprecated and will be removed in a future version.
|
|
41
|
+
|
|
42
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_jobs
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
job_id : str or RequestOptionsBase
|
|
47
|
+
The ID of the job to retrieve. If None, the method will return all
|
|
48
|
+
jobs for the site. If a RequestOptions object is provided, the
|
|
49
|
+
method will use the options to filter the jobs.
|
|
50
|
+
|
|
51
|
+
req_options : RequestOptionsBase
|
|
52
|
+
The request options to filter the jobs. If None, the method will
|
|
53
|
+
return all jobs for the site.
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
tuple[list[BackgroundJobItem], PaginationItem] or JobItem
|
|
58
|
+
If a job_id is provided, the method will return a JobItem. If no
|
|
59
|
+
job_id is provided, the method will return a tuple containing a
|
|
60
|
+
list of BackgroundJobItems and a PaginationItem.
|
|
61
|
+
"""
|
|
36
62
|
# Backwards Compatibility fix until we rev the major version
|
|
37
63
|
if job_id is not None and isinstance(job_id, str):
|
|
38
64
|
import warnings
|
|
@@ -50,21 +76,104 @@ class Jobs(QuerysetEndpoint[BackgroundJobItem]):
|
|
|
50
76
|
|
|
51
77
|
@api(version="3.1")
|
|
52
78
|
def cancel(self, job_id: Union[str, JobItem]):
|
|
79
|
+
"""
|
|
80
|
+
Cancels a job specified by job ID. To get a list of job IDs for jobs that are currently queued or in-progress, use the Query Jobs method.
|
|
81
|
+
|
|
82
|
+
The following jobs can be canceled using the Cancel Job method:
|
|
83
|
+
|
|
84
|
+
Full extract refresh
|
|
85
|
+
Incremental extract refresh
|
|
86
|
+
Subscription
|
|
87
|
+
Flow Run
|
|
88
|
+
Data Acceleration (Data acceleration is not available in Tableau Server 2022.1 (API 3.16) and later. See View Acceleration(Link opens in a new window).)
|
|
89
|
+
Bridge full extract refresh
|
|
90
|
+
Bridge incremental extract refresh
|
|
91
|
+
Queue upgrade Thumbnail (Job that puts the upgrade thumbnail job on the queue)
|
|
92
|
+
Upgrade Thumbnail
|
|
93
|
+
|
|
94
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#cancel_job
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
job_id : str or JobItem
|
|
99
|
+
The ID of the job to cancel. If a JobItem is provided, the method
|
|
100
|
+
will use the ID from the JobItem.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
None
|
|
105
|
+
"""
|
|
53
106
|
if isinstance(job_id, JobItem):
|
|
54
107
|
job_id = job_id.id
|
|
55
108
|
assert isinstance(job_id, str)
|
|
56
|
-
url = "{
|
|
109
|
+
url = f"{self.baseurl}/{job_id}"
|
|
57
110
|
return self.put_request(url)
|
|
58
111
|
|
|
59
112
|
@api(version="2.6")
|
|
60
113
|
def get_by_id(self, job_id: str) -> JobItem:
|
|
114
|
+
"""
|
|
115
|
+
Returns status information about an asynchronous process that is tracked
|
|
116
|
+
using a job. This method can be used to query jobs that are used to do
|
|
117
|
+
the following:
|
|
118
|
+
|
|
119
|
+
Import users from Active Directory (the result of a call to Create Group).
|
|
120
|
+
Synchronize an existing Tableau Server group with Active Directory (the result of a call to Update Group).
|
|
121
|
+
Run extract refresh tasks (the result of a call to Run Extract Refresh Task).
|
|
122
|
+
Publish a workbook asynchronously (the result of a call to Publish Workbook).
|
|
123
|
+
Run workbook or view subscriptions (the result of a call to Create Subscription or Update Subscription)
|
|
124
|
+
Run a flow task (the result of a call to Run Flow Task)
|
|
125
|
+
Status of Tableau Server site deletion (the result of a call to asynchronous Delete Site(Link opens in a new window) beginning API 3.18)
|
|
126
|
+
Note: To query a site deletion job, the server administrator must be first signed into the default site (contentUrl=" ").
|
|
127
|
+
|
|
128
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
job_id : str
|
|
133
|
+
The ID of the job to retrieve.
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
JobItem
|
|
138
|
+
The JobItem object that contains information about the requested job.
|
|
139
|
+
"""
|
|
61
140
|
logger.info("Query for information about job " + job_id)
|
|
62
|
-
url = "{
|
|
141
|
+
url = f"{self.baseurl}/{job_id}"
|
|
63
142
|
server_response = self.get_request(url)
|
|
64
143
|
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
65
144
|
return new_job
|
|
66
145
|
|
|
67
146
|
def wait_for_job(self, job_id: Union[str, JobItem], *, timeout: Optional[float] = None) -> JobItem:
|
|
147
|
+
"""
|
|
148
|
+
Waits for a job to complete. The method will poll the server for the job
|
|
149
|
+
status until the job is completed. If the job is successful, the method
|
|
150
|
+
will return the JobItem. If the job fails, the method will raise a
|
|
151
|
+
JobFailedException. If the job is cancelled, the method will raise a
|
|
152
|
+
JobCancelledException.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
job_id : str or JobItem
|
|
157
|
+
The ID of the job to wait for. If a JobItem is provided, the method
|
|
158
|
+
will use the ID from the JobItem.
|
|
159
|
+
|
|
160
|
+
timeout : float | None
|
|
161
|
+
The maximum amount of time to wait for the job to complete. If None,
|
|
162
|
+
the method will wait indefinitely.
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
JobItem
|
|
167
|
+
The JobItem object that contains information about the completed job.
|
|
168
|
+
|
|
169
|
+
Raises
|
|
170
|
+
------
|
|
171
|
+
JobFailedException
|
|
172
|
+
If the job failed to complete.
|
|
173
|
+
|
|
174
|
+
JobCancelledException
|
|
175
|
+
If the job was cancelled.
|
|
176
|
+
"""
|
|
68
177
|
if isinstance(job_id, JobItem):
|
|
69
178
|
job_id = job_id.id
|
|
70
179
|
assert isinstance(job_id, str)
|
|
@@ -77,7 +186,7 @@ class Jobs(QuerysetEndpoint[BackgroundJobItem]):
|
|
|
77
186
|
job = self.get_by_id(job_id)
|
|
78
187
|
logger.debug(f"\tJob {job_id} progress={job.progress}")
|
|
79
188
|
|
|
80
|
-
logger.info("Job {} Completed: Finish Code: {} - Notes:{
|
|
189
|
+
logger.info(f"Job {job_id} Completed: Finish Code: {job.finish_code} - Notes:{job.notes}")
|
|
81
190
|
|
|
82
191
|
if job.finish_code == JobItem.FinishCode.Success:
|
|
83
192
|
return job
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Optional, Union
|
|
2
2
|
|
|
3
3
|
from tableauserverclient.helpers.logging import logger
|
|
4
4
|
from tableauserverclient.models.linked_tasks_item import LinkedTaskItem, LinkedTaskJobItem
|
|
@@ -18,7 +18,7 @@ class LinkedTasks(QuerysetEndpoint[LinkedTaskItem]):
|
|
|
18
18
|
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tasks/linked"
|
|
19
19
|
|
|
20
20
|
@api(version="3.15")
|
|
21
|
-
def get(self, req_options: Optional["RequestOptions"] = None) ->
|
|
21
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[LinkedTaskItem], PaginationItem]:
|
|
22
22
|
logger.info("Querying all linked tasks on site")
|
|
23
23
|
url = self.baseurl
|
|
24
24
|
server_response = self.get_request(url, req_options)
|