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
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ from typing import Optional
2
3
 
3
4
  from typing_extensions import Self
4
5
 
@@ -9,12 +10,12 @@ import logging
9
10
  from tableauserverclient.helpers.logging import logger
10
11
 
11
12
 
12
- class RequestOptionsBase(object):
13
+ class RequestOptionsBase:
13
14
  # This method is used if server api version is below 3.7 (2020.1)
14
15
  def apply_query_params(self, url):
15
16
  try:
16
17
  params = self.get_query_params()
17
- params_list = ["{}={}".format(k, v) for (k, v) in params.items()]
18
+ params_list = [f"{k}={v}" for (k, v) in params.items()]
18
19
 
19
20
  logger.debug("Applying options to request: <%s(%s)>", self.__class__.__name__, ",".join(params_list))
20
21
 
@@ -22,15 +23,74 @@ class RequestOptionsBase(object):
22
23
  url, existing_params = url.split("?")
23
24
  params_list.append(existing_params)
24
25
 
25
- return "{0}?{1}".format(url, "&".join(params_list))
26
+ return "{}?{}".format(url, "&".join(params_list))
26
27
  except NotImplementedError:
27
28
  raise
28
29
 
29
- def get_query_params(self):
30
- raise NotImplementedError()
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
+ """
31
35
 
32
36
 
33
37
  class RequestOptions(RequestOptionsBase):
38
+ """
39
+ This class is used to manage the options that can be used when querying content on the server.
40
+ Optionally initialize with a page number and page size to control the number of items returned.
41
+
42
+ Additionally, you can add sorting and filtering options to the request.
43
+
44
+ The `sort` and `filter` options are set-like objects, so you can only add a field once. If you add the same field
45
+ multiple times, only the last one will be used.
46
+
47
+ The list of fields that can be sorted on or filtered by can be found in the `Field`
48
+ class contained within this class.
49
+
50
+ Parameters
51
+ ----------
52
+ pagenumber: int, optional
53
+ The page number to start the query on. Default is 1.
54
+
55
+ pagesize: int, optional
56
+ The number of items to return per page. Default is 100. Can also read
57
+ from the environment variable `TSC_PAGE_SIZE`
58
+ """
59
+
60
+ def __init__(self, pagenumber=1, pagesize=None):
61
+ self.pagenumber = pagenumber
62
+ self.pagesize = pagesize or config.PAGE_SIZE
63
+ self.sort = set()
64
+ self.filter = set()
65
+ # This is private until we expand all of our parsers to handle the extra fields
66
+ self._all_fields = False
67
+
68
+ def get_query_params(self) -> dict:
69
+ params = {}
70
+ if self.sort and len(self.sort) > 0:
71
+ sort_options = (str(sort_item) for sort_item in self.sort)
72
+ ordered_sort_options = sorted(sort_options)
73
+ params["sort"] = ",".join(ordered_sort_options)
74
+ if len(self.filter) > 0:
75
+ filter_options = (str(filter_item) for filter_item in self.filter)
76
+ ordered_filter_options = sorted(filter_options)
77
+ params["filter"] = ",".join(ordered_filter_options)
78
+ if self._all_fields:
79
+ params["fields"] = "_all_"
80
+ if self.pagenumber:
81
+ params["pageNumber"] = self.pagenumber
82
+ if self.pagesize:
83
+ params["pageSize"] = self.pagesize
84
+ return params
85
+
86
+ def page_size(self, page_size):
87
+ self.pagesize = page_size
88
+ return self
89
+
90
+ def page_number(self, page_number):
91
+ self.pagenumber = page_number
92
+ return self
93
+
34
94
  class Operator:
35
95
  Equals = "eq"
36
96
  GreaterThan = "gt"
@@ -41,6 +101,7 @@ class RequestOptions(RequestOptionsBase):
41
101
  Has = "has"
42
102
  CaseInsensitiveEquals = "cieq"
43
103
 
104
+ # These are fields in the REST API
44
105
  class Field:
45
106
  Args = "args"
46
107
  AuthenticationType = "authenticationType"
@@ -83,6 +144,7 @@ class RequestOptions(RequestOptionsBase):
83
144
  NotificationType = "notificationType"
84
145
  OwnerDomain = "ownerDomain"
85
146
  OwnerEmail = "ownerEmail"
147
+ OwnerId = "ownerId"
86
148
  OwnerName = "ownerName"
87
149
  ParentProjectId = "parentProjectId"
88
150
  Priority = "priority"
@@ -109,68 +171,93 @@ class RequestOptions(RequestOptionsBase):
109
171
  UpdatedAt = "updatedAt"
110
172
  UserCount = "userCount"
111
173
  UserId = "userId"
174
+ ViewId = "viewId"
112
175
  ViewUrlName = "viewUrlName"
113
176
  WorkbookDescription = "workbookDescription"
177
+ WorkbookId = "workbookId"
114
178
  WorkbookName = "workbookName"
115
179
 
116
180
  class Direction:
117
181
  Desc = "desc"
118
182
  Asc = "asc"
119
183
 
120
- def __init__(self, pagenumber=1, pagesize=None):
121
- self.pagenumber = pagenumber
122
- self.pagesize = pagesize or config.PAGE_SIZE
123
- self.sort = set()
124
- self.filter = set()
125
184
 
126
- # This is private until we expand all of our parsers to handle the extra fields
127
- self._all_fields = False
185
+ """
186
+ These options can be used by methods that are fetching data exported from a specific content item
187
+ """
128
188
 
129
- def page_size(self, page_size):
130
- self.pagesize = page_size
131
- return self
132
189
 
133
- def page_number(self, page_number):
134
- self.pagenumber = page_number
135
- return self
190
+ class _DataExportOptions(RequestOptionsBase):
191
+ def __init__(self, maxage: int = -1):
192
+ super().__init__()
193
+ self.view_filters: list[tuple[str, str]] = []
194
+ self.view_parameters: list[tuple[str, str]] = []
195
+ self.max_age: Optional[int] = maxage
196
+ """
197
+ This setting will affect the contents of the workbook as they are exported.
198
+ Valid language values are tableau-supported languages like de, es, en
199
+ If no locale is specified, the default locale for that language will be used
200
+ """
201
+ self.language: Optional[str] = None
202
+
203
+ @property
204
+ def max_age(self) -> int:
205
+ return self._max_age
206
+
207
+ @max_age.setter
208
+ @property_is_int(range=(0, 240), allowed=[-1])
209
+ def max_age(self, value):
210
+ self._max_age = value
136
211
 
137
212
  def get_query_params(self):
138
213
  params = {}
139
- if self.pagenumber:
140
- params["pageNumber"] = self.pagenumber
141
- if self.pagesize:
142
- params["pageSize"] = self.pagesize
143
- if len(self.sort) > 0:
144
- sort_options = (str(sort_item) for sort_item in self.sort)
145
- ordered_sort_options = sorted(sort_options)
146
- params["sort"] = ",".join(ordered_sort_options)
147
- if len(self.filter) > 0:
148
- filter_options = (str(filter_item) for filter_item in self.filter)
149
- ordered_filter_options = sorted(filter_options)
150
- params["filter"] = ",".join(ordered_filter_options)
151
- if self._all_fields:
152
- params["fields"] = "_all_"
214
+ if self.max_age != -1:
215
+ params["maxAge"] = self.max_age
216
+ if self.language:
217
+ params["language"] = self.language
218
+
219
+ self._append_view_filters(params)
153
220
  return params
154
221
 
222
+ def vf(self, name: str, value: str) -> Self:
223
+ """Apply a filter based on a column within the view.
224
+ Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'
155
225
 
156
- class _FilterOptionsBase(RequestOptionsBase):
157
- """Provide a basic implementation of adding view filters to the url"""
226
+ For more detail see: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_filtering_and_sorting.htm#Filter-query-views
158
227
 
159
- def __init__(self):
160
- self.view_filters = []
161
- self.view_parameters = []
228
+ Parameters
229
+ ----------
230
+ name: str
231
+ The name of the column to filter on
162
232
 
163
- def get_query_params(self):
164
- raise NotImplementedError()
233
+ value: str
234
+ The value to filter on
165
235
 
166
- def vf(self, name: str, value: str) -> Self:
167
- """Apply a filter to the view for a filter that is a normal column
168
- within the view."""
236
+ Returns
237
+ -------
238
+ Self
239
+ The current object
240
+ """
169
241
  self.view_filters.append((name, value))
170
242
  return self
171
243
 
172
244
  def parameter(self, name: str, value: str) -> Self:
173
- """Apply a filter based on a parameter within the workbook."""
245
+ """Apply a filter based on a parameter within the workbook.
246
+ Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'
247
+
248
+ Parameters
249
+ ----------
250
+ name: str
251
+ The name of the parameter to filter on
252
+
253
+ value: str
254
+ The value to filter on
255
+
256
+ Returns
257
+ -------
258
+ Self
259
+ The current object
260
+ """
174
261
  self.view_parameters.append((name, value))
175
262
  return self
176
263
 
@@ -181,82 +268,142 @@ class _FilterOptionsBase(RequestOptionsBase):
181
268
  params[name] = value
182
269
 
183
270
 
184
- class CSVRequestOptions(_FilterOptionsBase):
185
- def __init__(self, maxage=-1):
186
- super(CSVRequestOptions, self).__init__()
187
- self.max_age = maxage
271
+ class _ImagePDFCommonExportOptions(_DataExportOptions):
272
+ def __init__(self, maxage=-1, viz_height=None, viz_width=None):
273
+ super().__init__(maxage=maxage)
274
+ self.viz_height = viz_height
275
+ self.viz_width = viz_width
188
276
 
189
277
  @property
190
- def max_age(self):
191
- return self._max_age
278
+ def viz_height(self):
279
+ return self._viz_height
192
280
 
193
- @max_age.setter
194
- @property_is_int(range=(0, 240), allowed=[-1])
195
- def max_age(self, value):
196
- self._max_age = value
281
+ @viz_height.setter
282
+ @property_is_int(range=(0, sys.maxsize), allowed=(None,))
283
+ def viz_height(self, value):
284
+ self._viz_height = value
197
285
 
198
- def get_query_params(self):
199
- params = {}
200
- if self.max_age != -1:
201
- params["maxAge"] = self.max_age
286
+ @property
287
+ def viz_width(self):
288
+ return self._viz_width
289
+
290
+ @viz_width.setter
291
+ @property_is_int(range=(0, sys.maxsize), allowed=(None,))
292
+ def viz_width(self, value):
293
+ self._viz_width = value
294
+
295
+ def get_query_params(self) -> dict:
296
+ params = super().get_query_params()
297
+
298
+ # XOR. Either both are None or both are not None.
299
+ if (self.viz_height is None) ^ (self.viz_width is None):
300
+ raise ValueError("viz_height and viz_width must be specified together")
301
+
302
+ if self.viz_height is not None:
303
+ params["vizHeight"] = self.viz_height
304
+
305
+ if self.viz_width is not None:
306
+ params["vizWidth"] = self.viz_width
202
307
 
203
- self._append_view_filters(params)
204
308
  return params
205
309
 
206
310
 
207
- class ExcelRequestOptions(_FilterOptionsBase):
208
- def __init__(self, maxage: int = -1) -> None:
209
- super().__init__()
210
- self.max_age = maxage
311
+ class CSVRequestOptions(_DataExportOptions):
312
+ """
313
+ Options that can be used when exporting a view to CSV. Set the maxage to control the age of the data exported.
314
+ Filters to the underlying data can be applied using the `vf` and `parameter` methods.
211
315
 
212
- @property
213
- def max_age(self) -> int:
214
- return self._max_age
316
+ Parameters
317
+ ----------
318
+ maxage: int, optional
319
+ The maximum age of the data to export. Shortest possible duration is 1
320
+ minute. No upper limit. Default is -1, which means no limit.
321
+ """
215
322
 
216
- @max_age.setter
217
- @property_is_int(range=(0, 240), allowed=[-1])
218
- def max_age(self, value: int) -> None:
219
- self._max_age = value
323
+ extension = "csv"
220
324
 
221
- def get_query_params(self):
222
- params = {}
223
- if self.max_age != -1:
224
- params["maxAge"] = self.max_age
225
325
 
226
- self._append_view_filters(params)
227
- return params
326
+ class ExcelRequestOptions(_DataExportOptions):
327
+ """
328
+ Options that can be used when exporting a view to Excel. Set the maxage to control the age of the data exported.
329
+ Filters to the underlying data can be applied using the `vf` and `parameter` methods.
330
+
331
+ Parameters
332
+ ----------
333
+ maxage: int, optional
334
+ The maximum age of the data to export. Shortest possible duration is 1
335
+ minute. No upper limit. Default is -1, which means no limit.
336
+ """
337
+
338
+ extension = "xlsx"
339
+
340
+
341
+ class ImageRequestOptions(_ImagePDFCommonExportOptions):
342
+ """
343
+ Options that can be used when exporting a view to an image. Set the maxage to control the age of the data exported.
344
+ Filters to the underlying data can be applied using the `vf` and `parameter` methods.
345
+
346
+ Parameters
347
+ ----------
348
+ imageresolution: str, optional
349
+ The resolution of the image to export. Valid values are "high" or None. Default is None.
350
+ Image width and actual pixel density are determined by the display context
351
+ of the image. Aspect ratio is always preserved. Set the value to "high" to
352
+ ensure maximum pixel density.
353
+
354
+ maxage: int, optional
355
+ The maximum age of the data to export. Shortest possible duration is 1
356
+ minute. No upper limit. Default is -1, which means no limit.
357
+
358
+ viz_height: int, optional
359
+ The height of the viz in pixels. If specified, viz_width must also be specified.
360
+
361
+ viz_width: int, optional
362
+ The width of the viz in pixels. If specified, viz_height must also be specified.
363
+
364
+ """
228
365
 
366
+ extension = "png"
229
367
 
230
- class ImageRequestOptions(_FilterOptionsBase):
231
368
  # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution
232
369
  class Resolution:
233
370
  High = "high"
234
371
 
235
- def __init__(self, imageresolution=None, maxage=-1):
236
- super(ImageRequestOptions, self).__init__()
372
+ def __init__(self, imageresolution=None, maxage=-1, viz_height=None, viz_width=None):
373
+ super().__init__(maxage=maxage, viz_height=viz_height, viz_width=viz_width)
237
374
  self.image_resolution = imageresolution
238
- self.max_age = maxage
239
-
240
- @property
241
- def max_age(self):
242
- return self._max_age
243
-
244
- @max_age.setter
245
- @property_is_int(range=(0, 240), allowed=[-1])
246
- def max_age(self, value):
247
- self._max_age = value
248
375
 
249
376
  def get_query_params(self):
250
- params = {}
377
+ params = super().get_query_params()
251
378
  if self.image_resolution:
252
379
  params["resolution"] = self.image_resolution
253
- if self.max_age != -1:
254
- params["maxAge"] = self.max_age
255
- self._append_view_filters(params)
256
380
  return params
257
381
 
258
382
 
259
- class PDFRequestOptions(_FilterOptionsBase):
383
+ class PDFRequestOptions(_ImagePDFCommonExportOptions):
384
+ """
385
+ Options that can be used when exporting a view to PDF. Set the maxage to control the age of the data exported.
386
+ Filters to the underlying data can be applied using the `vf` and `parameter` methods.
387
+
388
+ Parameters
389
+ ----------
390
+ page_type: str, optional
391
+ The page type of the PDF to export. Valid values are accessible via the `PageType` class.
392
+
393
+ orientation: str, optional
394
+ The orientation of the PDF to export. Valid values are accessible via the `Orientation` class.
395
+
396
+ maxage: int, optional
397
+ The maximum age of the data to export. Shortest possible duration is 1
398
+ minute. No upper limit. Default is -1, which means no limit.
399
+
400
+ viz_height: int, optional
401
+ The height of the viz in pixels. If specified, viz_width must also be specified.
402
+
403
+ viz_width: int, optional
404
+ The width of the viz in pixels. If specified, viz_height must also be specified.
405
+ """
406
+
260
407
  class PageType:
261
408
  A3 = "a3"
262
409
  A4 = "a4"
@@ -278,61 +425,16 @@ class PDFRequestOptions(_FilterOptionsBase):
278
425
  Landscape = "landscape"
279
426
 
280
427
  def __init__(self, page_type=None, orientation=None, maxage=-1, viz_height=None, viz_width=None):
281
- super(PDFRequestOptions, self).__init__()
428
+ super().__init__(maxage=maxage, viz_height=viz_height, viz_width=viz_width)
282
429
  self.page_type = page_type
283
430
  self.orientation = orientation
284
- self.max_age = maxage
285
- self.viz_height = viz_height
286
- self.viz_width = viz_width
287
-
288
- @property
289
- def max_age(self):
290
- return self._max_age
291
-
292
- @max_age.setter
293
- @property_is_int(range=(0, 240), allowed=[-1])
294
- def max_age(self, value):
295
- self._max_age = value
296
-
297
- @property
298
- def viz_height(self):
299
- return self._viz_height
300
431
 
301
- @viz_height.setter
302
- @property_is_int(range=(0, sys.maxsize), allowed=(None,))
303
- def viz_height(self, value):
304
- self._viz_height = value
305
-
306
- @property
307
- def viz_width(self):
308
- return self._viz_width
309
-
310
- @viz_width.setter
311
- @property_is_int(range=(0, sys.maxsize), allowed=(None,))
312
- def viz_width(self, value):
313
- self._viz_width = value
314
-
315
- def get_query_params(self):
316
- params = {}
432
+ def get_query_params(self) -> dict:
433
+ params = super().get_query_params()
317
434
  if self.page_type:
318
435
  params["type"] = self.page_type
319
436
 
320
437
  if self.orientation:
321
438
  params["orientation"] = self.orientation
322
439
 
323
- if self.max_age != -1:
324
- params["maxAge"] = self.max_age
325
-
326
- # XOR. Either both are None or both are not None.
327
- if (self.viz_height is None) ^ (self.viz_width is None):
328
- raise ValueError("viz_height and viz_width must be specified together")
329
-
330
- if self.viz_height is not None:
331
- params["vizHeight"] = self.viz_height
332
-
333
- if self.viz_width is not None:
334
- params["vizWidth"] = self.viz_width
335
-
336
- self._append_view_filters(params)
337
-
338
440
  return params
@@ -58,11 +58,68 @@ minimum_supported_server_version = "2.3"
58
58
  default_server_version = "2.4" # first version that dropped the legacy auth endpoint
59
59
 
60
60
 
61
- class Server(object):
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
+
62
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
+
63
119
  Append = "Append"
64
120
  Overwrite = "Overwrite"
65
121
  CreateNew = "CreateNew"
122
+ Replace = "Replace"
66
123
 
67
124
  def __init__(self, server_address, use_server_version=False, http_options=None, session_factory=None):
68
125
  self._auth_token = None
@@ -130,7 +187,7 @@ class Server(object):
130
187
  raise ValueError("Server connection settings not valid", req_ex)
131
188
 
132
189
  def __repr__(self):
133
- return "<TableauServerClient [Connection: {}, {}]>".format(self.baseurl, self.server_info.serverInfo)
190
+ return f"<TableauServerClient [Connection: {self.baseurl}, {self.server_info.serverInfo}]>"
134
191
 
135
192
  def add_http_options(self, options_dict: dict):
136
193
  try:
@@ -142,7 +199,7 @@ class Server(object):
142
199
  # expected errors on invalid input:
143
200
  # 'set' object has no attribute 'keys', 'list' object has no attribute 'keys'
144
201
  # TypeError: cannot convert dictionary update sequence element #0 to a sequence (input is a tuple)
145
- raise ValueError("Invalid http options given: {}".format(options_dict))
202
+ raise ValueError(f"Invalid http options given: {options_dict}")
146
203
 
147
204
  def clear_http_options(self):
148
205
  self._http_options = dict()
@@ -151,12 +208,14 @@ class Server(object):
151
208
  self._site_id = None
152
209
  self._user_id = None
153
210
  self._auth_token = None
211
+ self._site_url = None
154
212
  self._session = self._session_factory()
155
213
 
156
- def _set_auth(self, site_id, user_id, auth_token):
214
+ def _set_auth(self, site_id, user_id, auth_token, site_url=None):
157
215
  self._site_id = site_id
158
216
  self._user_id = user_id
159
217
  self._auth_token = auth_token
218
+ self._site_url = site_url
160
219
 
161
220
  def _get_legacy_version(self):
162
221
  # the serverInfo call was introduced in 2.4, earlier than that we have this different call
@@ -176,15 +235,15 @@ class Server(object):
176
235
  old_version = self.version
177
236
  version = self.server_info.get().rest_api_version
178
237
  except ServerInfoEndpointNotFoundError as e:
179
- logger.info("Could not get version info from server: {}{}".format(e.__class__, e))
238
+ logger.info(f"Could not get version info from server: {e.__class__}{e}")
180
239
  version = self._get_legacy_version()
181
240
  except EndpointUnavailableError as e:
182
- logger.info("Could not get version info from server: {}{}".format(e.__class__, e))
241
+ logger.info(f"Could not get version info from server: {e.__class__}{e}")
183
242
  version = self._get_legacy_version()
184
243
  except Exception as e:
185
- logger.info("Could not get version info from server: {}{}".format(e.__class__, e))
244
+ logger.info(f"Could not get version info from server: {e.__class__}{e}")
186
245
  version = None
187
- logger.info("versions: {}, {}".format(version, old_version))
246
+ logger.info(f"versions: {version}, {old_version}")
188
247
  return version or old_version
189
248
 
190
249
  def use_server_version(self):
@@ -201,12 +260,12 @@ class Server(object):
201
260
 
202
261
  def assert_at_least_version(self, comparison: str, reason: str):
203
262
  if not self.check_at_least_version(comparison):
204
- error = "{} is not available in API version {}. Requires {}".format(reason, self.version, comparison)
263
+ error = f"{reason} is not available in API version {self.version}. Requires {comparison}"
205
264
  raise EndpointUnavailableError(error)
206
265
 
207
266
  @property
208
267
  def baseurl(self):
209
- return "{0}/api/{1}".format(self._server_address, str(self.version))
268
+ return f"{self._server_address}/api/{str(self.version)}"
210
269
 
211
270
  @property
212
271
  def namespace(self):
@@ -226,6 +285,13 @@ class Server(object):
226
285
  raise NotSignedInError(error)
227
286
  return self._site_id
228
287
 
288
+ @property
289
+ def site_url(self):
290
+ if self._site_url is None:
291
+ error = "Missing site URL. You must sign in first."
292
+ raise NotSignedInError(error)
293
+ return self._site_url
294
+
229
295
  @property
230
296
  def user_id(self):
231
297
  if self._user_id is None:
@@ -1,7 +1,21 @@
1
- class Sort(object):
1
+ class Sort:
2
+ """
3
+ Used with request options (RequestOptions) where you can filter and sort on
4
+ the results returned from the server.
5
+
6
+ Parameters
7
+ ----------
8
+ field : str
9
+ Sets the field to sort on. The fields are defined in the RequestOption class.
10
+
11
+ direction : str
12
+ The direction to sort, either ascending (Asc) or descending (Desc). The
13
+ options are defined in the RequestOptions.Direction class.
14
+ """
15
+
2
16
  def __init__(self, field, direction):
3
17
  self.field = field
4
18
  self.direction = direction
5
19
 
6
20
  def __str__(self):
7
- return "{0}:{1}".format(self.field, self.direction)
21
+ return f"{self.field}:{self.direction}"