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.
Files changed (94) hide show
  1. tableauserverclient/__init__.py +33 -23
  2. tableauserverclient/{_version.py → bin/_version.py} +3 -3
  3. tableauserverclient/config.py +5 -3
  4. tableauserverclient/models/column_item.py +1 -1
  5. tableauserverclient/models/connection_credentials.py +18 -2
  6. tableauserverclient/models/connection_item.py +44 -6
  7. tableauserverclient/models/custom_view_item.py +78 -11
  8. tableauserverclient/models/data_acceleration_report_item.py +2 -2
  9. tableauserverclient/models/data_alert_item.py +5 -5
  10. tableauserverclient/models/data_freshness_policy_item.py +6 -6
  11. tableauserverclient/models/database_item.py +3 -3
  12. tableauserverclient/models/datasource_item.py +10 -10
  13. tableauserverclient/models/dqw_item.py +1 -1
  14. tableauserverclient/models/favorites_item.py +5 -6
  15. tableauserverclient/models/fileupload_item.py +1 -1
  16. tableauserverclient/models/flow_item.py +54 -9
  17. tableauserverclient/models/flow_run_item.py +3 -3
  18. tableauserverclient/models/group_item.py +44 -4
  19. tableauserverclient/models/groupset_item.py +4 -4
  20. tableauserverclient/models/interval_item.py +9 -9
  21. tableauserverclient/models/job_item.py +73 -8
  22. tableauserverclient/models/linked_tasks_item.py +5 -5
  23. tableauserverclient/models/metric_item.py +5 -5
  24. tableauserverclient/models/pagination_item.py +1 -1
  25. tableauserverclient/models/permissions_item.py +12 -10
  26. tableauserverclient/models/project_item.py +73 -19
  27. tableauserverclient/models/property_decorators.py +12 -11
  28. tableauserverclient/models/reference_item.py +2 -2
  29. tableauserverclient/models/revision_item.py +3 -3
  30. tableauserverclient/models/schedule_item.py +2 -2
  31. tableauserverclient/models/server_info_item.py +26 -6
  32. tableauserverclient/models/site_item.py +69 -3
  33. tableauserverclient/models/subscription_item.py +3 -3
  34. tableauserverclient/models/table_item.py +1 -1
  35. tableauserverclient/models/tableau_auth.py +115 -5
  36. tableauserverclient/models/tableau_types.py +2 -2
  37. tableauserverclient/models/tag_item.py +3 -4
  38. tableauserverclient/models/task_item.py +34 -4
  39. tableauserverclient/models/user_item.py +47 -17
  40. tableauserverclient/models/view_item.py +66 -13
  41. tableauserverclient/models/virtual_connection_item.py +6 -5
  42. tableauserverclient/models/webhook_item.py +39 -6
  43. tableauserverclient/models/workbook_item.py +116 -13
  44. tableauserverclient/namespace.py +1 -1
  45. tableauserverclient/server/__init__.py +2 -1
  46. tableauserverclient/server/endpoint/auth_endpoint.py +69 -10
  47. tableauserverclient/server/endpoint/custom_views_endpoint.py +258 -29
  48. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
  49. tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
  50. tableauserverclient/server/endpoint/databases_endpoint.py +13 -12
  51. tableauserverclient/server/endpoint/datasources_endpoint.py +61 -62
  52. tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
  53. tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
  54. tableauserverclient/server/endpoint/endpoint.py +19 -21
  55. tableauserverclient/server/endpoint/exceptions.py +23 -7
  56. tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
  57. tableauserverclient/server/endpoint/fileuploads_endpoint.py +9 -11
  58. tableauserverclient/server/endpoint/flow_runs_endpoint.py +15 -13
  59. tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
  60. tableauserverclient/server/endpoint/flows_endpoint.py +344 -29
  61. tableauserverclient/server/endpoint/groups_endpoint.py +342 -27
  62. tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
  63. tableauserverclient/server/endpoint/jobs_endpoint.py +116 -7
  64. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +2 -2
  65. tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
  66. tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
  67. tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
  68. tableauserverclient/server/endpoint/projects_endpoint.py +681 -30
  69. tableauserverclient/server/endpoint/resource_tagger.py +14 -13
  70. tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
  71. tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
  72. tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
  73. tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
  74. tableauserverclient/server/endpoint/tables_endpoint.py +15 -14
  75. tableauserverclient/server/endpoint/tasks_endpoint.py +86 -8
  76. tableauserverclient/server/endpoint/users_endpoint.py +366 -19
  77. tableauserverclient/server/endpoint/views_endpoint.py +262 -20
  78. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +6 -5
  79. tableauserverclient/server/endpoint/webhooks_endpoint.py +88 -11
  80. tableauserverclient/server/endpoint/workbooks_endpoint.py +653 -65
  81. tableauserverclient/server/filter.py +2 -2
  82. tableauserverclient/server/pager.py +29 -6
  83. tableauserverclient/server/query.py +68 -19
  84. tableauserverclient/server/request_factory.py +57 -37
  85. tableauserverclient/server/request_options.py +243 -141
  86. tableauserverclient/server/server.py +76 -10
  87. tableauserverclient/server/sort.py +16 -2
  88. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/METADATA +7 -7
  89. tableauserverclient-0.35.dist-info/RECORD +106 -0
  90. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/WHEEL +1 -1
  91. tableauserverclient-0.33.dist-info/RECORD +0 -106
  92. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE +0 -0
  93. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE.versioneer +0 -0
  94. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/top_level.txt +0 -0
@@ -7,6 +7,7 @@ from contextlib import closing
7
7
  from pathlib import Path
8
8
 
9
9
  from tableauserverclient.helpers.headers import fix_filename
10
+ from tableauserverclient.models.permissions_item import PermissionsRule
10
11
  from tableauserverclient.server.query import QuerySet
11
12
 
12
13
  from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api, parameter_added_in
@@ -25,15 +26,11 @@ from tableauserverclient.models import WorkbookItem, ConnectionItem, ViewItem, P
25
26
  from tableauserverclient.server import RequestFactory
26
27
 
27
28
  from typing import (
28
- Iterable,
29
- List,
30
29
  Optional,
31
- Sequence,
32
- Set,
33
- Tuple,
34
30
  TYPE_CHECKING,
35
31
  Union,
36
32
  )
33
+ from collections.abc import Iterable, Sequence
37
34
 
38
35
  if TYPE_CHECKING:
39
36
  from tableauserverclient.server import Server
@@ -61,18 +58,34 @@ PathOrFileW = Union[FilePath, FileObjectW]
61
58
 
62
59
  class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
63
60
  def __init__(self, parent_srv: "Server") -> None:
64
- super(Workbooks, self).__init__(parent_srv)
61
+ super().__init__(parent_srv)
65
62
  self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl)
66
63
 
67
64
  return None
68
65
 
69
66
  @property
70
67
  def baseurl(self) -> str:
71
- return "{0}/sites/{1}/workbooks".format(self.parent_srv.baseurl, self.parent_srv.site_id)
68
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/workbooks"
72
69
 
73
70
  # Get all workbooks on site
74
71
  @api(version="2.0")
75
- def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[WorkbookItem], PaginationItem]:
72
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[WorkbookItem], PaginationItem]:
73
+ """
74
+ Queries the server and returns information about the workbooks the site.
75
+
76
+ Parameters
77
+ ----------
78
+ req_options : RequestOptions, optional
79
+ (Optional) You can pass the method a request object that contains
80
+ additional parameters to filter the request. For example, if you
81
+ were searching for a specific workbook, you could specify the name
82
+ of the workbook or the name of the owner.
83
+
84
+ Returns
85
+ -------
86
+ Tuple containing one page's worth of workbook items and pagination
87
+ information.
88
+ """
76
89
  logger.info("Querying all workbooks on site")
77
90
  url = self.baseurl
78
91
  server_response = self.get_request(url, req_options)
@@ -83,20 +96,48 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
83
96
  # Get 1 workbook
84
97
  @api(version="2.0")
85
98
  def get_by_id(self, workbook_id: str) -> WorkbookItem:
99
+ """
100
+ Returns information about the specified workbook on the site.
101
+
102
+ Parameters
103
+ ----------
104
+ workbook_id : str
105
+ The workbook ID.
106
+
107
+ Returns
108
+ -------
109
+ WorkbookItem
110
+ The workbook item.
111
+ """
86
112
  if not workbook_id:
87
113
  error = "Workbook ID undefined."
88
114
  raise ValueError(error)
89
- logger.info("Querying single workbook (ID: {0})".format(workbook_id))
90
- url = "{0}/{1}".format(self.baseurl, workbook_id)
115
+ logger.info(f"Querying single workbook (ID: {workbook_id})")
116
+ url = f"{self.baseurl}/{workbook_id}"
91
117
  server_response = self.get_request(url)
92
118
  return WorkbookItem.from_response(server_response.content, self.parent_srv.namespace)[0]
93
119
 
94
120
  @api(version="2.8")
95
- def refresh(self, workbook_item: Union[WorkbookItem, str]) -> JobItem:
121
+ def refresh(self, workbook_item: Union[WorkbookItem, str], incremental: bool = False) -> JobItem:
122
+ """
123
+ Refreshes the extract of an existing workbook.
124
+
125
+ Parameters
126
+ ----------
127
+ workbook_item : WorkbookItem | str
128
+ The workbook item or workbook ID.
129
+ incremental: bool
130
+ Whether to do a full refresh or incremental refresh of the extract data
131
+
132
+ Returns
133
+ -------
134
+ JobItem
135
+ The job item.
136
+ """
96
137
  id_ = getattr(workbook_item, "id", workbook_item)
97
- url = "{0}/{1}/refresh".format(self.baseurl, id_)
98
- empty_req = RequestFactory.Empty.empty_req()
99
- server_response = self.post_request(url, empty_req)
138
+ url = f"{self.baseurl}/{id_}/refresh"
139
+ refresh_req = RequestFactory.Task.refresh_req(incremental)
140
+ server_response = self.post_request(url, refresh_req)
100
141
  new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
101
142
  return new_job
102
143
 
@@ -107,10 +148,37 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
107
148
  workbook_item: WorkbookItem,
108
149
  encrypt: bool = False,
109
150
  includeAll: bool = True,
110
- datasources: Optional[List["DatasourceItem"]] = None,
151
+ datasources: Optional[list["DatasourceItem"]] = None,
111
152
  ) -> JobItem:
153
+ """
154
+ Create one or more extracts on 1 workbook, optionally encrypted.
155
+
156
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#create_extracts_for_workbook
157
+
158
+ Parameters
159
+ ----------
160
+ workbook_item : WorkbookItem
161
+ The workbook item to create extracts for.
162
+
163
+ encrypt : bool, default False
164
+ Set to True to encrypt the extracts.
165
+
166
+ includeAll : bool, default True
167
+ If True, all data sources in the workbook will have an extract
168
+ created for them. If False, then a data source must be supplied in
169
+ the request.
170
+
171
+ datasources : list[DatasourceItem] | None
172
+ List of DatasourceItem objects for the data sources to create
173
+ extracts for. Only required if includeAll is False.
174
+
175
+ Returns
176
+ -------
177
+ JobItem
178
+ The job item for the extract creation.
179
+ """
112
180
  id_ = getattr(workbook_item, "id", workbook_item)
113
- url = "{0}/{1}/createExtract?encrypt={2}".format(self.baseurl, id_, encrypt)
181
+ url = f"{self.baseurl}/{id_}/createExtract?encrypt={encrypt}"
114
182
 
115
183
  datasource_req = RequestFactory.Workbook.embedded_extract_req(includeAll, datasources)
116
184
  server_response = self.post_request(url, datasource_req)
@@ -120,8 +188,31 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
120
188
  # delete all the extracts on 1 workbook
121
189
  @api(version="3.3")
122
190
  def delete_extract(self, workbook_item: WorkbookItem, includeAll: bool = True, datasources=None) -> JobItem:
191
+ """
192
+ Delete all extracts of embedded datasources on 1 workbook.
193
+
194
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#delete_extracts_from_workbook
195
+
196
+ Parameters
197
+ ----------
198
+ workbook_item : WorkbookItem
199
+ The workbook item to delete extracts from.
200
+
201
+ includeAll : bool, default True
202
+ If True, all data sources in the workbook will have their extracts
203
+ deleted. If False, then a data source must be supplied in the
204
+ request.
205
+
206
+ datasources : list[DatasourceItem] | None
207
+ List of DatasourceItem objects for the data sources to delete
208
+ extracts from. Only required if includeAll is False.
209
+
210
+ Returns
211
+ -------
212
+ JobItem
213
+ """
123
214
  id_ = getattr(workbook_item, "id", workbook_item)
124
- url = "{0}/{1}/deleteExtract".format(self.baseurl, id_)
215
+ url = f"{self.baseurl}/{id_}/deleteExtract"
125
216
  datasource_req = RequestFactory.Workbook.embedded_extract_req(includeAll, datasources)
126
217
  server_response = self.post_request(url, datasource_req)
127
218
  new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
@@ -130,12 +221,24 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
130
221
  # Delete 1 workbook by id
131
222
  @api(version="2.0")
132
223
  def delete(self, workbook_id: str) -> None:
224
+ """
225
+ Deletes a workbook with the specified ID.
226
+
227
+ Parameters
228
+ ----------
229
+ workbook_id : str
230
+ The workbook ID.
231
+
232
+ Returns
233
+ -------
234
+ None
235
+ """
133
236
  if not workbook_id:
134
237
  error = "Workbook ID undefined."
135
238
  raise ValueError(error)
136
- url = "{0}/{1}".format(self.baseurl, workbook_id)
239
+ url = f"{self.baseurl}/{workbook_id}"
137
240
  self.delete_request(url)
138
- logger.info("Deleted single workbook (ID: {0})".format(workbook_id))
241
+ logger.info(f"Deleted single workbook (ID: {workbook_id})")
139
242
 
140
243
  # Update workbook
141
244
  @api(version="2.0")
@@ -145,6 +248,29 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
145
248
  workbook_item: WorkbookItem,
146
249
  include_view_acceleration_status: bool = False,
147
250
  ) -> WorkbookItem:
251
+ """
252
+ Modifies an existing workbook. Use this method to change the owner or
253
+ the project that the workbook belongs to, or to change whether the
254
+ workbook shows views in tabs. The workbook item must include the
255
+ workbook ID and overrides the existing settings.
256
+
257
+ See https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_workbook
258
+ for a list of fields that can be updated.
259
+
260
+ Parameters
261
+ ----------
262
+ workbook_item : WorkbookItem
263
+ The workbook item to update. ID is required. Other fields are
264
+ optional. Any fields that are not specified will not be changed.
265
+
266
+ include_view_acceleration_status : bool, default False
267
+ Set to True to include the view acceleration status in the response.
268
+
269
+ Returns
270
+ -------
271
+ WorkbookItem
272
+ The updated workbook item.
273
+ """
148
274
  if not workbook_item.id:
149
275
  error = "Workbook item missing ID. Workbook must be retrieved from server first."
150
276
  raise MissingRequiredFieldError(error)
@@ -152,27 +278,47 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
152
278
  self.update_tags(workbook_item)
153
279
 
154
280
  # Update the workbook itself
155
- url = "{0}/{1}".format(self.baseurl, workbook_item.id)
281
+ url = f"{self.baseurl}/{workbook_item.id}"
156
282
  if include_view_acceleration_status:
157
283
  url += "?includeViewAccelerationStatus=True"
158
284
 
159
- update_req = RequestFactory.Workbook.update_req(workbook_item)
285
+ update_req = RequestFactory.Workbook.update_req(workbook_item, self.parent_srv)
160
286
  server_response = self.put_request(url, update_req)
161
- logger.info("Updated workbook item (ID: {0})".format(workbook_item.id))
287
+ logger.info(f"Updated workbook item (ID: {workbook_item.id})")
162
288
  updated_workbook = copy.copy(workbook_item)
163
289
  return updated_workbook._parse_common_tags(server_response.content, self.parent_srv.namespace)
164
290
 
165
291
  # Update workbook_connection
166
292
  @api(version="2.3")
167
293
  def update_connection(self, workbook_item: WorkbookItem, connection_item: ConnectionItem) -> ConnectionItem:
168
- url = "{0}/{1}/connections/{2}".format(self.baseurl, workbook_item.id, connection_item.id)
294
+ """
295
+ Updates a workbook connection information (server addres, server port,
296
+ user name, and password).
297
+
298
+ The workbook connections must be populated before the strings can be
299
+ updated.
300
+
301
+ Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_workbook_connection
302
+
303
+ Parameters
304
+ ----------
305
+ workbook_item : WorkbookItem
306
+ The workbook item to update.
307
+
308
+ connection_item : ConnectionItem
309
+ The connection item to update.
310
+
311
+ Returns
312
+ -------
313
+ ConnectionItem
314
+ The updated connection item.
315
+ """
316
+ url = f"{self.baseurl}/{workbook_item.id}/connections/{connection_item.id}"
169
317
  update_req = RequestFactory.Connection.update_req(connection_item)
170
318
  server_response = self.put_request(url, update_req)
171
319
  connection = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)[0]
172
320
 
173
- logger.info(
174
- "Updated workbook item (ID: {0} & connection item {1})".format(workbook_item.id, connection_item.id)
175
- )
321
+ logger.info(f"Updated workbook item (ID: {workbook_item.id} & connection item {connection_item.id})")
176
322
  return connection
177
323
 
178
324
  # Download workbook contents with option of passing in filepath
@@ -185,6 +331,34 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
185
331
  filepath: Optional[PathOrFileW] = None,
186
332
  include_extract: bool = True,
187
333
  ) -> PathOrFileW:
334
+ """
335
+ Downloads a workbook to the specified directory (optional).
336
+
337
+ Parameters
338
+ ----------
339
+ workbook_id : str
340
+ The workbook ID.
341
+
342
+ filepath : Path or File object, optional
343
+ Downloads the file to the location you specify. If no location is
344
+ specified, the file is downloaded to the current working directory.
345
+ The default is Filepath=None.
346
+
347
+ include_extract : bool, default True
348
+ Set to False to exclude the extract from the download. The default
349
+ is True.
350
+
351
+ Returns
352
+ -------
353
+ Path or File object
354
+ The path to the downloaded workbook or the file object.
355
+
356
+ Raises
357
+ ------
358
+ ValueError
359
+ If the workbook ID is not defined.
360
+ """
361
+
188
362
  return self.download_revision(
189
363
  workbook_id,
190
364
  None,
@@ -195,18 +369,48 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
195
369
  # Get all views of workbook
196
370
  @api(version="2.0")
197
371
  def populate_views(self, workbook_item: WorkbookItem, usage: bool = False) -> None:
372
+ """
373
+ Populates (or gets) a list of views for a workbook.
374
+
375
+ You must first call this method to populate views before you can iterate
376
+ through the views.
377
+
378
+ This method retrieves the view information for the specified workbook.
379
+ The REST API is designed to return only the information you ask for
380
+ explicitly. When you query for all the workbooks, the view information
381
+ is not included. Use this method to retrieve the views. The method adds
382
+ the list of views to the workbook item (workbook_item.views). This is a
383
+ list of ViewItem.
384
+
385
+ Parameters
386
+ ----------
387
+ workbook_item : WorkbookItem
388
+ The workbook item to populate views for.
389
+
390
+ usage : bool, default False
391
+ Set to True to include usage statistics for each view.
392
+
393
+ Returns
394
+ -------
395
+ None
396
+
397
+ Raises
398
+ ------
399
+ MissingRequiredFieldError
400
+ If the workbook item is missing an ID.
401
+ """
198
402
  if not workbook_item.id:
199
403
  error = "Workbook item missing ID. Workbook must be retrieved from server first."
200
404
  raise MissingRequiredFieldError(error)
201
405
 
202
- def view_fetcher() -> List[ViewItem]:
406
+ def view_fetcher() -> list[ViewItem]:
203
407
  return self._get_views_for_workbook(workbook_item, usage)
204
408
 
205
409
  workbook_item._set_views(view_fetcher)
206
- logger.info("Populated views for workbook (ID: {0})".format(workbook_item.id))
410
+ logger.info(f"Populated views for workbook (ID: {workbook_item.id})")
207
411
 
208
- def _get_views_for_workbook(self, workbook_item: WorkbookItem, usage: bool) -> List[ViewItem]:
209
- url = "{0}/{1}/views".format(self.baseurl, workbook_item.id)
412
+ def _get_views_for_workbook(self, workbook_item: WorkbookItem, usage: bool) -> list[ViewItem]:
413
+ url = f"{self.baseurl}/{workbook_item.id}/views"
210
414
  if usage:
211
415
  url += "?includeUsageStatistics=true"
212
416
  server_response = self.get_request(url)
@@ -220,6 +424,36 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
220
424
  # Get all connections of workbook
221
425
  @api(version="2.0")
222
426
  def populate_connections(self, workbook_item: WorkbookItem) -> None:
427
+ """
428
+ Populates a list of data source connections for the specified workbook.
429
+
430
+ You must populate connections before you can iterate through the
431
+ connections.
432
+
433
+ This method retrieves the data source connection information for the
434
+ specified workbook. The REST API is designed to return only the
435
+ information you ask for explicitly. When you query all the workbooks,
436
+ the data source connection information is not included. Use this method
437
+ to retrieve the connection information for any data sources used by the
438
+ workbook. The method adds the list of data connections to the workbook
439
+ item (workbook_item.connections). This is a list of ConnectionItem.
440
+
441
+ REST API docs: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_workbook_connections
442
+
443
+ Parameters
444
+ ----------
445
+ workbook_item : WorkbookItem
446
+ The workbook item to populate connections for.
447
+
448
+ Returns
449
+ -------
450
+ None
451
+
452
+ Raises
453
+ ------
454
+ MissingRequiredFieldError
455
+ If the workbook item is missing an ID.
456
+ """
223
457
  if not workbook_item.id:
224
458
  error = "Workbook item missing ID. Workbook must be retrieved from server first."
225
459
  raise MissingRequiredFieldError(error)
@@ -228,12 +462,12 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
228
462
  return self._get_workbook_connections(workbook_item)
229
463
 
230
464
  workbook_item._set_connections(connection_fetcher)
231
- logger.info("Populated connections for workbook (ID: {0})".format(workbook_item.id))
465
+ logger.info(f"Populated connections for workbook (ID: {workbook_item.id})")
232
466
 
233
467
  def _get_workbook_connections(
234
468
  self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None
235
- ) -> List[ConnectionItem]:
236
- url = "{0}/{1}/connections".format(self.baseurl, workbook_item.id)
469
+ ) -> list[ConnectionItem]:
470
+ url = f"{self.baseurl}/{workbook_item.id}/connections"
237
471
  server_response = self.get_request(url, req_options)
238
472
  connections = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)
239
473
  return connections
@@ -241,6 +475,34 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
241
475
  # Get the pdf of the entire workbook if its tabs are enabled, pdf of the default view if its tabs are disabled
242
476
  @api(version="3.4")
243
477
  def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None:
478
+ """
479
+ Populates the PDF for the specified workbook item.
480
+
481
+ This method populates a PDF with image(s) of the workbook view(s) you
482
+ specify.
483
+
484
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#download_workbook_pdf
485
+
486
+ Parameters
487
+ ----------
488
+ workbook_item : WorkbookItem
489
+ The workbook item to populate the PDF for.
490
+
491
+ req_options : RequestOptions, optional
492
+ (Optional) You can pass in request options to specify the page type
493
+ and orientation of the PDF content, as well as the maximum age of
494
+ the PDF rendered on the server. See PDFRequestOptions class for more
495
+ details.
496
+
497
+ Returns
498
+ -------
499
+ None
500
+
501
+ Raises
502
+ ------
503
+ MissingRequiredFieldError
504
+ If the workbook item is missing an ID.
505
+ """
244
506
  if not workbook_item.id:
245
507
  error = "Workbook item missing ID."
246
508
  raise MissingRequiredFieldError(error)
@@ -249,16 +511,46 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
249
511
  return self._get_wb_pdf(workbook_item, req_options)
250
512
 
251
513
  workbook_item._set_pdf(pdf_fetcher)
252
- logger.info("Populated pdf for workbook (ID: {0})".format(workbook_item.id))
514
+ logger.info(f"Populated pdf for workbook (ID: {workbook_item.id})")
253
515
 
254
516
  def _get_wb_pdf(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"]) -> bytes:
255
- url = "{0}/{1}/pdf".format(self.baseurl, workbook_item.id)
517
+ url = f"{self.baseurl}/{workbook_item.id}/pdf"
256
518
  server_response = self.get_request(url, req_options)
257
519
  pdf = server_response.content
258
520
  return pdf
259
521
 
260
522
  @api(version="3.8")
261
523
  def populate_powerpoint(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None:
524
+ """
525
+ Populates the PowerPoint for the specified workbook item.
526
+
527
+ This method populates a PowerPoint with image(s) of the workbook view(s) you
528
+ specify.
529
+
530
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#download_workbook_powerpoint
531
+
532
+ Parameters
533
+ ----------
534
+ workbook_item : WorkbookItem
535
+ The workbook item to populate the PDF for.
536
+
537
+ req_options : RequestOptions, optional
538
+ (Optional) You can pass in request options to specify the maximum
539
+ number of minutes a workbook .pptx will be cached before being
540
+ refreshed. To prevent multiple .pptx requests from overloading the
541
+ server, the shortest interval you can set is one minute. There is no
542
+ maximum value, but the server job enacting the caching action may
543
+ expire before a long cache period is reached.
544
+
545
+ Returns
546
+ -------
547
+ None
548
+
549
+ Raises
550
+ ------
551
+ MissingRequiredFieldError
552
+ If the workbook item is missing an ID.
553
+ """
262
554
  if not workbook_item.id:
263
555
  error = "Workbook item missing ID."
264
556
  raise MissingRequiredFieldError(error)
@@ -267,10 +559,10 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
267
559
  return self._get_wb_pptx(workbook_item, req_options)
268
560
 
269
561
  workbook_item._set_powerpoint(pptx_fetcher)
270
- logger.info("Populated powerpoint for workbook (ID: {0})".format(workbook_item.id))
562
+ logger.info(f"Populated powerpoint for workbook (ID: {workbook_item.id})")
271
563
 
272
564
  def _get_wb_pptx(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"]) -> bytes:
273
- url = "{0}/{1}/powerpoint".format(self.baseurl, workbook_item.id)
565
+ url = f"{self.baseurl}/{workbook_item.id}/powerpoint"
274
566
  server_response = self.get_request(url, req_options)
275
567
  pptx = server_response.content
276
568
  return pptx
@@ -278,6 +570,26 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
278
570
  # Get preview image of workbook
279
571
  @api(version="2.0")
280
572
  def populate_preview_image(self, workbook_item: WorkbookItem) -> None:
573
+ """
574
+ This method gets the preview image (thumbnail) for the specified workbook item.
575
+
576
+ This method uses the workbook's ID to get the preview image. The method
577
+ adds the preview image to the workbook item (workbook_item.preview_image).
578
+
579
+ Parameters
580
+ ----------
581
+ workbook_item : WorkbookItem
582
+ The workbook item to populate the preview image for.
583
+
584
+ Returns
585
+ -------
586
+ None
587
+
588
+ Raises
589
+ ------
590
+ MissingRequiredFieldError
591
+ If the workbook item is missing an ID.
592
+ """
281
593
  if not workbook_item.id:
282
594
  error = "Workbook item missing ID. Workbook must be retrieved from server first."
283
595
  raise MissingRequiredFieldError(error)
@@ -286,24 +598,75 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
286
598
  return self._get_wb_preview_image(workbook_item)
287
599
 
288
600
  workbook_item._set_preview_image(image_fetcher)
289
- logger.info("Populated preview image for workbook (ID: {0})".format(workbook_item.id))
601
+ logger.info(f"Populated preview image for workbook (ID: {workbook_item.id})")
290
602
 
291
603
  def _get_wb_preview_image(self, workbook_item: WorkbookItem) -> bytes:
292
- url = "{0}/{1}/previewImage".format(self.baseurl, workbook_item.id)
604
+ url = f"{self.baseurl}/{workbook_item.id}/previewImage"
293
605
  server_response = self.get_request(url)
294
606
  preview_image = server_response.content
295
607
  return preview_image
296
608
 
297
609
  @api(version="2.0")
298
610
  def populate_permissions(self, item: WorkbookItem) -> None:
611
+ """
612
+ Populates the permissions for the specified workbook item.
613
+
614
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#query_workbook_permissions
615
+
616
+ Parameters
617
+ ----------
618
+ item : WorkbookItem
619
+ The workbook item to populate permissions for.
620
+
621
+ Returns
622
+ -------
623
+ None
624
+ """
299
625
  self._permissions.populate(item)
300
626
 
301
627
  @api(version="2.0")
302
- def update_permissions(self, resource, rules):
628
+ def update_permissions(self, resource: WorkbookItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
629
+ """
630
+ Updates the permissions for the specified workbook item. The method
631
+ replaces the existing permissions with the new permissions. Any missing
632
+ permissions are removed.
633
+
634
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#replace_permissions_for_content
635
+
636
+ Parameters
637
+ ----------
638
+ resource : WorkbookItem
639
+ The workbook item to update permissions for.
640
+
641
+ rules : list[PermissionsRule]
642
+ A list of permissions rules to apply to the workbook item.
643
+
644
+ Returns
645
+ -------
646
+ list[PermissionsRule]
647
+ The updated permissions rules.
648
+ """
303
649
  return self._permissions.update(resource, rules)
304
650
 
305
651
  @api(version="2.0")
306
- def delete_permission(self, item, capability_item):
652
+ def delete_permission(self, item: WorkbookItem, capability_item: PermissionsRule) -> None:
653
+ """
654
+ Deletes a single permission rule from the specified workbook item.
655
+
656
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#delete_workbook_permission
657
+
658
+ Parameters
659
+ ----------
660
+ item : WorkbookItem
661
+ The workbook item to delete the permission from.
662
+
663
+ capability_item : PermissionsRule
664
+ The permission rule to delete.
665
+
666
+ Returns
667
+ -------
668
+ None
669
+ """
307
670
  return self._permissions.delete(item, capability_item)
308
671
 
309
672
  @api(version="2.0")
@@ -319,10 +682,87 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
319
682
  skip_connection_check: bool = False,
320
683
  parameters=None,
321
684
  ):
685
+ """
686
+ Publish a workbook to the specified site.
687
+
688
+ Note: The REST API cannot automatically include extracts or other
689
+ resources that the workbook uses. Therefore, a .twb file that uses data
690
+ from an Excel or csv file on a local computer cannot be published,
691
+ unless you package the data and workbook in a .twbx file, or publish the
692
+ data source separately.
693
+
694
+ For workbooks that are larger than 64 MB, the publish method
695
+ automatically takes care of chunking the file in parts for uploading.
696
+ Using this method is considerably more convenient than calling the
697
+ publish REST APIs directly.
698
+
699
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#publish_workbook
700
+
701
+ Parameters
702
+ ----------
703
+ workbook_item : WorkbookItem
704
+ The workbook_item specifies the workbook you are publishing. When
705
+ you are adding a workbook, you need to first create a new instance
706
+ of a workbook_item that includes a project_id of an existing
707
+ project. The name of the workbook will be the name of the file,
708
+ unless you also specify a name for the new workbook when you create
709
+ the instance.
710
+
711
+ file : Path or File object
712
+ The file path or file object of the workbook to publish. When
713
+ providing a file object, you must also specifiy the name of the
714
+ workbook in your instance of the workbook_itemworkbook_item , as
715
+ the name cannot be derived from the file name.
716
+
717
+ mode : str
718
+ Specifies whether you are publishing a new workbook (CreateNew) or
719
+ overwriting an existing workbook (Overwrite). You cannot appending
720
+ workbooks. You can also use the publish mode attributes, for
721
+ example: TSC.Server.PublishMode.Overwrite.
722
+
723
+ connections : list[ConnectionItem] | None
724
+ List of ConnectionItems objects for the connections created within
725
+ the workbook.
726
+
727
+ as_job : bool, default False
728
+ Set to True to run the upload as a job (asynchronous upload). If set
729
+ to True a job will start to perform the publishing process and a Job
730
+ object is returned. Defaults to False.
731
+
732
+ skip_connection_check : bool, default False
733
+ Set to True to skip connection check at time of upload. Publishing
734
+ will succeed but unchecked connection issues may result in a
735
+ non-functioning workbook. Defaults to False.
736
+
737
+ Raises
738
+ ------
739
+ OSError
740
+ If the file path does not lead to an existing file.
741
+
742
+ ServerResponseError
743
+ If the server response is not successful.
744
+
745
+ TypeError
746
+ If the file is not a file path or file object.
747
+
748
+ ValueError
749
+ If the file extension is not supported
750
+
751
+ ValueError
752
+ If the mode is invalid.
753
+
754
+ ValueError
755
+ Workbooks cannot be appended.
756
+
757
+ Returns
758
+ -------
759
+ WorkbookItem | JobItem
760
+ The workbook item or job item that was published.
761
+ """
322
762
  if isinstance(file, (str, os.PathLike)):
323
763
  if not os.path.isfile(file):
324
764
  error = "File path does not lead to an existing file."
325
- raise IOError(error)
765
+ raise OSError(error)
326
766
 
327
767
  filename = os.path.basename(file)
328
768
  file_extension = os.path.splitext(filename)[1][1:]
@@ -346,12 +786,12 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
346
786
  elif file_type == "xml":
347
787
  file_extension = "twb"
348
788
  else:
349
- error = "Unsupported file type {}!".format(file_type)
789
+ error = f"Unsupported file type {file_type}!"
350
790
  raise ValueError(error)
351
791
 
352
792
  # Generate filename for file object.
353
793
  # This is needed when publishing the workbook in a single request
354
- filename = "{}.{}".format(workbook_item.name, file_extension)
794
+ filename = f"{workbook_item.name}.{file_extension}"
355
795
  file_size = get_file_object_size(file)
356
796
 
357
797
  else:
@@ -362,30 +802,30 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
362
802
  raise ValueError(error)
363
803
 
364
804
  # Construct the url with the defined mode
365
- url = "{0}?workbookType={1}".format(self.baseurl, file_extension)
805
+ url = f"{self.baseurl}?workbookType={file_extension}"
366
806
  if mode == self.parent_srv.PublishMode.Overwrite:
367
- url += "&{0}=true".format(mode.lower())
807
+ url += f"&{mode.lower()}=true"
368
808
  elif mode == self.parent_srv.PublishMode.Append:
369
809
  error = "Workbooks cannot be appended."
370
810
  raise ValueError(error)
371
811
 
372
812
  if as_job:
373
- url += "&{0}=true".format("asJob")
813
+ url += "&{}=true".format("asJob")
374
814
 
375
815
  if skip_connection_check:
376
- url += "&{0}=true".format("skipConnectionCheck")
816
+ url += "&{}=true".format("skipConnectionCheck")
377
817
 
378
818
  # Determine if chunking is required (64MB is the limit for single upload method)
379
819
  if file_size >= FILESIZE_LIMIT:
380
- logger.info("Publishing {0} to server with chunking method (workbook over 64MB)".format(workbook_item.name))
820
+ logger.info(f"Publishing {workbook_item.name} to server with chunking method (workbook over 64MB)")
381
821
  upload_session_id = self.parent_srv.fileuploads.upload(file)
382
- url = "{0}&uploadSessionId={1}".format(url, upload_session_id)
822
+ url = f"{url}&uploadSessionId={upload_session_id}"
383
823
  xml_request, content_type = RequestFactory.Workbook.publish_req_chunked(
384
824
  workbook_item,
385
825
  connections=connections,
386
826
  )
387
827
  else:
388
- logger.info("Publishing {0} to server".format(filename))
828
+ logger.info(f"Publishing {filename} to server")
389
829
 
390
830
  if isinstance(file, (str, Path)):
391
831
  with open(file, "rb") as f:
@@ -403,7 +843,7 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
403
843
  file_contents,
404
844
  connections=connections,
405
845
  )
406
- logger.debug("Request xml: {0} ".format(redact_xml(xml_request[:1000])))
846
+ logger.debug(f"Request xml: {redact_xml(xml_request[:1000])} ")
407
847
 
408
848
  # Send the publishing request to server
409
849
  try:
@@ -415,16 +855,38 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
415
855
 
416
856
  if as_job:
417
857
  new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
418
- logger.info("Published {0} (JOB_ID: {1}".format(workbook_item.name, new_job.id))
858
+ logger.info(f"Published {workbook_item.name} (JOB_ID: {new_job.id}")
419
859
  return new_job
420
860
  else:
421
861
  new_workbook = WorkbookItem.from_response(server_response.content, self.parent_srv.namespace)[0]
422
- logger.info("Published {0} (ID: {1})".format(workbook_item.name, new_workbook.id))
862
+ logger.info(f"Published {workbook_item.name} (ID: {new_workbook.id})")
423
863
  return new_workbook
424
864
 
425
865
  # Populate workbook item's revisions
426
866
  @api(version="2.3")
427
867
  def populate_revisions(self, workbook_item: WorkbookItem) -> None:
868
+ """
869
+ Populates (or gets) a list of revisions for a workbook.
870
+
871
+ You must first call this method to populate revisions before you can
872
+ iterate through the revisions.
873
+
874
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_workbook_revisions
875
+
876
+ Parameters
877
+ ----------
878
+ workbook_item : WorkbookItem
879
+ The workbook item to populate revisions for.
880
+
881
+ Returns
882
+ -------
883
+ None
884
+
885
+ Raises
886
+ ------
887
+ MissingRequiredFieldError
888
+ If the workbook item is missing an ID.
889
+ """
428
890
  if not workbook_item.id:
429
891
  error = "Workbook item missing ID. Workbook must be retrieved from server first."
430
892
  raise MissingRequiredFieldError(error)
@@ -433,12 +895,12 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
433
895
  return self._get_workbook_revisions(workbook_item)
434
896
 
435
897
  workbook_item._set_revisions(revisions_fetcher)
436
- logger.info("Populated revisions for workbook (ID: {0})".format(workbook_item.id))
898
+ logger.info(f"Populated revisions for workbook (ID: {workbook_item.id})")
437
899
 
438
900
  def _get_workbook_revisions(
439
901
  self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None
440
- ) -> List[RevisionItem]:
441
- url = "{0}/{1}/revisions".format(self.baseurl, workbook_item.id)
902
+ ) -> list[RevisionItem]:
903
+ url = f"{self.baseurl}/{workbook_item.id}/revisions"
442
904
  server_response = self.get_request(url, req_options)
443
905
  revisions = RevisionItem.from_response(server_response.content, self.parent_srv.namespace, workbook_item)
444
906
  return revisions
@@ -452,13 +914,47 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
452
914
  filepath: Optional[PathOrFileW] = None,
453
915
  include_extract: bool = True,
454
916
  ) -> PathOrFileW:
917
+ """
918
+ Downloads a workbook revision to the specified directory (optional).
919
+
920
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#download_workbook_revision
921
+
922
+ Parameters
923
+ ----------
924
+ workbook_id : str
925
+ The workbook ID.
926
+
927
+ revision_number : str | None
928
+ The revision number of the workbook. If None, the latest revision is
929
+ downloaded.
930
+
931
+ filepath : Path or File object, optional
932
+ Downloads the file to the location you specify. If no location is
933
+ specified, the file is downloaded to the current working directory.
934
+ The default is Filepath=None.
935
+
936
+ include_extract : bool, default True
937
+ Set to False to exclude the extract from the download. The default
938
+ is True.
939
+
940
+ Returns
941
+ -------
942
+ Path or File object
943
+ The path to the downloaded workbook or the file object.
944
+
945
+ Raises
946
+ ------
947
+ ValueError
948
+ If the workbook ID is not defined.
949
+ """
950
+
455
951
  if not workbook_id:
456
952
  error = "Workbook ID undefined."
457
953
  raise ValueError(error)
458
954
  if revision_number is None:
459
- url = "{0}/{1}/content".format(self.baseurl, workbook_id)
955
+ url = f"{self.baseurl}/{workbook_id}/content"
460
956
  else:
461
- url = "{0}/{1}/revisions/{2}/content".format(self.baseurl, workbook_id, revision_number)
957
+ url = f"{self.baseurl}/{workbook_id}/revisions/{revision_number}/content"
462
958
 
463
959
  if not include_extract:
464
960
  url += "?includeExtract=False"
@@ -480,37 +976,129 @@ class Workbooks(QuerysetEndpoint[WorkbookItem], TaggingMixin[WorkbookItem]):
480
976
  f.write(chunk)
481
977
  return_path = os.path.abspath(download_path)
482
978
 
483
- logger.info(
484
- "Downloaded workbook revision {0} to {1} (ID: {2})".format(revision_number, return_path, workbook_id)
485
- )
979
+ logger.info(f"Downloaded workbook revision {revision_number} to {return_path} (ID: {workbook_id})")
486
980
  return return_path
487
981
 
488
982
  @api(version="2.3")
489
983
  def delete_revision(self, workbook_id: str, revision_number: str) -> None:
984
+ """
985
+ Deletes a specific revision from a workbook on Tableau Server.
986
+
987
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_revisions.htm#remove_workbook_revision
988
+
989
+ Parameters
990
+ ----------
991
+ workbook_id : str
992
+ The workbook ID.
993
+
994
+ revision_number : str
995
+ The revision number of the workbook to delete.
996
+
997
+ Returns
998
+ -------
999
+ None
1000
+
1001
+ Raises
1002
+ ------
1003
+ ValueError
1004
+ If the workbook ID or revision number is not defined.
1005
+ """
490
1006
  if workbook_id is None or revision_number is None:
491
1007
  raise ValueError
492
1008
  url = "/".join([self.baseurl, workbook_id, "revisions", revision_number])
493
1009
 
494
1010
  self.delete_request(url)
495
- logger.info("Deleted single workbook revision (ID: {0}) (Revision: {1})".format(workbook_id, revision_number))
1011
+ logger.info(f"Deleted single workbook revision (ID: {workbook_id}) (Revision: {revision_number})")
496
1012
 
497
1013
  # a convenience method
498
1014
  @api(version="2.8")
499
1015
  def schedule_extract_refresh(
500
1016
  self, schedule_id: str, item: WorkbookItem
501
- ) -> List["AddResponse"]: # actually should return a task
1017
+ ) -> list["AddResponse"]: # actually should return a task
1018
+ """
1019
+ Adds a workbook to a schedule for extract refresh.
1020
+
1021
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#add_workbook_to_schedule
1022
+
1023
+ Parameters
1024
+ ----------
1025
+ schedule_id : str
1026
+ The schedule ID.
1027
+
1028
+ item : WorkbookItem
1029
+ The workbook item to add to the schedule.
1030
+
1031
+ Returns
1032
+ -------
1033
+ list[AddResponse]
1034
+ The response from the server.
1035
+ """
502
1036
  return self.parent_srv.schedules.add_to_schedule(schedule_id, workbook=item)
503
1037
 
504
1038
  @api(version="1.0")
505
- def add_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], str]) -> Set[str]:
1039
+ def add_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], str]) -> set[str]:
1040
+ """
1041
+ Adds tags to a workbook. One or more tags may be added at a time. If a
1042
+ tag already exists on the workbook, it will not be duplicated.
1043
+
1044
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#add_tags_to_workbook
1045
+
1046
+ Parameters
1047
+ ----------
1048
+ item : WorkbookItem | str
1049
+ The workbook item or workbook ID to add tags to.
1050
+
1051
+ tags : Iterable[str] | str
1052
+ The tag or tags to add to the workbook. Tags can be a single tag or
1053
+ a list of tags.
1054
+
1055
+ Returns
1056
+ -------
1057
+ set[str]
1058
+ The set of tags added to the workbook.
1059
+ """
506
1060
  return super().add_tags(item, tags)
507
1061
 
508
1062
  @api(version="1.0")
509
1063
  def delete_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], str]) -> None:
1064
+ """
1065
+ Deletes tags from a workbook. One or more tags may be deleted at a time.
1066
+
1067
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#delete_tag_from_workbook
1068
+
1069
+ Parameters
1070
+ ----------
1071
+ item : WorkbookItem | str
1072
+ The workbook item or workbook ID to delete tags from.
1073
+
1074
+ tags : Iterable[str] | str
1075
+ The tag or tags to delete from the workbook. Tags can be a single
1076
+ tag or a list of tags.
1077
+
1078
+ Returns
1079
+ -------
1080
+ None
1081
+ """
510
1082
  return super().delete_tags(item, tags)
511
1083
 
512
1084
  @api(version="1.0")
513
1085
  def update_tags(self, item: WorkbookItem) -> None:
1086
+ """
1087
+ Updates the tags on a workbook. This method is used to update the tags
1088
+ on the server to match the tags on the workbook item. This method is a
1089
+ convenience method that calls add_tags and delete_tags to update the
1090
+ tags on the server.
1091
+
1092
+ Parameters
1093
+ ----------
1094
+ item : WorkbookItem
1095
+ The workbook item to update the tags for. The tags on the workbook
1096
+ item will be used to update the tags on the server.
1097
+
1098
+ Returns
1099
+ -------
1100
+ None
1101
+ """
514
1102
  return super().update_tags(item)
515
1103
 
516
1104
  def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[WorkbookItem]: