tableauserverclient 0.32__py3-none-any.whl → 0.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tableauserverclient/__init__.py +34 -18
- tableauserverclient/_version.py +3 -3
- tableauserverclient/config.py +20 -6
- tableauserverclient/models/__init__.py +12 -0
- tableauserverclient/models/column_item.py +1 -1
- tableauserverclient/models/connection_credentials.py +1 -1
- tableauserverclient/models/connection_item.py +10 -8
- tableauserverclient/models/custom_view_item.py +29 -6
- 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 +8 -2
- 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 +12 -12
- tableauserverclient/models/flow_run_item.py +3 -3
- tableauserverclient/models/group_item.py +4 -4
- tableauserverclient/models/groupset_item.py +53 -0
- tableauserverclient/models/interval_item.py +36 -23
- tableauserverclient/models/job_item.py +26 -10
- tableauserverclient/models/linked_tasks_item.py +102 -0
- tableauserverclient/models/metric_item.py +5 -5
- tableauserverclient/models/pagination_item.py +1 -1
- tableauserverclient/models/permissions_item.py +19 -14
- tableauserverclient/models/project_item.py +35 -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 +11 -9
- tableauserverclient/models/tag_item.py +3 -4
- tableauserverclient/models/task_item.py +4 -4
- tableauserverclient/models/user_item.py +47 -17
- tableauserverclient/models/view_item.py +11 -10
- tableauserverclient/models/virtual_connection_item.py +78 -0
- tableauserverclient/models/webhook_item.py +6 -6
- tableauserverclient/models/workbook_item.py +90 -12
- tableauserverclient/namespace.py +1 -1
- tableauserverclient/server/__init__.py +2 -1
- tableauserverclient/server/endpoint/__init__.py +8 -0
- tableauserverclient/server/endpoint/auth_endpoint.py +68 -11
- tableauserverclient/server/endpoint/custom_views_endpoint.py +124 -19
- 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 +32 -17
- tableauserverclient/server/endpoint/datasources_endpoint.py +150 -59
- tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
- tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
- tableauserverclient/server/endpoint/endpoint.py +47 -31
- tableauserverclient/server/endpoint/exceptions.py +23 -7
- tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
- tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -13
- tableauserverclient/server/endpoint/flow_runs_endpoint.py +59 -17
- tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
- tableauserverclient/server/endpoint/flows_endpoint.py +73 -35
- tableauserverclient/server/endpoint/groups_endpoint.py +96 -27
- tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
- tableauserverclient/server/endpoint/jobs_endpoint.py +79 -12
- tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
- 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 +124 -30
- tableauserverclient/server/endpoint/resource_tagger.py +139 -6
- 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 +33 -19
- tableauserverclient/server/endpoint/tasks_endpoint.py +8 -8
- tableauserverclient/server/endpoint/users_endpoint.py +405 -19
- tableauserverclient/server/endpoint/views_endpoint.py +111 -25
- tableauserverclient/server/endpoint/virtual_connections_endpoint.py +174 -0
- tableauserverclient/server/endpoint/webhooks_endpoint.py +11 -11
- tableauserverclient/server/endpoint/workbooks_endpoint.py +735 -68
- tableauserverclient/server/filter.py +2 -2
- tableauserverclient/server/pager.py +8 -10
- tableauserverclient/server/query.py +70 -20
- tableauserverclient/server/request_factory.py +213 -41
- tableauserverclient/server/request_options.py +125 -145
- tableauserverclient/server/server.py +73 -9
- tableauserverclient/server/sort.py +2 -2
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/METADATA +17 -17
- tableauserverclient-0.34.dist-info/RECORD +106 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/WHEEL +1 -1
- tableauserverclient-0.32.dist-info/RECORD +0 -100
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE +0 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from typing_extensions import Self
|
|
4
5
|
|
|
6
|
+
from tableauserverclient.config import config
|
|
5
7
|
from tableauserverclient.models.property_decorators import property_is_int
|
|
6
8
|
import logging
|
|
7
9
|
|
|
8
10
|
from tableauserverclient.helpers.logging import logger
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
class RequestOptionsBase
|
|
13
|
+
class RequestOptionsBase:
|
|
12
14
|
# This method is used if server api version is below 3.7 (2020.1)
|
|
13
15
|
def apply_query_params(self, url):
|
|
14
16
|
try:
|
|
15
17
|
params = self.get_query_params()
|
|
16
|
-
params_list = ["{}={}"
|
|
18
|
+
params_list = [f"{k}={v}" for (k, v) in params.items()]
|
|
17
19
|
|
|
18
20
|
logger.debug("Applying options to request: <%s(%s)>", self.__class__.__name__, ",".join(params_list))
|
|
19
21
|
|
|
@@ -21,15 +23,52 @@ class RequestOptionsBase(object):
|
|
|
21
23
|
url, existing_params = url.split("?")
|
|
22
24
|
params_list.append(existing_params)
|
|
23
25
|
|
|
24
|
-
return "{
|
|
26
|
+
return "{}?{}".format(url, "&".join(params_list))
|
|
25
27
|
except NotImplementedError:
|
|
26
28
|
raise
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
|
|
31
|
+
# If it wasn't a breaking change, I'd rename it to QueryOptions
|
|
32
|
+
"""
|
|
33
|
+
This class manages options can be used when querying content on the server
|
|
34
|
+
"""
|
|
30
35
|
|
|
31
36
|
|
|
32
37
|
class RequestOptions(RequestOptionsBase):
|
|
38
|
+
def __init__(self, pagenumber=1, pagesize=None):
|
|
39
|
+
self.pagenumber = pagenumber
|
|
40
|
+
self.pagesize = pagesize or config.PAGE_SIZE
|
|
41
|
+
self.sort = set()
|
|
42
|
+
self.filter = set()
|
|
43
|
+
# This is private until we expand all of our parsers to handle the extra fields
|
|
44
|
+
self._all_fields = False
|
|
45
|
+
|
|
46
|
+
def get_query_params(self) -> dict:
|
|
47
|
+
params = {}
|
|
48
|
+
if self.sort and len(self.sort) > 0:
|
|
49
|
+
sort_options = (str(sort_item) for sort_item in self.sort)
|
|
50
|
+
ordered_sort_options = sorted(sort_options)
|
|
51
|
+
params["sort"] = ",".join(ordered_sort_options)
|
|
52
|
+
if len(self.filter) > 0:
|
|
53
|
+
filter_options = (str(filter_item) for filter_item in self.filter)
|
|
54
|
+
ordered_filter_options = sorted(filter_options)
|
|
55
|
+
params["filter"] = ",".join(ordered_filter_options)
|
|
56
|
+
if self._all_fields:
|
|
57
|
+
params["fields"] = "_all_"
|
|
58
|
+
if self.pagenumber:
|
|
59
|
+
params["pageNumber"] = self.pagenumber
|
|
60
|
+
if self.pagesize:
|
|
61
|
+
params["pageSize"] = self.pagesize
|
|
62
|
+
return params
|
|
63
|
+
|
|
64
|
+
def page_size(self, page_size):
|
|
65
|
+
self.pagesize = page_size
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def page_number(self, page_number):
|
|
69
|
+
self.pagenumber = page_number
|
|
70
|
+
return self
|
|
71
|
+
|
|
33
72
|
class Operator:
|
|
34
73
|
Equals = "eq"
|
|
35
74
|
GreaterThan = "gt"
|
|
@@ -38,7 +77,9 @@ class RequestOptions(RequestOptionsBase):
|
|
|
38
77
|
LessThanOrEqual = "lte"
|
|
39
78
|
In = "in"
|
|
40
79
|
Has = "has"
|
|
80
|
+
CaseInsensitiveEquals = "cieq"
|
|
41
81
|
|
|
82
|
+
# These are fields in the REST API
|
|
42
83
|
class Field:
|
|
43
84
|
Args = "args"
|
|
44
85
|
AuthenticationType = "authenticationType"
|
|
@@ -115,60 +156,53 @@ class RequestOptions(RequestOptionsBase):
|
|
|
115
156
|
Desc = "desc"
|
|
116
157
|
Asc = "asc"
|
|
117
158
|
|
|
118
|
-
def __init__(self, pagenumber=1, pagesize=100):
|
|
119
|
-
self.pagenumber = pagenumber
|
|
120
|
-
self.pagesize = pagesize
|
|
121
|
-
self.sort = set()
|
|
122
|
-
self.filter = set()
|
|
123
159
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def page_size(self, page_size):
|
|
128
|
-
self.pagesize = page_size
|
|
129
|
-
return self
|
|
160
|
+
"""
|
|
161
|
+
These options can be used by methods that are fetching data exported from a specific content item
|
|
162
|
+
"""
|
|
130
163
|
|
|
131
|
-
def page_number(self, page_number):
|
|
132
|
-
self.pagenumber = page_number
|
|
133
|
-
return self
|
|
134
|
-
|
|
135
|
-
def get_query_params(self):
|
|
136
|
-
params = {}
|
|
137
|
-
if self.pagenumber:
|
|
138
|
-
params["pageNumber"] = self.pagenumber
|
|
139
|
-
if self.pagesize:
|
|
140
|
-
params["pageSize"] = self.pagesize
|
|
141
|
-
if len(self.sort) > 0:
|
|
142
|
-
sort_options = (str(sort_item) for sort_item in self.sort)
|
|
143
|
-
ordered_sort_options = sorted(sort_options)
|
|
144
|
-
params["sort"] = ",".join(ordered_sort_options)
|
|
145
|
-
if len(self.filter) > 0:
|
|
146
|
-
filter_options = (str(filter_item) for filter_item in self.filter)
|
|
147
|
-
ordered_filter_options = sorted(filter_options)
|
|
148
|
-
params["filter"] = ",".join(ordered_filter_options)
|
|
149
|
-
if self._all_fields:
|
|
150
|
-
params["fields"] = "_all_"
|
|
151
|
-
return params
|
|
152
164
|
|
|
165
|
+
class _DataExportOptions(RequestOptionsBase):
|
|
166
|
+
def __init__(self, maxage: int = -1):
|
|
167
|
+
super().__init__()
|
|
168
|
+
self.view_filters: list[tuple[str, str]] = []
|
|
169
|
+
self.view_parameters: list[tuple[str, str]] = []
|
|
170
|
+
self.max_age: Optional[int] = maxage
|
|
171
|
+
"""
|
|
172
|
+
This setting will affect the contents of the workbook as they are exported.
|
|
173
|
+
Valid language values are tableau-supported languages like de, es, en
|
|
174
|
+
If no locale is specified, the default locale for that language will be used
|
|
175
|
+
"""
|
|
176
|
+
self.language: Optional[str] = None
|
|
153
177
|
|
|
154
|
-
|
|
155
|
-
|
|
178
|
+
@property
|
|
179
|
+
def max_age(self) -> int:
|
|
180
|
+
return self._max_age
|
|
156
181
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
@max_age.setter
|
|
183
|
+
@property_is_int(range=(0, 240), allowed=[-1])
|
|
184
|
+
def max_age(self, value):
|
|
185
|
+
self._max_age = value
|
|
160
186
|
|
|
161
187
|
def get_query_params(self):
|
|
162
|
-
|
|
188
|
+
params = {}
|
|
189
|
+
if self.max_age != -1:
|
|
190
|
+
params["maxAge"] = self.max_age
|
|
191
|
+
if self.language:
|
|
192
|
+
params["language"] = self.language
|
|
193
|
+
|
|
194
|
+
self._append_view_filters(params)
|
|
195
|
+
return params
|
|
163
196
|
|
|
164
197
|
def vf(self, name: str, value: str) -> Self:
|
|
165
|
-
"""Apply a filter
|
|
166
|
-
|
|
198
|
+
"""Apply a filter based on a column within the view.
|
|
199
|
+
Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'"""
|
|
167
200
|
self.view_filters.append((name, value))
|
|
168
201
|
return self
|
|
169
202
|
|
|
170
203
|
def parameter(self, name: str, value: str) -> Self:
|
|
171
|
-
"""Apply a filter based on a parameter within the workbook.
|
|
204
|
+
"""Apply a filter based on a parameter within the workbook.
|
|
205
|
+
Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'"""
|
|
172
206
|
self.view_parameters.append((name, value))
|
|
173
207
|
return self
|
|
174
208
|
|
|
@@ -179,82 +213,73 @@ class _FilterOptionsBase(RequestOptionsBase):
|
|
|
179
213
|
params[name] = value
|
|
180
214
|
|
|
181
215
|
|
|
182
|
-
class
|
|
183
|
-
def __init__(self, maxage=-1):
|
|
184
|
-
super(
|
|
185
|
-
self.
|
|
216
|
+
class _ImagePDFCommonExportOptions(_DataExportOptions):
|
|
217
|
+
def __init__(self, maxage=-1, viz_height=None, viz_width=None):
|
|
218
|
+
super().__init__(maxage=maxage)
|
|
219
|
+
self.viz_height = viz_height
|
|
220
|
+
self.viz_width = viz_width
|
|
186
221
|
|
|
187
222
|
@property
|
|
188
|
-
def
|
|
189
|
-
return self.
|
|
190
|
-
|
|
191
|
-
@max_age.setter
|
|
192
|
-
@property_is_int(range=(0, 240), allowed=[-1])
|
|
193
|
-
def max_age(self, value):
|
|
194
|
-
self._max_age = value
|
|
223
|
+
def viz_height(self):
|
|
224
|
+
return self._viz_height
|
|
195
225
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
226
|
+
@viz_height.setter
|
|
227
|
+
@property_is_int(range=(0, sys.maxsize), allowed=(None,))
|
|
228
|
+
def viz_height(self, value):
|
|
229
|
+
self._viz_height = value
|
|
200
230
|
|
|
201
|
-
|
|
202
|
-
|
|
231
|
+
@property
|
|
232
|
+
def viz_width(self):
|
|
233
|
+
return self._viz_width
|
|
203
234
|
|
|
235
|
+
@viz_width.setter
|
|
236
|
+
@property_is_int(range=(0, sys.maxsize), allowed=(None,))
|
|
237
|
+
def viz_width(self, value):
|
|
238
|
+
self._viz_width = value
|
|
204
239
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
super().__init__()
|
|
208
|
-
self.max_age = maxage
|
|
240
|
+
def get_query_params(self) -> dict:
|
|
241
|
+
params = super().get_query_params()
|
|
209
242
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
243
|
+
# XOR. Either both are None or both are not None.
|
|
244
|
+
if (self.viz_height is None) ^ (self.viz_width is None):
|
|
245
|
+
raise ValueError("viz_height and viz_width must be specified together")
|
|
213
246
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def max_age(self, value: int) -> None:
|
|
217
|
-
self._max_age = value
|
|
247
|
+
if self.viz_height is not None:
|
|
248
|
+
params["vizHeight"] = self.viz_height
|
|
218
249
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if self.max_age != -1:
|
|
222
|
-
params["maxAge"] = self.max_age
|
|
250
|
+
if self.viz_width is not None:
|
|
251
|
+
params["vizWidth"] = self.viz_width
|
|
223
252
|
|
|
224
|
-
self._append_view_filters(params)
|
|
225
253
|
return params
|
|
226
254
|
|
|
227
255
|
|
|
228
|
-
class
|
|
256
|
+
class CSVRequestOptions(_DataExportOptions):
|
|
257
|
+
extension = "csv"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class ExcelRequestOptions(_DataExportOptions):
|
|
261
|
+
extension = "xlsx"
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ImageRequestOptions(_ImagePDFCommonExportOptions):
|
|
265
|
+
extension = "png"
|
|
266
|
+
|
|
229
267
|
# if 'high' isn't specified, the REST API endpoint returns an image with standard resolution
|
|
230
268
|
class Resolution:
|
|
231
269
|
High = "high"
|
|
232
270
|
|
|
233
|
-
def __init__(self, imageresolution=None, maxage=-1):
|
|
234
|
-
super(
|
|
271
|
+
def __init__(self, imageresolution=None, maxage=-1, viz_height=None, viz_width=None):
|
|
272
|
+
super().__init__(maxage=maxage, viz_height=viz_height, viz_width=viz_width)
|
|
235
273
|
self.image_resolution = imageresolution
|
|
236
|
-
self.max_age = maxage
|
|
237
|
-
|
|
238
|
-
@property
|
|
239
|
-
def max_age(self):
|
|
240
|
-
return self._max_age
|
|
241
|
-
|
|
242
|
-
@max_age.setter
|
|
243
|
-
@property_is_int(range=(0, 240), allowed=[-1])
|
|
244
|
-
def max_age(self, value):
|
|
245
|
-
self._max_age = value
|
|
246
274
|
|
|
247
275
|
def get_query_params(self):
|
|
248
|
-
params =
|
|
276
|
+
params = super().get_query_params()
|
|
249
277
|
if self.image_resolution:
|
|
250
278
|
params["resolution"] = self.image_resolution
|
|
251
|
-
if self.max_age != -1:
|
|
252
|
-
params["maxAge"] = self.max_age
|
|
253
|
-
self._append_view_filters(params)
|
|
254
279
|
return params
|
|
255
280
|
|
|
256
281
|
|
|
257
|
-
class PDFRequestOptions(
|
|
282
|
+
class PDFRequestOptions(_ImagePDFCommonExportOptions):
|
|
258
283
|
class PageType:
|
|
259
284
|
A3 = "a3"
|
|
260
285
|
A4 = "a4"
|
|
@@ -276,61 +301,16 @@ class PDFRequestOptions(_FilterOptionsBase):
|
|
|
276
301
|
Landscape = "landscape"
|
|
277
302
|
|
|
278
303
|
def __init__(self, page_type=None, orientation=None, maxage=-1, viz_height=None, viz_width=None):
|
|
279
|
-
super(
|
|
304
|
+
super().__init__(maxage=maxage, viz_height=viz_height, viz_width=viz_width)
|
|
280
305
|
self.page_type = page_type
|
|
281
306
|
self.orientation = orientation
|
|
282
|
-
self.max_age = maxage
|
|
283
|
-
self.viz_height = viz_height
|
|
284
|
-
self.viz_width = viz_width
|
|
285
|
-
|
|
286
|
-
@property
|
|
287
|
-
def max_age(self):
|
|
288
|
-
return self._max_age
|
|
289
|
-
|
|
290
|
-
@max_age.setter
|
|
291
|
-
@property_is_int(range=(0, 240), allowed=[-1])
|
|
292
|
-
def max_age(self, value):
|
|
293
|
-
self._max_age = value
|
|
294
|
-
|
|
295
|
-
@property
|
|
296
|
-
def viz_height(self):
|
|
297
|
-
return self._viz_height
|
|
298
|
-
|
|
299
|
-
@viz_height.setter
|
|
300
|
-
@property_is_int(range=(0, sys.maxsize), allowed=(None,))
|
|
301
|
-
def viz_height(self, value):
|
|
302
|
-
self._viz_height = value
|
|
303
|
-
|
|
304
|
-
@property
|
|
305
|
-
def viz_width(self):
|
|
306
|
-
return self._viz_width
|
|
307
307
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def viz_width(self, value):
|
|
311
|
-
self._viz_width = value
|
|
312
|
-
|
|
313
|
-
def get_query_params(self):
|
|
314
|
-
params = {}
|
|
308
|
+
def get_query_params(self) -> dict:
|
|
309
|
+
params = super().get_query_params()
|
|
315
310
|
if self.page_type:
|
|
316
311
|
params["type"] = self.page_type
|
|
317
312
|
|
|
318
313
|
if self.orientation:
|
|
319
314
|
params["orientation"] = self.orientation
|
|
320
315
|
|
|
321
|
-
if self.max_age != -1:
|
|
322
|
-
params["maxAge"] = self.max_age
|
|
323
|
-
|
|
324
|
-
# XOR. Either both are None or both are not None.
|
|
325
|
-
if (self.viz_height is None) ^ (self.viz_width is None):
|
|
326
|
-
raise ValueError("viz_height and viz_width must be specified together")
|
|
327
|
-
|
|
328
|
-
if self.viz_height is not None:
|
|
329
|
-
params["vizHeight"] = self.viz_height
|
|
330
|
-
|
|
331
|
-
if self.viz_width is not None:
|
|
332
|
-
params["vizWidth"] = self.viz_width
|
|
333
|
-
|
|
334
|
-
self._append_view_filters(params)
|
|
335
|
-
|
|
336
316
|
return params
|
|
@@ -33,6 +33,10 @@ from tableauserverclient.server.endpoint import (
|
|
|
33
33
|
Metrics,
|
|
34
34
|
Endpoint,
|
|
35
35
|
CustomViews,
|
|
36
|
+
LinkedTasks,
|
|
37
|
+
GroupSets,
|
|
38
|
+
Tags,
|
|
39
|
+
VirtualConnections,
|
|
36
40
|
)
|
|
37
41
|
from tableauserverclient.server.exceptions import (
|
|
38
42
|
ServerInfoEndpointNotFoundError,
|
|
@@ -54,8 +58,64 @@ minimum_supported_server_version = "2.3"
|
|
|
54
58
|
default_server_version = "2.4" # first version that dropped the legacy auth endpoint
|
|
55
59
|
|
|
56
60
|
|
|
57
|
-
class Server
|
|
61
|
+
class Server:
|
|
62
|
+
"""
|
|
63
|
+
In the Tableau REST API, the server (https://MY-SERVER/) is the base or core
|
|
64
|
+
of the URI that makes up the various endpoints or methods for accessing
|
|
65
|
+
resources on the server (views, workbooks, sites, users, data sources, etc.)
|
|
66
|
+
The TSC library provides a Server class that represents the server. You
|
|
67
|
+
create a server instance to sign in to the server and to call the various
|
|
68
|
+
methods for accessing resources.
|
|
69
|
+
|
|
70
|
+
The Server class contains the attributes that represent the server on
|
|
71
|
+
Tableau Server. After you create an instance of the Server class, you can
|
|
72
|
+
sign in to the server and call methods to access all of the resources on the
|
|
73
|
+
server.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
server_address : str
|
|
78
|
+
Specifies the address of the Tableau Server or Tableau Cloud (for
|
|
79
|
+
example, https://MY-SERVER/).
|
|
80
|
+
|
|
81
|
+
use_server_version : bool
|
|
82
|
+
Specifies the version of the REST API to use (for example, '2.5'). When
|
|
83
|
+
you use the TSC library to call methods that access Tableau Server, the
|
|
84
|
+
version is passed to the endpoint as part of the URI
|
|
85
|
+
(https://MY-SERVER/api/2.5/). Each release of Tableau Server supports
|
|
86
|
+
specific versions of the REST API. New versions of the REST API are
|
|
87
|
+
released with Tableau Server. By default, the value of version is set to
|
|
88
|
+
'2.3', which corresponds to Tableau Server 10.0. You can view or set
|
|
89
|
+
this value. You might need to set this to a different value, for
|
|
90
|
+
example, if you want to access features that are supported by the server
|
|
91
|
+
and a later version of the REST API. For more information, see REST API
|
|
92
|
+
Versions.
|
|
93
|
+
|
|
94
|
+
Examples
|
|
95
|
+
--------
|
|
96
|
+
>>> import tableauserverclient as TSC
|
|
97
|
+
|
|
98
|
+
>>> # create a instance of server
|
|
99
|
+
>>> server = TSC.Server('https://MY-SERVER')
|
|
100
|
+
|
|
101
|
+
>>> # sign in, etc.
|
|
102
|
+
|
|
103
|
+
>>> # change the REST API version to match the server
|
|
104
|
+
>>> server.use_server_version()
|
|
105
|
+
|
|
106
|
+
>>> # or change the REST API version to match a specific version
|
|
107
|
+
>>> # for example, 2.8
|
|
108
|
+
>>> # server.version = '2.8'
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
|
|
58
112
|
class PublishMode:
|
|
113
|
+
"""
|
|
114
|
+
Enumerates the options that specify what happens when you publish a
|
|
115
|
+
workbook or data source. The options are Overwrite, Append, or
|
|
116
|
+
CreateNew.
|
|
117
|
+
"""
|
|
118
|
+
|
|
59
119
|
Append = "Append"
|
|
60
120
|
Overwrite = "Overwrite"
|
|
61
121
|
CreateNew = "CreateNew"
|
|
@@ -99,6 +159,10 @@ class Server(object):
|
|
|
99
159
|
self.flow_runs = FlowRuns(self)
|
|
100
160
|
self.metrics = Metrics(self)
|
|
101
161
|
self.custom_views = CustomViews(self)
|
|
162
|
+
self.linked_tasks = LinkedTasks(self)
|
|
163
|
+
self.group_sets = GroupSets(self)
|
|
164
|
+
self.tags = Tags(self)
|
|
165
|
+
self.virtual_connections = VirtualConnections(self)
|
|
102
166
|
|
|
103
167
|
self._session = self._session_factory()
|
|
104
168
|
self._http_options = dict() # must set this before making a server call
|
|
@@ -122,7 +186,7 @@ class Server(object):
|
|
|
122
186
|
raise ValueError("Server connection settings not valid", req_ex)
|
|
123
187
|
|
|
124
188
|
def __repr__(self):
|
|
125
|
-
return "<TableauServerClient [Connection: {
|
|
189
|
+
return f"<TableauServerClient [Connection: {self.baseurl}, {self.server_info.serverInfo}]>"
|
|
126
190
|
|
|
127
191
|
def add_http_options(self, options_dict: dict):
|
|
128
192
|
try:
|
|
@@ -134,7 +198,7 @@ class Server(object):
|
|
|
134
198
|
# expected errors on invalid input:
|
|
135
199
|
# 'set' object has no attribute 'keys', 'list' object has no attribute 'keys'
|
|
136
200
|
# TypeError: cannot convert dictionary update sequence element #0 to a sequence (input is a tuple)
|
|
137
|
-
raise ValueError("Invalid http options given: {}"
|
|
201
|
+
raise ValueError(f"Invalid http options given: {options_dict}")
|
|
138
202
|
|
|
139
203
|
def clear_http_options(self):
|
|
140
204
|
self._http_options = dict()
|
|
@@ -168,15 +232,15 @@ class Server(object):
|
|
|
168
232
|
old_version = self.version
|
|
169
233
|
version = self.server_info.get().rest_api_version
|
|
170
234
|
except ServerInfoEndpointNotFoundError as e:
|
|
171
|
-
logger.info("Could not get version info from server: {}{}"
|
|
235
|
+
logger.info(f"Could not get version info from server: {e.__class__}{e}")
|
|
172
236
|
version = self._get_legacy_version()
|
|
173
237
|
except EndpointUnavailableError as e:
|
|
174
|
-
logger.info("Could not get version info from server: {}{}"
|
|
238
|
+
logger.info(f"Could not get version info from server: {e.__class__}{e}")
|
|
175
239
|
version = self._get_legacy_version()
|
|
176
240
|
except Exception as e:
|
|
177
|
-
logger.info("Could not get version info from server: {}{}"
|
|
241
|
+
logger.info(f"Could not get version info from server: {e.__class__}{e}")
|
|
178
242
|
version = None
|
|
179
|
-
logger.info("versions: {}, {}"
|
|
243
|
+
logger.info(f"versions: {version}, {old_version}")
|
|
180
244
|
return version or old_version
|
|
181
245
|
|
|
182
246
|
def use_server_version(self):
|
|
@@ -193,12 +257,12 @@ class Server(object):
|
|
|
193
257
|
|
|
194
258
|
def assert_at_least_version(self, comparison: str, reason: str):
|
|
195
259
|
if not self.check_at_least_version(comparison):
|
|
196
|
-
error = "{} is not available in API version {}. Requires {}"
|
|
260
|
+
error = f"{reason} is not available in API version {self.version}. Requires {comparison}"
|
|
197
261
|
raise EndpointUnavailableError(error)
|
|
198
262
|
|
|
199
263
|
@property
|
|
200
264
|
def baseurl(self):
|
|
201
|
-
return "{
|
|
265
|
+
return f"{self._server_address}/api/{str(self.version)}"
|
|
202
266
|
|
|
203
267
|
@property
|
|
204
268
|
def namespace(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tableauserverclient
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.34
|
|
4
4
|
Summary: A Python module for working with the Tableau Server REST API.
|
|
5
5
|
Author-email: Tableau <github@tableau.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -28,28 +28,28 @@ License: The MIT License (MIT)
|
|
|
28
28
|
Project-URL: repository, https://github.com/tableau/server-client-python
|
|
29
29
|
Classifier: Programming Language :: Python
|
|
30
30
|
Classifier: Programming Language :: Python :: 3
|
|
31
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
32
31
|
Classifier: Programming Language :: Python :: 3.9
|
|
33
32
|
Classifier: Programming Language :: Python :: 3.10
|
|
34
33
|
Classifier: Programming Language :: Python :: 3.11
|
|
35
34
|
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
-
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
+
Requires-Python: >=3.9
|
|
37
37
|
Description-Content-Type: text/markdown
|
|
38
38
|
License-File: LICENSE
|
|
39
39
|
License-File: LICENSE.versioneer
|
|
40
|
-
Requires-Dist: defusedxml
|
|
41
|
-
Requires-Dist: packaging
|
|
42
|
-
Requires-Dist: requests
|
|
43
|
-
Requires-Dist: urllib3
|
|
44
|
-
Requires-Dist: typing-extensions
|
|
40
|
+
Requires-Dist: defusedxml>=0.7.1
|
|
41
|
+
Requires-Dist: packaging>=23.1
|
|
42
|
+
Requires-Dist: requests>=2.32
|
|
43
|
+
Requires-Dist: urllib3<3,>=2.2.2
|
|
44
|
+
Requires-Dist: typing-extensions>=4.0.1
|
|
45
45
|
Provides-Extra: test
|
|
46
|
-
Requires-Dist: black
|
|
47
|
-
Requires-Dist: build
|
|
48
|
-
Requires-Dist: mypy
|
|
49
|
-
Requires-Dist: pytest
|
|
50
|
-
Requires-Dist: pytest-cov
|
|
51
|
-
Requires-Dist: pytest-subtests
|
|
52
|
-
Requires-Dist: requests-mock
|
|
46
|
+
Requires-Dist: black==24.8; extra == "test"
|
|
47
|
+
Requires-Dist: build; extra == "test"
|
|
48
|
+
Requires-Dist: mypy==1.4; extra == "test"
|
|
49
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
50
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
51
|
+
Requires-Dist: pytest-subtests; extra == "test"
|
|
52
|
+
Requires-Dist: requests-mock<2.0,>=1.0; extra == "test"
|
|
53
53
|
|
|
54
54
|
# Tableau Server Client (Python)
|
|
55
55
|
|
|
@@ -62,14 +62,14 @@ Use the Tableau Server Client (TSC) library to increase your productivity as you
|
|
|
62
62
|
* Create users and groups.
|
|
63
63
|
* Query projects, sites, and more.
|
|
64
64
|
|
|
65
|
-
This repository contains Python source code for the library and sample files showing how to use it. As of
|
|
65
|
+
This repository contains Python source code for the library and sample files showing how to use it. As of September 2024, support for Python 3.7 and 3.8 will be dropped - support for older versions of Python aims to match https://devguide.python.org/versions/
|
|
66
66
|
|
|
67
67
|
To see sample code that works directly with the REST API (in Java, Python, or Postman), visit the [REST API Samples](https://github.com/tableau/rest-api-samples) repo.
|
|
68
68
|
|
|
69
69
|
For more information on installing and using TSC, see the documentation:
|
|
70
70
|
<https://tableau.github.io/server-client-python/docs/>
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
To contribute, see our [Developer Guide](https://tableau.github.io/server-client-python/docs/dev-guide). A list of all our contributors to date is in [CONTRIBUTORS.md].
|
|
73
73
|
|
|
74
74
|
## License
|
|
75
75
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2Ftableau%2Fserver-client-python?ref=badge_large)
|