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
|
@@ -8,20 +8,49 @@ from tableauserverclient.models import SiteItem, PaginationItem
|
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.helpers.logging import logger
|
|
10
10
|
|
|
11
|
-
from typing import TYPE_CHECKING,
|
|
11
|
+
from typing import TYPE_CHECKING, Optional
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from ..request_options import RequestOptions
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class Sites(Endpoint):
|
|
18
|
+
"""
|
|
19
|
+
Using the site methods of the Tableau Server REST API you can:
|
|
20
|
+
|
|
21
|
+
List sites on a server or get details of a specific site
|
|
22
|
+
Create, update, or delete a site
|
|
23
|
+
List views in a site
|
|
24
|
+
Encrypt, decrypt, or reencrypt extracts on a site
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
18
28
|
@property
|
|
19
29
|
def baseurl(self) -> str:
|
|
20
|
-
return "{
|
|
30
|
+
return f"{self.parent_srv.baseurl}/sites"
|
|
21
31
|
|
|
22
32
|
# Gets all sites
|
|
23
33
|
@api(version="2.0")
|
|
24
|
-
def get(self, req_options: Optional["RequestOptions"] = None) ->
|
|
34
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[SiteItem], PaginationItem]:
|
|
35
|
+
"""
|
|
36
|
+
Query all sites on the server. This method requires server admin
|
|
37
|
+
permissions. This endpoint is paginated, meaning that the server will
|
|
38
|
+
only return a subset of the data at a time. The response will contain
|
|
39
|
+
information about the total number of sites and the number of sites
|
|
40
|
+
returned in the current response. Use the PaginationItem object to
|
|
41
|
+
request more data.
|
|
42
|
+
|
|
43
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_sites
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
req_options : RequestOptions, optional
|
|
48
|
+
Filtering options for the request.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
tuple[list[SiteItem], PaginationItem]
|
|
53
|
+
"""
|
|
25
54
|
logger.info("Querying all sites on site")
|
|
26
55
|
logger.info("Requires Server Admin permissions")
|
|
27
56
|
url = self.baseurl
|
|
@@ -33,6 +62,33 @@ class Sites(Endpoint):
|
|
|
33
62
|
# Gets 1 site by id
|
|
34
63
|
@api(version="2.0")
|
|
35
64
|
def get_by_id(self, site_id: str) -> SiteItem:
|
|
65
|
+
"""
|
|
66
|
+
Query a single site on the server. You can only retrieve the site that
|
|
67
|
+
you are currently authenticated for.
|
|
68
|
+
|
|
69
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
site_id : str
|
|
74
|
+
The site ID.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
SiteItem
|
|
79
|
+
|
|
80
|
+
Raises
|
|
81
|
+
------
|
|
82
|
+
ValueError
|
|
83
|
+
If the site ID is not defined.
|
|
84
|
+
|
|
85
|
+
ValueError
|
|
86
|
+
If the site ID does not match the site for which you are currently authenticated.
|
|
87
|
+
|
|
88
|
+
Examples
|
|
89
|
+
--------
|
|
90
|
+
>>> site = server.sites.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
91
|
+
"""
|
|
36
92
|
if not site_id:
|
|
37
93
|
error = "Site ID undefined."
|
|
38
94
|
raise ValueError(error)
|
|
@@ -40,20 +96,45 @@ class Sites(Endpoint):
|
|
|
40
96
|
error = "You can only retrieve the site for which you are currently authenticated."
|
|
41
97
|
raise ValueError(error)
|
|
42
98
|
|
|
43
|
-
logger.info("Querying single site (ID: {
|
|
44
|
-
url = "{
|
|
99
|
+
logger.info(f"Querying single site (ID: {site_id})")
|
|
100
|
+
url = f"{self.baseurl}/{site_id}"
|
|
45
101
|
server_response = self.get_request(url)
|
|
46
102
|
return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
47
103
|
|
|
48
104
|
# Gets 1 site by name
|
|
49
105
|
@api(version="2.0")
|
|
50
106
|
def get_by_name(self, site_name: str) -> SiteItem:
|
|
107
|
+
"""
|
|
108
|
+
Query a single site on the server. You can only retrieve the site that
|
|
109
|
+
you are currently authenticated for.
|
|
110
|
+
|
|
111
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
site_name : str
|
|
116
|
+
The site name.
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
SiteItem
|
|
121
|
+
|
|
122
|
+
Raises
|
|
123
|
+
------
|
|
124
|
+
ValueError
|
|
125
|
+
If the site name is not defined.
|
|
126
|
+
|
|
127
|
+
Examples
|
|
128
|
+
--------
|
|
129
|
+
>>> site = server.sites.get_by_name('Tableau')
|
|
130
|
+
|
|
131
|
+
"""
|
|
51
132
|
if not site_name:
|
|
52
133
|
error = "Site Name undefined."
|
|
53
134
|
raise ValueError(error)
|
|
54
135
|
print("Note: You can only work with the site for which you are currently authenticated")
|
|
55
|
-
logger.info("Querying single site (Name: {
|
|
56
|
-
url = "{
|
|
136
|
+
logger.info(f"Querying single site (Name: {site_name})")
|
|
137
|
+
url = f"{self.baseurl}/{site_name}?key=name"
|
|
57
138
|
print(self.baseurl, url)
|
|
58
139
|
server_response = self.get_request(url)
|
|
59
140
|
return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
@@ -61,6 +142,31 @@ class Sites(Endpoint):
|
|
|
61
142
|
# Gets 1 site by content url
|
|
62
143
|
@api(version="2.0")
|
|
63
144
|
def get_by_content_url(self, content_url: str) -> SiteItem:
|
|
145
|
+
"""
|
|
146
|
+
Query a single site on the server. You can only retrieve the site that
|
|
147
|
+
you are currently authenticated for.
|
|
148
|
+
|
|
149
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
content_url : str
|
|
154
|
+
The content URL.
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
SiteItem
|
|
159
|
+
|
|
160
|
+
Raises
|
|
161
|
+
------
|
|
162
|
+
ValueError
|
|
163
|
+
If the site name is not defined.
|
|
164
|
+
|
|
165
|
+
Examples
|
|
166
|
+
--------
|
|
167
|
+
>>> site = server.sites.get_by_name('Tableau')
|
|
168
|
+
|
|
169
|
+
"""
|
|
64
170
|
if content_url is None:
|
|
65
171
|
error = "Content URL undefined."
|
|
66
172
|
raise ValueError(error)
|
|
@@ -68,15 +174,51 @@ class Sites(Endpoint):
|
|
|
68
174
|
error = "You can only work with the site you are currently authenticated for"
|
|
69
175
|
raise ValueError(error)
|
|
70
176
|
|
|
71
|
-
logger.info("Querying single site (Content URL: {
|
|
177
|
+
logger.info(f"Querying single site (Content URL: {content_url})")
|
|
72
178
|
logger.debug("Querying other sites requires Server Admin permissions")
|
|
73
|
-
url = "{
|
|
179
|
+
url = f"{self.baseurl}/{content_url}?key=contentUrl"
|
|
74
180
|
server_response = self.get_request(url)
|
|
75
181
|
return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
76
182
|
|
|
77
183
|
# Update site
|
|
78
184
|
@api(version="2.0")
|
|
79
185
|
def update(self, site_item: SiteItem) -> SiteItem:
|
|
186
|
+
"""
|
|
187
|
+
Modifies the settings for site.
|
|
188
|
+
|
|
189
|
+
The site item object must include the site ID and overrides all other settings.
|
|
190
|
+
|
|
191
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_site
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
site_item : SiteItem
|
|
196
|
+
The site item that you want to update. The settings specified in the
|
|
197
|
+
site item override the current site settings.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
SiteItem
|
|
202
|
+
The site item object that was updated.
|
|
203
|
+
|
|
204
|
+
Raises
|
|
205
|
+
------
|
|
206
|
+
MissingRequiredFieldError
|
|
207
|
+
If the site item is missing an ID.
|
|
208
|
+
|
|
209
|
+
ValueError
|
|
210
|
+
If the site ID does not match the site for which you are currently authenticated.
|
|
211
|
+
|
|
212
|
+
ValueError
|
|
213
|
+
If the site admin mode is set to ContentOnly and a user quota is also set.
|
|
214
|
+
|
|
215
|
+
Examples
|
|
216
|
+
--------
|
|
217
|
+
>>> ...
|
|
218
|
+
>>> site_item.name = 'New Name'
|
|
219
|
+
>>> updated_site = server.sites.update(site_item)
|
|
220
|
+
|
|
221
|
+
"""
|
|
80
222
|
if not site_item.id:
|
|
81
223
|
error = "Site item missing ID."
|
|
82
224
|
raise MissingRequiredFieldError(error)
|
|
@@ -90,30 +232,94 @@ class Sites(Endpoint):
|
|
|
90
232
|
error = "You cannot set admin_mode to ContentOnly and also set a user quota"
|
|
91
233
|
raise ValueError(error)
|
|
92
234
|
|
|
93
|
-
url = "{
|
|
235
|
+
url = f"{self.baseurl}/{site_item.id}"
|
|
94
236
|
update_req = RequestFactory.Site.update_req(site_item, self.parent_srv)
|
|
95
237
|
server_response = self.put_request(url, update_req)
|
|
96
|
-
logger.info("Updated site item (ID: {
|
|
238
|
+
logger.info(f"Updated site item (ID: {site_item.id})")
|
|
97
239
|
update_site = copy.copy(site_item)
|
|
98
240
|
return update_site._parse_common_tags(server_response.content, self.parent_srv.namespace)
|
|
99
241
|
|
|
100
242
|
# Delete 1 site object
|
|
101
243
|
@api(version="2.0")
|
|
102
244
|
def delete(self, site_id: str) -> None:
|
|
245
|
+
"""
|
|
246
|
+
Deletes the specified site from the server. You can only delete the site
|
|
247
|
+
if you are a Server Admin.
|
|
248
|
+
|
|
249
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#delete_site
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
site_id : str
|
|
254
|
+
The site ID.
|
|
255
|
+
|
|
256
|
+
Raises
|
|
257
|
+
------
|
|
258
|
+
ValueError
|
|
259
|
+
If the site ID is not defined.
|
|
260
|
+
|
|
261
|
+
ValueError
|
|
262
|
+
If the site ID does not match the site for which you are currently authenticated.
|
|
263
|
+
|
|
264
|
+
Examples
|
|
265
|
+
--------
|
|
266
|
+
>>> server.sites.delete('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
267
|
+
"""
|
|
103
268
|
if not site_id:
|
|
104
269
|
error = "Site ID undefined."
|
|
105
270
|
raise ValueError(error)
|
|
106
|
-
url = "{
|
|
271
|
+
url = f"{self.baseurl}/{site_id}"
|
|
107
272
|
if not site_id == self.parent_srv.site_id:
|
|
108
273
|
error = "You can only delete the site you are currently authenticated for"
|
|
109
274
|
raise ValueError(error)
|
|
110
275
|
self.delete_request(url)
|
|
111
276
|
self.parent_srv._clear_auth()
|
|
112
|
-
logger.info("Deleted single site (ID: {
|
|
277
|
+
logger.info(f"Deleted single site (ID: {site_id}) and signed out")
|
|
113
278
|
|
|
114
279
|
# Create new site
|
|
115
280
|
@api(version="2.0")
|
|
116
281
|
def create(self, site_item: SiteItem) -> SiteItem:
|
|
282
|
+
"""
|
|
283
|
+
Creates a new site on the server for the specified site item object.
|
|
284
|
+
|
|
285
|
+
Tableau Server only.
|
|
286
|
+
|
|
287
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#create_site
|
|
288
|
+
|
|
289
|
+
Parameters
|
|
290
|
+
----------
|
|
291
|
+
site_item : SiteItem
|
|
292
|
+
The settings for the site that you want to create. You need to
|
|
293
|
+
create an instance of SiteItem and pass it to the create method.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
SiteItem
|
|
298
|
+
The site item object that was created.
|
|
299
|
+
|
|
300
|
+
Raises
|
|
301
|
+
------
|
|
302
|
+
ValueError
|
|
303
|
+
If the site admin mode is set to ContentOnly and a user quota is also set.
|
|
304
|
+
|
|
305
|
+
Examples
|
|
306
|
+
--------
|
|
307
|
+
>>> import tableauserverclient as TSC
|
|
308
|
+
|
|
309
|
+
>>> # create an instance of server
|
|
310
|
+
>>> server = TSC.Server('https://MY-SERVER')
|
|
311
|
+
|
|
312
|
+
>>> # create shortcut for admin mode
|
|
313
|
+
>>> content_users=TSC.SiteItem.AdminMode.ContentAndUsers
|
|
314
|
+
|
|
315
|
+
>>> # create a new SiteItem
|
|
316
|
+
>>> new_site = TSC.SiteItem(name='Tableau', content_url='tableau', admin_mode=content_users, user_quota=15, storage_quota=1000, disable_subscriptions=True)
|
|
317
|
+
|
|
318
|
+
>>> # call the sites create method with the SiteItem
|
|
319
|
+
>>> new_site = server.sites.create(new_site)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
"""
|
|
117
323
|
if site_item.admin_mode:
|
|
118
324
|
if site_item.admin_mode == SiteItem.AdminMode.ContentOnly and site_item.user_quota:
|
|
119
325
|
error = "You cannot set admin_mode to ContentOnly and also set a user quota"
|
|
@@ -123,33 +329,92 @@ class Sites(Endpoint):
|
|
|
123
329
|
create_req = RequestFactory.Site.create_req(site_item, self.parent_srv)
|
|
124
330
|
server_response = self.post_request(url, create_req)
|
|
125
331
|
new_site = SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
126
|
-
logger.info("Created new site (ID: {
|
|
332
|
+
logger.info(f"Created new site (ID: {new_site.id})")
|
|
127
333
|
return new_site
|
|
128
334
|
|
|
129
335
|
@api(version="3.5")
|
|
130
336
|
def encrypt_extracts(self, site_id: str) -> None:
|
|
337
|
+
"""
|
|
338
|
+
Encrypts all extracts on the site.
|
|
339
|
+
|
|
340
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#encrypt_extracts
|
|
341
|
+
|
|
342
|
+
Parameters
|
|
343
|
+
----------
|
|
344
|
+
site_id : str
|
|
345
|
+
The site ID.
|
|
346
|
+
|
|
347
|
+
Raises
|
|
348
|
+
------
|
|
349
|
+
ValueError
|
|
350
|
+
If the site ID is not defined.
|
|
351
|
+
|
|
352
|
+
Examples
|
|
353
|
+
--------
|
|
354
|
+
>>> server.sites.encrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
355
|
+
"""
|
|
131
356
|
if not site_id:
|
|
132
357
|
error = "Site ID undefined."
|
|
133
358
|
raise ValueError(error)
|
|
134
|
-
url = "{
|
|
359
|
+
url = f"{self.baseurl}/{site_id}/encrypt-extracts"
|
|
135
360
|
empty_req = RequestFactory.Empty.empty_req()
|
|
136
361
|
self.post_request(url, empty_req)
|
|
137
362
|
|
|
138
363
|
@api(version="3.5")
|
|
139
364
|
def decrypt_extracts(self, site_id: str) -> None:
|
|
365
|
+
"""
|
|
366
|
+
Decrypts all extracts on the site.
|
|
367
|
+
|
|
368
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#decrypt_extracts
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
site_id : str
|
|
373
|
+
The site ID.
|
|
374
|
+
|
|
375
|
+
Raises
|
|
376
|
+
------
|
|
377
|
+
ValueError
|
|
378
|
+
If the site ID is not defined.
|
|
379
|
+
|
|
380
|
+
Examples
|
|
381
|
+
--------
|
|
382
|
+
>>> server.sites.decrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
383
|
+
"""
|
|
140
384
|
if not site_id:
|
|
141
385
|
error = "Site ID undefined."
|
|
142
386
|
raise ValueError(error)
|
|
143
|
-
url = "{
|
|
387
|
+
url = f"{self.baseurl}/{site_id}/decrypt-extracts"
|
|
144
388
|
empty_req = RequestFactory.Empty.empty_req()
|
|
145
389
|
self.post_request(url, empty_req)
|
|
146
390
|
|
|
147
391
|
@api(version="3.5")
|
|
148
392
|
def re_encrypt_extracts(self, site_id: str) -> None:
|
|
393
|
+
"""
|
|
394
|
+
Reencrypt all extracts on a site with new encryption keys. If no site is
|
|
395
|
+
specified, extracts on the default site will be reencrypted.
|
|
396
|
+
|
|
397
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#reencrypt_extracts
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
----------
|
|
401
|
+
site_id : str
|
|
402
|
+
The site ID.
|
|
403
|
+
|
|
404
|
+
Raises
|
|
405
|
+
------
|
|
406
|
+
ValueError
|
|
407
|
+
If the site ID is not defined.
|
|
408
|
+
|
|
409
|
+
Examples
|
|
410
|
+
--------
|
|
411
|
+
>>> server.sites.re_encrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
|
|
412
|
+
|
|
413
|
+
"""
|
|
149
414
|
if not site_id:
|
|
150
415
|
error = "Site ID undefined."
|
|
151
416
|
raise ValueError(error)
|
|
152
|
-
url = "{
|
|
417
|
+
url = f"{self.baseurl}/{site_id}/reencrypt-extracts"
|
|
153
418
|
|
|
154
419
|
empty_req = RequestFactory.Empty.empty_req()
|
|
155
420
|
self.post_request(url, empty_req)
|
|
@@ -7,7 +7,7 @@ from tableauserverclient.models import SubscriptionItem, PaginationItem
|
|
|
7
7
|
|
|
8
8
|
from tableauserverclient.helpers.logging import logger
|
|
9
9
|
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import Optional, TYPE_CHECKING
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from ..request_options import RequestOptions
|
|
@@ -16,10 +16,10 @@ if TYPE_CHECKING:
|
|
|
16
16
|
class Subscriptions(Endpoint):
|
|
17
17
|
@property
|
|
18
18
|
def baseurl(self) -> str:
|
|
19
|
-
return "{
|
|
19
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/subscriptions"
|
|
20
20
|
|
|
21
21
|
@api(version="2.3")
|
|
22
|
-
def get(self, req_options: Optional["RequestOptions"] = None) ->
|
|
22
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[SubscriptionItem], PaginationItem]:
|
|
23
23
|
logger.info("Querying all subscriptions for the site")
|
|
24
24
|
url = self.baseurl
|
|
25
25
|
server_response = self.get_request(url, req_options)
|
|
@@ -33,8 +33,8 @@ class Subscriptions(Endpoint):
|
|
|
33
33
|
if not subscription_id:
|
|
34
34
|
error = "No Subscription ID provided"
|
|
35
35
|
raise ValueError(error)
|
|
36
|
-
logger.info("Querying a single subscription by id ({})"
|
|
37
|
-
url = "{}/{}"
|
|
36
|
+
logger.info(f"Querying a single subscription by id ({subscription_id})")
|
|
37
|
+
url = f"{self.baseurl}/{subscription_id}"
|
|
38
38
|
server_response = self.get_request(url)
|
|
39
39
|
return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ class Subscriptions(Endpoint):
|
|
|
43
43
|
if not subscription_item:
|
|
44
44
|
error = "No Susbcription provided"
|
|
45
45
|
raise ValueError(error)
|
|
46
|
-
logger.info("Creating a subscription ({})"
|
|
46
|
+
logger.info(f"Creating a subscription ({subscription_item})")
|
|
47
47
|
url = self.baseurl
|
|
48
48
|
create_req = RequestFactory.Subscription.create_req(subscription_item)
|
|
49
49
|
server_response = self.post_request(url, create_req)
|
|
@@ -54,17 +54,17 @@ class Subscriptions(Endpoint):
|
|
|
54
54
|
if not subscription_id:
|
|
55
55
|
error = "Subscription ID undefined."
|
|
56
56
|
raise ValueError(error)
|
|
57
|
-
url = "{
|
|
57
|
+
url = f"{self.baseurl}/{subscription_id}"
|
|
58
58
|
self.delete_request(url)
|
|
59
|
-
logger.info("Deleted subscription (ID: {
|
|
59
|
+
logger.info(f"Deleted subscription (ID: {subscription_id})")
|
|
60
60
|
|
|
61
61
|
@api(version="2.3")
|
|
62
62
|
def update(self, subscription_item: SubscriptionItem) -> SubscriptionItem:
|
|
63
63
|
if not subscription_item.id:
|
|
64
64
|
error = "Subscription item missing ID. Subscription must be retrieved from server first."
|
|
65
65
|
raise MissingRequiredFieldError(error)
|
|
66
|
-
url = "{
|
|
66
|
+
url = f"{self.baseurl}/{subscription_item.id}"
|
|
67
67
|
update_req = RequestFactory.Subscription.update_req(subscription_item)
|
|
68
68
|
server_response = self.put_request(url, update_req)
|
|
69
|
-
logger.info("Updated subscription item (ID: {
|
|
69
|
+
logger.info(f"Updated subscription item (ID: {subscription_item.id})")
|
|
70
70
|
return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
|
|
3
|
-
from .
|
|
4
|
-
|
|
5
|
-
from .
|
|
6
|
-
from .
|
|
2
|
+
from typing import Union
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
|
|
5
|
+
from tableauserverclient.server.endpoint.dqw_endpoint import _DataQualityWarningEndpoint
|
|
6
|
+
from tableauserverclient.server.endpoint.endpoint import api, Endpoint
|
|
7
|
+
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
|
|
8
|
+
from tableauserverclient.server.endpoint.permissions_endpoint import _PermissionsEndpoint
|
|
9
|
+
from tableauserverclient.server.endpoint.resource_tagger import TaggingMixin
|
|
7
10
|
from tableauserverclient.server import RequestFactory
|
|
8
11
|
from tableauserverclient.models import TableItem, ColumnItem, PaginationItem
|
|
9
|
-
from
|
|
12
|
+
from tableauserverclient.server.pager import Pager
|
|
10
13
|
|
|
11
14
|
from tableauserverclient.helpers.logging import logger
|
|
12
15
|
|
|
13
16
|
|
|
14
|
-
class Tables(Endpoint):
|
|
17
|
+
class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
15
18
|
def __init__(self, parent_srv):
|
|
16
|
-
super(
|
|
19
|
+
super().__init__(parent_srv)
|
|
17
20
|
|
|
18
21
|
self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl)
|
|
19
22
|
self._data_quality_warnings = _DataQualityWarningEndpoint(self.parent_srv, "table")
|
|
20
23
|
|
|
21
24
|
@property
|
|
22
25
|
def baseurl(self):
|
|
23
|
-
return "{
|
|
26
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tables"
|
|
24
27
|
|
|
25
28
|
@api(version="3.5")
|
|
26
29
|
def get(self, req_options=None):
|
|
@@ -37,8 +40,8 @@ class Tables(Endpoint):
|
|
|
37
40
|
if not table_id:
|
|
38
41
|
error = "table ID undefined."
|
|
39
42
|
raise ValueError(error)
|
|
40
|
-
logger.info("Querying single table (ID: {
|
|
41
|
-
url = "{
|
|
43
|
+
logger.info(f"Querying single table (ID: {table_id})")
|
|
44
|
+
url = f"{self.baseurl}/{table_id}"
|
|
42
45
|
server_response = self.get_request(url)
|
|
43
46
|
return TableItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
44
47
|
|
|
@@ -47,9 +50,9 @@ class Tables(Endpoint):
|
|
|
47
50
|
if not table_id:
|
|
48
51
|
error = "Database ID undefined."
|
|
49
52
|
raise ValueError(error)
|
|
50
|
-
url = "{
|
|
53
|
+
url = f"{self.baseurl}/{table_id}"
|
|
51
54
|
self.delete_request(url)
|
|
52
|
-
logger.info("Deleted single table (ID: {
|
|
55
|
+
logger.info(f"Deleted single table (ID: {table_id})")
|
|
53
56
|
|
|
54
57
|
@api(version="3.5")
|
|
55
58
|
def update(self, table_item):
|
|
@@ -57,10 +60,10 @@ class Tables(Endpoint):
|
|
|
57
60
|
error = "table item missing ID."
|
|
58
61
|
raise MissingRequiredFieldError(error)
|
|
59
62
|
|
|
60
|
-
url = "{
|
|
63
|
+
url = f"{self.baseurl}/{table_item.id}"
|
|
61
64
|
update_req = RequestFactory.Table.update_req(table_item)
|
|
62
65
|
server_response = self.put_request(url, update_req)
|
|
63
|
-
logger.info("Updated table item (ID: {
|
|
66
|
+
logger.info(f"Updated table item (ID: {table_item.id})")
|
|
64
67
|
updated_table = TableItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
65
68
|
return updated_table
|
|
66
69
|
|
|
@@ -78,10 +81,10 @@ class Tables(Endpoint):
|
|
|
78
81
|
)
|
|
79
82
|
|
|
80
83
|
table_item._set_columns(column_fetcher)
|
|
81
|
-
logger.info("Populated columns for table (ID: {
|
|
84
|
+
logger.info(f"Populated columns for table (ID: {table_item.id}")
|
|
82
85
|
|
|
83
86
|
def _get_columns_for_table(self, table_item, req_options=None):
|
|
84
|
-
url = "{
|
|
87
|
+
url = f"{self.baseurl}/{table_item.id}/columns"
|
|
85
88
|
server_response = self.get_request(url, req_options)
|
|
86
89
|
columns = ColumnItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
87
90
|
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
@@ -89,12 +92,12 @@ class Tables(Endpoint):
|
|
|
89
92
|
|
|
90
93
|
@api(version="3.5")
|
|
91
94
|
def update_column(self, table_item, column_item):
|
|
92
|
-
url = "{
|
|
95
|
+
url = f"{self.baseurl}/{table_item.id}/columns/{column_item.id}"
|
|
93
96
|
update_req = RequestFactory.Column.update_req(column_item)
|
|
94
97
|
server_response = self.put_request(url, update_req)
|
|
95
98
|
column = ColumnItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
96
99
|
|
|
97
|
-
logger.info("Updated table item (ID: {
|
|
100
|
+
logger.info(f"Updated table item (ID: {table_item.id} & column item {column_item.id}")
|
|
98
101
|
return column
|
|
99
102
|
|
|
100
103
|
@api(version="3.5")
|
|
@@ -124,3 +127,14 @@ class Tables(Endpoint):
|
|
|
124
127
|
@api(version="3.5")
|
|
125
128
|
def delete_dqw(self, item):
|
|
126
129
|
self._data_quality_warnings.clear(item)
|
|
130
|
+
|
|
131
|
+
@api(version="3.9")
|
|
132
|
+
def add_tags(self, item: Union[TableItem, str], tags: Union[Iterable[str], str]) -> set[str]:
|
|
133
|
+
return super().add_tags(item, tags)
|
|
134
|
+
|
|
135
|
+
@api(version="3.9")
|
|
136
|
+
def delete_tags(self, item: Union[TableItem, str], tags: Union[Iterable[str], str]) -> None:
|
|
137
|
+
return super().delete_tags(item, tags)
|
|
138
|
+
|
|
139
|
+
def update_tags(self, item: TableItem) -> None: # type: ignore
|
|
140
|
+
raise NotImplementedError("Update tags is not implemented for TableItem")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional, TYPE_CHECKING
|
|
3
3
|
|
|
4
4
|
from tableauserverclient.server.endpoint.endpoint import Endpoint, api
|
|
5
5
|
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
|
|
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
|
|
15
15
|
class Tasks(Endpoint):
|
|
16
16
|
@property
|
|
17
17
|
def baseurl(self) -> str:
|
|
18
|
-
return "{
|
|
18
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tasks"
|
|
19
19
|
|
|
20
20
|
def __normalize_task_type(self, task_type: str) -> str:
|
|
21
21
|
"""
|
|
@@ -23,20 +23,20 @@ class Tasks(Endpoint):
|
|
|
23
23
|
It is different than the tag "extractRefresh" used in the request body.
|
|
24
24
|
"""
|
|
25
25
|
if task_type == TaskItem.Type.ExtractRefresh:
|
|
26
|
-
return "{}es"
|
|
26
|
+
return f"{task_type}es"
|
|
27
27
|
else:
|
|
28
28
|
return task_type
|
|
29
29
|
|
|
30
30
|
@api(version="2.6")
|
|
31
31
|
def get(
|
|
32
32
|
self, req_options: Optional["RequestOptions"] = None, task_type: str = TaskItem.Type.ExtractRefresh
|
|
33
|
-
) ->
|
|
33
|
+
) -> tuple[list[TaskItem], PaginationItem]:
|
|
34
34
|
if task_type == TaskItem.Type.DataAcceleration:
|
|
35
35
|
self.parent_srv.assert_at_least_version("3.8", "Data Acceleration Tasks")
|
|
36
36
|
|
|
37
37
|
logger.info("Querying all %s tasks for the site", task_type)
|
|
38
38
|
|
|
39
|
-
url = "{
|
|
39
|
+
url = f"{self.baseurl}/{self.__normalize_task_type(task_type)}"
|
|
40
40
|
server_response = self.get_request(url, req_options)
|
|
41
41
|
|
|
42
42
|
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
@@ -63,7 +63,7 @@ class Tasks(Endpoint):
|
|
|
63
63
|
error = "No extract refresh provided"
|
|
64
64
|
raise ValueError(error)
|
|
65
65
|
logger.info("Creating an extract refresh %s", extract_item)
|
|
66
|
-
url = "{
|
|
66
|
+
url = f"{self.baseurl}/{self.__normalize_task_type(TaskItem.Type.ExtractRefresh)}"
|
|
67
67
|
create_req = RequestFactory.Task.create_extract_req(extract_item)
|
|
68
68
|
server_response = self.post_request(url, create_req)
|
|
69
69
|
return server_response.content
|
|
@@ -74,7 +74,7 @@ class Tasks(Endpoint):
|
|
|
74
74
|
error = "Task item missing ID."
|
|
75
75
|
raise MissingRequiredFieldError(error)
|
|
76
76
|
|
|
77
|
-
url = "{
|
|
77
|
+
url = "{}/{}/{}/runNow".format(
|
|
78
78
|
self.baseurl,
|
|
79
79
|
self.__normalize_task_type(TaskItem.Type.ExtractRefresh),
|
|
80
80
|
task_item.id,
|
|
@@ -92,6 +92,6 @@ class Tasks(Endpoint):
|
|
|
92
92
|
if not task_id:
|
|
93
93
|
error = "No Task ID provided"
|
|
94
94
|
raise ValueError(error)
|
|
95
|
-
url = "{
|
|
95
|
+
url = f"{self.baseurl}/{self.__normalize_task_type(task_type)}/{task_id}"
|
|
96
96
|
self.delete_request(url)
|
|
97
97
|
logger.info("Deleted single task (ID: %s)", task_id)
|