tableauserverclient 0.34__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 +5 -1
- tableauserverclient/{_version.py → bin/_version.py} +3 -3
- tableauserverclient/models/connection_credentials.py +17 -1
- tableauserverclient/models/connection_item.py +38 -0
- tableauserverclient/models/custom_view_item.py +49 -5
- tableauserverclient/models/flow_item.py +49 -4
- tableauserverclient/models/group_item.py +40 -0
- tableauserverclient/models/job_item.py +65 -0
- tableauserverclient/models/project_item.py +39 -1
- tableauserverclient/models/task_item.py +30 -0
- tableauserverclient/models/view_item.py +55 -3
- tableauserverclient/models/webhook_item.py +33 -0
- tableauserverclient/models/workbook_item.py +26 -1
- tableauserverclient/server/endpoint/auth_endpoint.py +4 -2
- tableauserverclient/server/endpoint/custom_views_endpoint.py +197 -12
- tableauserverclient/server/endpoint/datasources_endpoint.py +13 -9
- tableauserverclient/server/endpoint/flows_endpoint.py +314 -0
- tableauserverclient/server/endpoint/groups_endpoint.py +325 -11
- tableauserverclient/server/endpoint/jobs_endpoint.py +109 -0
- tableauserverclient/server/endpoint/projects_endpoint.py +600 -0
- tableauserverclient/server/endpoint/tasks_endpoint.py +78 -0
- tableauserverclient/server/endpoint/views_endpoint.py +243 -2
- tableauserverclient/server/endpoint/webhooks_endpoint.py +77 -0
- tableauserverclient/server/endpoint/workbooks_endpoint.py +6 -4
- tableauserverclient/server/pager.py +24 -0
- tableauserverclient/server/request_factory.py +20 -1
- tableauserverclient/server/request_options.py +126 -2
- tableauserverclient/server/server.py +11 -1
- tableauserverclient/server/sort.py +14 -0
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/METADATA +2 -2
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/RECORD +35 -35
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/WHEEL +1 -1
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/LICENSE +0 -0
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.34.dist-info → tableauserverclient-0.35.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
import os
|
|
4
4
|
from contextlib import closing
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Optional, Union
|
|
6
|
+
from typing import Optional, Union, TYPE_CHECKING
|
|
7
7
|
from collections.abc import Iterator
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.config import BYTES_PER_MB, config
|
|
@@ -21,6 +21,9 @@ from tableauserverclient.server import (
|
|
|
21
21
|
|
|
22
22
|
from tableauserverclient.helpers.logging import logger
|
|
23
23
|
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from tableauserverclient.server.query import QuerySet
|
|
26
|
+
|
|
24
27
|
"""
|
|
25
28
|
Get a list of custom views on a site
|
|
26
29
|
get the details of a custom view
|
|
@@ -51,19 +54,31 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
51
54
|
def expurl(self) -> str:
|
|
52
55
|
return f"{self.parent_srv._server_address}/api/exp/sites/{self.parent_srv.site_id}/customviews"
|
|
53
56
|
|
|
54
|
-
"""
|
|
55
|
-
If the request has no filter parameters: Administrators will see all custom views.
|
|
56
|
-
Other users will see only custom views that they own.
|
|
57
|
-
If the filter parameters include ownerId: Users will see only custom views that they own.
|
|
58
|
-
If the filter parameters include viewId and/or workbookId, and don't include ownerId:
|
|
59
|
-
Users will see those custom views that they have Write and WebAuthoring permissions for.
|
|
60
|
-
If site user visibility is not set to Limited, the Users will see those custom views that are "public",
|
|
61
|
-
meaning the value of their shared attribute is true.
|
|
62
|
-
If site user visibility is set to Limited, ????
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
57
|
@api(version="3.18")
|
|
66
58
|
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[CustomViewItem], PaginationItem]:
|
|
59
|
+
"""
|
|
60
|
+
Get a list of custom views on a site.
|
|
61
|
+
|
|
62
|
+
If the request has no filter parameters: Administrators will see all custom views.
|
|
63
|
+
Other users will see only custom views that they own.
|
|
64
|
+
If the filter parameters include ownerId: Users will see only custom views that they own.
|
|
65
|
+
If the filter parameters include viewId and/or workbookId, and don't include ownerId:
|
|
66
|
+
Users will see those custom views that they have Write and WebAuthoring permissions for.
|
|
67
|
+
If site user visibility is not set to Limited, the Users will see those custom views that are "public",
|
|
68
|
+
meaning the value of their shared attribute is true.
|
|
69
|
+
If site user visibility is set to Limited, ????
|
|
70
|
+
|
|
71
|
+
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#list_custom_views
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
req_options : RequestOptions, optional
|
|
76
|
+
Filtering options for the request, by default None
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
tuple[list[CustomViewItem], PaginationItem]
|
|
81
|
+
"""
|
|
67
82
|
logger.info("Querying all custom views on site")
|
|
68
83
|
url = self.baseurl
|
|
69
84
|
server_response = self.get_request(url, req_options)
|
|
@@ -73,6 +88,19 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
73
88
|
|
|
74
89
|
@api(version="3.18")
|
|
75
90
|
def get_by_id(self, view_id: str) -> Optional[CustomViewItem]:
|
|
91
|
+
"""
|
|
92
|
+
Get the details of a specific custom view.
|
|
93
|
+
|
|
94
|
+
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_custom_view
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
view_id : str
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
Optional[CustomViewItem]
|
|
103
|
+
"""
|
|
76
104
|
if not view_id:
|
|
77
105
|
error = "Custom view item missing ID."
|
|
78
106
|
raise MissingRequiredFieldError(error)
|
|
@@ -83,6 +111,27 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
83
111
|
|
|
84
112
|
@api(version="3.18")
|
|
85
113
|
def populate_image(self, view_item: CustomViewItem, req_options: Optional["ImageRequestOptions"] = None) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Populate the image of a custom view.
|
|
116
|
+
|
|
117
|
+
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_custom_view_image
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
view_item : CustomViewItem
|
|
122
|
+
|
|
123
|
+
req_options : ImageRequestOptions, optional
|
|
124
|
+
Options to customize the image returned, by default None
|
|
125
|
+
|
|
126
|
+
Returns
|
|
127
|
+
-------
|
|
128
|
+
None
|
|
129
|
+
|
|
130
|
+
Raises
|
|
131
|
+
------
|
|
132
|
+
MissingRequiredFieldError
|
|
133
|
+
If the view_item is missing an ID
|
|
134
|
+
"""
|
|
86
135
|
if not view_item.id:
|
|
87
136
|
error = "Custom View item missing ID."
|
|
88
137
|
raise MissingRequiredFieldError(error)
|
|
@@ -101,6 +150,26 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
101
150
|
|
|
102
151
|
@api(version="3.23")
|
|
103
152
|
def populate_pdf(self, custom_view_item: CustomViewItem, req_options: Optional["PDFRequestOptions"] = None) -> None:
|
|
153
|
+
"""
|
|
154
|
+
Populate the PDF of a custom view.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
custom_view_item : CustomViewItem
|
|
159
|
+
The custom view item to populate the PDF for.
|
|
160
|
+
|
|
161
|
+
req_options : PDFRequestOptions, optional
|
|
162
|
+
Options to customize the PDF returned, by default None
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
None
|
|
167
|
+
|
|
168
|
+
Raises
|
|
169
|
+
------
|
|
170
|
+
MissingRequiredFieldError
|
|
171
|
+
If the custom view item is missing an ID
|
|
172
|
+
"""
|
|
104
173
|
if not custom_view_item.id:
|
|
105
174
|
error = "Custom View item missing ID."
|
|
106
175
|
raise MissingRequiredFieldError(error)
|
|
@@ -121,6 +190,26 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
121
190
|
|
|
122
191
|
@api(version="3.23")
|
|
123
192
|
def populate_csv(self, custom_view_item: CustomViewItem, req_options: Optional["CSVRequestOptions"] = None) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Populate the CSV of a custom view.
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
custom_view_item : CustomViewItem
|
|
199
|
+
The custom view item to populate the CSV for.
|
|
200
|
+
|
|
201
|
+
req_options : CSVRequestOptions, optional
|
|
202
|
+
Options to customize the CSV returned, by default None
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
None
|
|
207
|
+
|
|
208
|
+
Raises
|
|
209
|
+
------
|
|
210
|
+
MissingRequiredFieldError
|
|
211
|
+
If the custom view item is missing an ID
|
|
212
|
+
"""
|
|
124
213
|
if not custom_view_item.id:
|
|
125
214
|
error = "Custom View item missing ID."
|
|
126
215
|
raise MissingRequiredFieldError(error)
|
|
@@ -141,6 +230,21 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
141
230
|
|
|
142
231
|
@api(version="3.18")
|
|
143
232
|
def update(self, view_item: CustomViewItem) -> Optional[CustomViewItem]:
|
|
233
|
+
"""
|
|
234
|
+
Updates the name, owner, or shared status of a custom view.
|
|
235
|
+
|
|
236
|
+
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_custom_view
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
view_item : CustomViewItem
|
|
241
|
+
The custom view item to update.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
Optional[CustomViewItem]
|
|
246
|
+
The updated custom view item.
|
|
247
|
+
"""
|
|
144
248
|
if not view_item.id:
|
|
145
249
|
error = "Custom view item missing ID."
|
|
146
250
|
raise MissingRequiredFieldError(error)
|
|
@@ -158,6 +262,25 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
158
262
|
# Delete 1 view by id
|
|
159
263
|
@api(version="3.19")
|
|
160
264
|
def delete(self, view_id: str) -> None:
|
|
265
|
+
"""
|
|
266
|
+
Deletes a single custom view by ID.
|
|
267
|
+
|
|
268
|
+
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#delete_custom_view
|
|
269
|
+
|
|
270
|
+
Parameters
|
|
271
|
+
----------
|
|
272
|
+
view_id : str
|
|
273
|
+
The ID of the custom view to delete.
|
|
274
|
+
|
|
275
|
+
Returns
|
|
276
|
+
-------
|
|
277
|
+
None
|
|
278
|
+
|
|
279
|
+
Raises
|
|
280
|
+
------
|
|
281
|
+
ValueError
|
|
282
|
+
If the view_id is not provided.
|
|
283
|
+
"""
|
|
161
284
|
if not view_id:
|
|
162
285
|
error = "Custom View ID undefined."
|
|
163
286
|
raise ValueError(error)
|
|
@@ -167,6 +290,27 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
167
290
|
|
|
168
291
|
@api(version="3.21")
|
|
169
292
|
def download(self, view_item: CustomViewItem, file: PathOrFileW) -> PathOrFileW:
|
|
293
|
+
"""
|
|
294
|
+
Download the definition of a custom view as json. The file parameter can
|
|
295
|
+
be a file path or a file object. If a file path is provided, the file
|
|
296
|
+
will be written to that location. If a file object is provided, the file
|
|
297
|
+
will be written to that object.
|
|
298
|
+
|
|
299
|
+
May contain sensitive information.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
view_item : CustomViewItem
|
|
304
|
+
The custom view item to download.
|
|
305
|
+
|
|
306
|
+
file : PathOrFileW
|
|
307
|
+
The file path or file object to write the custom view to.
|
|
308
|
+
|
|
309
|
+
Returns
|
|
310
|
+
-------
|
|
311
|
+
PathOrFileW
|
|
312
|
+
The file path or file object that the custom view was written to.
|
|
313
|
+
"""
|
|
170
314
|
url = f"{self.expurl}/{view_item.id}/content"
|
|
171
315
|
server_response = self.get_request(url)
|
|
172
316
|
if isinstance(file, io_types_w):
|
|
@@ -180,6 +324,25 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
180
324
|
|
|
181
325
|
@api(version="3.21")
|
|
182
326
|
def publish(self, view_item: CustomViewItem, file: PathOrFileR) -> Optional[CustomViewItem]:
|
|
327
|
+
"""
|
|
328
|
+
Publish a custom view to Tableau Server. The file parameter can be a
|
|
329
|
+
file path or a file object. If a file path is provided, the file will be
|
|
330
|
+
read from that location. If a file object is provided, the file will be
|
|
331
|
+
read from that object.
|
|
332
|
+
|
|
333
|
+
Parameters
|
|
334
|
+
----------
|
|
335
|
+
view_item : CustomViewItem
|
|
336
|
+
The custom view item to publish.
|
|
337
|
+
|
|
338
|
+
file : PathOrFileR
|
|
339
|
+
The file path or file object to read the custom view from.
|
|
340
|
+
|
|
341
|
+
Returns
|
|
342
|
+
-------
|
|
343
|
+
Optional[CustomViewItem]
|
|
344
|
+
The published custom view item.
|
|
345
|
+
"""
|
|
183
346
|
url = self.expurl
|
|
184
347
|
if isinstance(file, io_types_r):
|
|
185
348
|
size = get_file_object_size(file)
|
|
@@ -207,3 +370,25 @@ class CustomViews(QuerysetEndpoint[CustomViewItem]):
|
|
|
207
370
|
|
|
208
371
|
server_response = self.post_request(url, xml_request, content_type)
|
|
209
372
|
return CustomViewItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
373
|
+
|
|
374
|
+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> "QuerySet[CustomViewItem]":
|
|
375
|
+
"""
|
|
376
|
+
Queries the Tableau Server for items using the specified filters. Page
|
|
377
|
+
size can be specified to limit the number of items returned in a single
|
|
378
|
+
request. If not specified, the default page size is 100. Page size can
|
|
379
|
+
be an integer between 1 and 1000.
|
|
380
|
+
|
|
381
|
+
No positional arguments are allowed. All filters must be specified as
|
|
382
|
+
keyword arguments. If you use the equality operator, you can specify it
|
|
383
|
+
through <field_name>=<value>. If you want to use a different operator,
|
|
384
|
+
you can specify it through <field_name>__<operator>=<value>. Field
|
|
385
|
+
names can either be in snake_case or camelCase.
|
|
386
|
+
|
|
387
|
+
This endpoint supports the following fields and operators:
|
|
388
|
+
|
|
389
|
+
view_id=...
|
|
390
|
+
workbook_id=...
|
|
391
|
+
owner_id=...
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
return super().filter(*invalid, page_size=page_size, **kwargs)
|
|
@@ -102,10 +102,15 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
102
102
|
datasource_item._set_connections(connections_fetcher)
|
|
103
103
|
logger.info(f"Populated connections for datasource (ID: {datasource_item.id})")
|
|
104
104
|
|
|
105
|
-
def _get_datasource_connections(
|
|
105
|
+
def _get_datasource_connections(
|
|
106
|
+
self, datasource_item: DatasourceItem, req_options: Optional[RequestOptions] = None
|
|
107
|
+
) -> list[ConnectionItem]:
|
|
106
108
|
url = f"{self.baseurl}/{datasource_item.id}/connections"
|
|
107
109
|
server_response = self.get_request(url, req_options)
|
|
108
110
|
connections = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
111
|
+
for connection in connections:
|
|
112
|
+
connection._datasource_id = datasource_item.id
|
|
113
|
+
connection._datasource_name = datasource_item.name
|
|
109
114
|
return connections
|
|
110
115
|
|
|
111
116
|
# Delete 1 datasource by id
|
|
@@ -182,11 +187,11 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
182
187
|
return connection
|
|
183
188
|
|
|
184
189
|
@api(version="2.8")
|
|
185
|
-
def refresh(self, datasource_item: DatasourceItem) -> JobItem:
|
|
190
|
+
def refresh(self, datasource_item: DatasourceItem, incremental: bool = False) -> JobItem:
|
|
186
191
|
id_ = getattr(datasource_item, "id", datasource_item)
|
|
187
192
|
url = f"{self.baseurl}/{id_}/refresh"
|
|
188
|
-
|
|
189
|
-
server_response = self.post_request(url,
|
|
193
|
+
refresh_req = RequestFactory.Task.refresh_req(incremental)
|
|
194
|
+
server_response = self.post_request(url, refresh_req)
|
|
190
195
|
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
191
196
|
return new_job
|
|
192
197
|
|
|
@@ -255,13 +260,12 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
255
260
|
else:
|
|
256
261
|
raise TypeError("file should be a filepath or file object.")
|
|
257
262
|
|
|
258
|
-
if not mode or not hasattr(self.parent_srv.PublishMode, mode):
|
|
259
|
-
error = "Invalid mode defined."
|
|
260
|
-
raise ValueError(error)
|
|
261
|
-
|
|
262
263
|
# Construct the url with the defined mode
|
|
263
264
|
url = f"{self.baseurl}?datasourceType={file_extension}"
|
|
264
|
-
if mode
|
|
265
|
+
if not mode or not hasattr(self.parent_srv.PublishMode, mode):
|
|
266
|
+
error = f"Invalid mode defined: {mode}"
|
|
267
|
+
raise ValueError(error)
|
|
268
|
+
else:
|
|
265
269
|
url += f"&{mode.lower()}=true"
|
|
266
270
|
|
|
267
271
|
if as_job:
|