tableauserverclient 0.36__py3-none-any.whl → 0.38__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 +6 -0
- tableauserverclient/bin/_version.py +3 -3
- tableauserverclient/helpers/strings.py +25 -1
- tableauserverclient/models/__init__.py +6 -1
- tableauserverclient/models/connection_item.py +3 -3
- tableauserverclient/models/datasource_item.py +218 -23
- tableauserverclient/models/extract_item.py +82 -0
- tableauserverclient/models/flow_item.py +2 -2
- tableauserverclient/models/group_item.py +11 -0
- tableauserverclient/models/interval_item.py +40 -0
- tableauserverclient/models/job_item.py +1 -0
- tableauserverclient/models/location_item.py +53 -0
- tableauserverclient/models/project_item.py +138 -27
- tableauserverclient/models/schedule_item.py +57 -0
- tableauserverclient/models/site_item.py +28 -0
- tableauserverclient/models/table_item.py +7 -3
- tableauserverclient/models/tableau_types.py +13 -1
- tableauserverclient/models/user_item.py +101 -1
- tableauserverclient/models/view_item.py +79 -5
- tableauserverclient/models/workbook_item.py +151 -1
- tableauserverclient/server/__init__.py +2 -0
- tableauserverclient/server/endpoint/databases_endpoint.py +101 -18
- tableauserverclient/server/endpoint/datasources_endpoint.py +562 -7
- tableauserverclient/server/endpoint/dqw_endpoint.py +16 -6
- tableauserverclient/server/endpoint/endpoint.py +39 -0
- tableauserverclient/server/endpoint/exceptions.py +4 -0
- tableauserverclient/server/endpoint/fileuploads_endpoint.py +1 -1
- tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
- tableauserverclient/server/endpoint/jobs_endpoint.py +1 -1
- tableauserverclient/server/endpoint/schedules_endpoint.py +132 -2
- tableauserverclient/server/endpoint/sites_endpoint.py +18 -1
- tableauserverclient/server/endpoint/tables_endpoint.py +140 -17
- tableauserverclient/server/endpoint/users_endpoint.py +22 -5
- tableauserverclient/server/endpoint/views_endpoint.py +5 -1
- tableauserverclient/server/endpoint/workbooks_endpoint.py +24 -10
- tableauserverclient/server/query.py +36 -0
- tableauserverclient/server/request_factory.py +16 -5
- tableauserverclient/server/request_options.py +162 -2
- tableauserverclient/server/server.py +42 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/METADATA +3 -2
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/RECORD +45 -43
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/WHEEL +1 -1
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE +0 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from typing import Callable, Optional, Protocol, TYPE_CHECKING
|
|
2
3
|
|
|
3
4
|
from .endpoint import Endpoint
|
|
4
5
|
from .exceptions import MissingRequiredFieldError
|
|
@@ -7,6 +8,15 @@ from tableauserverclient.models import DQWItem
|
|
|
7
8
|
|
|
8
9
|
from tableauserverclient.helpers.logging import logger
|
|
9
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from tableauserverclient.server.request_options import RequestOptions
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class HasId(Protocol):
|
|
16
|
+
@property
|
|
17
|
+
def id(self) -> Optional[str]: ...
|
|
18
|
+
def _set_data_quality_warnings(self, dqw: Callable[[], list[DQWItem]]): ...
|
|
19
|
+
|
|
10
20
|
|
|
11
21
|
class _DataQualityWarningEndpoint(Endpoint):
|
|
12
22
|
def __init__(self, parent_srv, resource_type):
|
|
@@ -14,12 +24,12 @@ class _DataQualityWarningEndpoint(Endpoint):
|
|
|
14
24
|
self.resource_type = resource_type
|
|
15
25
|
|
|
16
26
|
@property
|
|
17
|
-
def baseurl(self):
|
|
27
|
+
def baseurl(self) -> str:
|
|
18
28
|
return "{}/sites/{}/dataQualityWarnings/{}".format(
|
|
19
29
|
self.parent_srv.baseurl, self.parent_srv.site_id, self.resource_type
|
|
20
30
|
)
|
|
21
31
|
|
|
22
|
-
def add(self, resource, warning):
|
|
32
|
+
def add(self, resource: HasId, warning: DQWItem) -> list[DQWItem]:
|
|
23
33
|
url = f"{self.baseurl}/{resource.id}"
|
|
24
34
|
add_req = RequestFactory.DQW.add_req(warning)
|
|
25
35
|
response = self.post_request(url, add_req)
|
|
@@ -28,7 +38,7 @@ class _DataQualityWarningEndpoint(Endpoint):
|
|
|
28
38
|
|
|
29
39
|
return warnings
|
|
30
40
|
|
|
31
|
-
def update(self, resource, warning):
|
|
41
|
+
def update(self, resource: HasId, warning: DQWItem) -> list[DQWItem]:
|
|
32
42
|
url = f"{self.baseurl}/{resource.id}"
|
|
33
43
|
add_req = RequestFactory.DQW.update_req(warning)
|
|
34
44
|
response = self.put_request(url, add_req)
|
|
@@ -37,11 +47,11 @@ class _DataQualityWarningEndpoint(Endpoint):
|
|
|
37
47
|
|
|
38
48
|
return warnings
|
|
39
49
|
|
|
40
|
-
def clear(self, resource):
|
|
50
|
+
def clear(self, resource: HasId) -> None:
|
|
41
51
|
url = f"{self.baseurl}/{resource.id}"
|
|
42
52
|
return self.delete_request(url)
|
|
43
53
|
|
|
44
|
-
def populate(self, item):
|
|
54
|
+
def populate(self, item: HasId) -> None:
|
|
45
55
|
if not item.id:
|
|
46
56
|
error = "Server item is missing ID. Item must be retrieved from server first."
|
|
47
57
|
raise MissingRequiredFieldError(error)
|
|
@@ -52,7 +62,7 @@ class _DataQualityWarningEndpoint(Endpoint):
|
|
|
52
62
|
item._set_data_quality_warnings(dqw_fetcher)
|
|
53
63
|
logger.info(f"Populated permissions for item (ID: {item.id})")
|
|
54
64
|
|
|
55
|
-
def _get_data_quality_warnings(self, item, req_options=None):
|
|
65
|
+
def _get_data_quality_warnings(self, item: HasId, req_options: Optional["RequestOptions"] = None) -> list[DQWItem]:
|
|
56
66
|
url = f"{self.baseurl}/{item.id}"
|
|
57
67
|
server_response = self.get_request(url, req_options)
|
|
58
68
|
dqws = DQWItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
@@ -14,6 +14,7 @@ from typing import (
|
|
|
14
14
|
TypeVar,
|
|
15
15
|
Union,
|
|
16
16
|
)
|
|
17
|
+
from typing_extensions import Self
|
|
17
18
|
|
|
18
19
|
from tableauserverclient.models.pagination_item import PaginationItem
|
|
19
20
|
from tableauserverclient.server.request_options import RequestOptions
|
|
@@ -353,3 +354,41 @@ class QuerysetEndpoint(Endpoint, Generic[T]):
|
|
|
353
354
|
@abc.abstractmethod
|
|
354
355
|
def get(self, request_options: Optional[RequestOptions] = None) -> tuple[list[T], PaginationItem]:
|
|
355
356
|
raise NotImplementedError(f".get has not been implemented for {self.__class__.__qualname__}")
|
|
357
|
+
|
|
358
|
+
def fields(self: Self, *fields: str) -> QuerySet:
|
|
359
|
+
"""
|
|
360
|
+
Add fields to the request options. If no fields are provided, the
|
|
361
|
+
default fields will be used. If fields are provided, the default fields
|
|
362
|
+
will be used in addition to the provided fields.
|
|
363
|
+
|
|
364
|
+
Parameters
|
|
365
|
+
----------
|
|
366
|
+
fields : str
|
|
367
|
+
The fields to include in the request options.
|
|
368
|
+
|
|
369
|
+
Returns
|
|
370
|
+
-------
|
|
371
|
+
QuerySet
|
|
372
|
+
"""
|
|
373
|
+
queryset = QuerySet(self)
|
|
374
|
+
queryset.request_options.fields |= set(fields) | set(("_default_",))
|
|
375
|
+
return queryset
|
|
376
|
+
|
|
377
|
+
def only_fields(self: Self, *fields: str) -> QuerySet:
|
|
378
|
+
"""
|
|
379
|
+
Add fields to the request options. If no fields are provided, the
|
|
380
|
+
default fields will be used. If fields are provided, the default fields
|
|
381
|
+
will be replaced by the provided fields.
|
|
382
|
+
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
fields : str
|
|
386
|
+
The fields to include in the request options.
|
|
387
|
+
|
|
388
|
+
Returns
|
|
389
|
+
-------
|
|
390
|
+
QuerySet
|
|
391
|
+
"""
|
|
392
|
+
queryset = QuerySet(self)
|
|
393
|
+
queryset.request_options.fields |= set(fields)
|
|
394
|
+
return queryset
|
|
@@ -56,6 +56,6 @@ class Fileuploads(Endpoint):
|
|
|
56
56
|
request, content_type = RequestFactory.Fileupload.chunk_req(chunk)
|
|
57
57
|
logger.debug(f"{datetime.timestamp()} created chunk request")
|
|
58
58
|
fileupload_item = self.append(upload_id, request, content_type)
|
|
59
|
-
logger.info(f"\t{datetime.timestamp()} Published {
|
|
59
|
+
logger.info(f"\t{datetime.timestamp()} Published {fileupload_item.file_size}MB")
|
|
60
60
|
logger.info(f"File upload finished (ID: {upload_id})")
|
|
61
61
|
return upload_id
|
|
@@ -25,14 +25,14 @@ class GroupSets(QuerysetEndpoint[GroupSetItem]):
|
|
|
25
25
|
@api(version="3.22")
|
|
26
26
|
def get(
|
|
27
27
|
self,
|
|
28
|
-
|
|
28
|
+
req_options: Optional[RequestOptions] = None,
|
|
29
29
|
result_level: Optional[Literal["members", "local"]] = None,
|
|
30
30
|
) -> tuple[list[GroupSetItem], PaginationItem]:
|
|
31
31
|
logger.info("Querying all group sets on site")
|
|
32
32
|
url = self.baseurl
|
|
33
33
|
if result_level:
|
|
34
34
|
url += f"?resultlevel={result_level}"
|
|
35
|
-
server_response = self.get_request(url,
|
|
35
|
+
server_response = self.get_request(url, req_options)
|
|
36
36
|
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
37
37
|
all_group_set_items = GroupSetItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
38
38
|
return all_group_set_items, pagination_item
|
|
@@ -188,7 +188,7 @@ class Jobs(QuerysetEndpoint[BackgroundJobItem]):
|
|
|
188
188
|
|
|
189
189
|
logger.info(f"Job {job_id} Completed: Finish Code: {job.finish_code} - Notes:{job.notes}")
|
|
190
190
|
|
|
191
|
-
if job.finish_code
|
|
191
|
+
if job.finish_code in [JobItem.FinishCode.Success, JobItem.FinishCode.Completed]:
|
|
192
192
|
return job
|
|
193
193
|
elif job.finish_code == JobItem.FinishCode.Failed:
|
|
194
194
|
raise JobFailedException(job)
|
|
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Callable, Optional, Union
|
|
|
7
7
|
from .endpoint import Endpoint, api, parameter_added_in
|
|
8
8
|
from .exceptions import MissingRequiredFieldError
|
|
9
9
|
from tableauserverclient.server import RequestFactory
|
|
10
|
-
from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem
|
|
10
|
+
from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem, ExtractItem
|
|
11
11
|
|
|
12
12
|
from tableauserverclient.helpers.logging import logger
|
|
13
13
|
|
|
@@ -30,6 +30,23 @@ class Schedules(Endpoint):
|
|
|
30
30
|
|
|
31
31
|
@api(version="2.3")
|
|
32
32
|
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[ScheduleItem], PaginationItem]:
|
|
33
|
+
"""
|
|
34
|
+
Returns a list of flows, extract, and subscription server schedules on
|
|
35
|
+
Tableau Server. For each schedule, the API returns name, frequency,
|
|
36
|
+
priority, and other information.
|
|
37
|
+
|
|
38
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_schedules
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
req_options : Optional[RequestOptions]
|
|
43
|
+
Filtering and paginating options for request.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
Tuple[List[ScheduleItem], PaginationItem]
|
|
48
|
+
A tuple of list of ScheduleItem and PaginationItem
|
|
49
|
+
"""
|
|
33
50
|
logger.info("Querying all schedules")
|
|
34
51
|
url = self.baseurl
|
|
35
52
|
server_response = self.get_request(url, req_options)
|
|
@@ -38,7 +55,22 @@ class Schedules(Endpoint):
|
|
|
38
55
|
return all_schedule_items, pagination_item
|
|
39
56
|
|
|
40
57
|
@api(version="3.8")
|
|
41
|
-
def get_by_id(self, schedule_id):
|
|
58
|
+
def get_by_id(self, schedule_id: str) -> ScheduleItem:
|
|
59
|
+
"""
|
|
60
|
+
Returns detailed information about the specified server schedule.
|
|
61
|
+
|
|
62
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#get-schedule
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
schedule_id : str
|
|
67
|
+
The ID of the schedule to get information for.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
ScheduleItem
|
|
72
|
+
The schedule item that corresponds to the given ID.
|
|
73
|
+
"""
|
|
42
74
|
if not schedule_id:
|
|
43
75
|
error = "No Schedule ID provided"
|
|
44
76
|
raise ValueError(error)
|
|
@@ -49,6 +81,20 @@ class Schedules(Endpoint):
|
|
|
49
81
|
|
|
50
82
|
@api(version="2.3")
|
|
51
83
|
def delete(self, schedule_id: str) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Deletes the specified schedule from the server.
|
|
86
|
+
|
|
87
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#delete_schedule
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
schedule_id : str
|
|
92
|
+
The ID of the schedule to delete.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
None
|
|
97
|
+
"""
|
|
52
98
|
if not schedule_id:
|
|
53
99
|
error = "Schedule ID undefined"
|
|
54
100
|
raise ValueError(error)
|
|
@@ -58,6 +104,23 @@ class Schedules(Endpoint):
|
|
|
58
104
|
|
|
59
105
|
@api(version="2.3")
|
|
60
106
|
def update(self, schedule_item: ScheduleItem) -> ScheduleItem:
|
|
107
|
+
"""
|
|
108
|
+
Modifies settings for the specified server schedule, including the name,
|
|
109
|
+
priority, and frequency details on Tableau Server. For Tableau Cloud,
|
|
110
|
+
see the tasks and subscritpions API.
|
|
111
|
+
|
|
112
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#update_schedule
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
schedule_item : ScheduleItem
|
|
117
|
+
The schedule item to update.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
ScheduleItem
|
|
122
|
+
The updated schedule item.
|
|
123
|
+
"""
|
|
61
124
|
if not schedule_item.id:
|
|
62
125
|
error = "Schedule item missing ID."
|
|
63
126
|
raise MissingRequiredFieldError(error)
|
|
@@ -71,6 +134,20 @@ class Schedules(Endpoint):
|
|
|
71
134
|
|
|
72
135
|
@api(version="2.3")
|
|
73
136
|
def create(self, schedule_item: ScheduleItem) -> ScheduleItem:
|
|
137
|
+
"""
|
|
138
|
+
Creates a new server schedule on Tableau Server. For Tableau Cloud, use
|
|
139
|
+
the tasks and subscriptions API.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
schedule_item : ScheduleItem
|
|
144
|
+
The schedule item to create.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
ScheduleItem
|
|
149
|
+
The newly created schedule.
|
|
150
|
+
"""
|
|
74
151
|
if schedule_item.interval_item is None:
|
|
75
152
|
error = "Interval item must be defined."
|
|
76
153
|
raise MissingRequiredFieldError(error)
|
|
@@ -92,6 +169,41 @@ class Schedules(Endpoint):
|
|
|
92
169
|
flow: Optional["FlowItem"] = None,
|
|
93
170
|
task_type: Optional[str] = None,
|
|
94
171
|
) -> list[AddResponse]:
|
|
172
|
+
"""
|
|
173
|
+
Adds a workbook, datasource, or flow to a schedule on Tableau Server.
|
|
174
|
+
Only one of workbook, datasource, or flow can be passed in at a time.
|
|
175
|
+
|
|
176
|
+
The task type is optional and will default to ExtractRefresh if a
|
|
177
|
+
workbook or datasource is passed in, and RunFlow if a flow is passed in.
|
|
178
|
+
|
|
179
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#add_workbook_to_schedule
|
|
180
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#add_data_source_to_schedule
|
|
181
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_flow.htm#add_flow_task_to_schedule
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
schedule_id : str
|
|
186
|
+
The ID of the schedule to add the item to.
|
|
187
|
+
|
|
188
|
+
workbook : Optional[WorkbookItem]
|
|
189
|
+
The workbook to add to the schedule.
|
|
190
|
+
|
|
191
|
+
datasource : Optional[DatasourceItem]
|
|
192
|
+
The datasource to add to the schedule.
|
|
193
|
+
|
|
194
|
+
flow : Optional[FlowItem]
|
|
195
|
+
The flow to add to the schedule.
|
|
196
|
+
|
|
197
|
+
task_type : Optional[str]
|
|
198
|
+
The type of task to add to the schedule. If not provided, it will
|
|
199
|
+
default to ExtractRefresh if a workbook or datasource is passed in,
|
|
200
|
+
and RunFlow if a flow is passed in.
|
|
201
|
+
|
|
202
|
+
Returns
|
|
203
|
+
-------
|
|
204
|
+
list[AddResponse]
|
|
205
|
+
A list of responses for each item added to the schedule.
|
|
206
|
+
"""
|
|
95
207
|
# There doesn't seem to be a good reason to allow one item of each type?
|
|
96
208
|
if workbook and datasource:
|
|
97
209
|
warnings.warn("Passing in multiple items for add_to_schedule will be deprecated", PendingDeprecationWarning)
|
|
@@ -149,3 +261,21 @@ class Schedules(Endpoint):
|
|
|
149
261
|
)
|
|
150
262
|
else:
|
|
151
263
|
return OK
|
|
264
|
+
|
|
265
|
+
@api(version="2.3")
|
|
266
|
+
def get_extract_refresh_tasks(
|
|
267
|
+
self, schedule_id: str, req_options: Optional["RequestOptions"] = None
|
|
268
|
+
) -> tuple[list["ExtractItem"], "PaginationItem"]:
|
|
269
|
+
"""Get all extract refresh tasks for the specified schedule."""
|
|
270
|
+
if not schedule_id:
|
|
271
|
+
error = "Schedule ID undefined"
|
|
272
|
+
raise ValueError(error)
|
|
273
|
+
|
|
274
|
+
logger.info(f"Querying extract refresh tasks for schedule (ID: {schedule_id})")
|
|
275
|
+
url = f"{self.siteurl}/{schedule_id}/extracts"
|
|
276
|
+
server_response = self.get_request(url, req_options)
|
|
277
|
+
|
|
278
|
+
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
279
|
+
extract_items = ExtractItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
280
|
+
|
|
281
|
+
return extract_items, pagination_item
|
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
from .endpoint import Endpoint, api
|
|
5
5
|
from .exceptions import MissingRequiredFieldError
|
|
6
6
|
from tableauserverclient.server import RequestFactory
|
|
7
|
-
from tableauserverclient.models import SiteItem, PaginationItem
|
|
7
|
+
from tableauserverclient.models import SiteAuthConfiguration, SiteItem, PaginationItem
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.helpers.logging import logger
|
|
10
10
|
|
|
@@ -418,3 +418,20 @@ class Sites(Endpoint):
|
|
|
418
418
|
|
|
419
419
|
empty_req = RequestFactory.Empty.empty_req()
|
|
420
420
|
self.post_request(url, empty_req)
|
|
421
|
+
|
|
422
|
+
@api(version="3.24")
|
|
423
|
+
def list_auth_configurations(self) -> list[SiteAuthConfiguration]:
|
|
424
|
+
"""
|
|
425
|
+
Lists all authentication configurations on the current site.
|
|
426
|
+
|
|
427
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_site.htm#list_authentication_configurations_site
|
|
428
|
+
|
|
429
|
+
Returns
|
|
430
|
+
-------
|
|
431
|
+
list[SiteAuthConfiguration]
|
|
432
|
+
A list of authentication configurations on the current site.
|
|
433
|
+
"""
|
|
434
|
+
url = f"{self.baseurl}/{self.parent_srv.site_id}/site-auth-configurations"
|
|
435
|
+
server_response = self.get_request(url)
|
|
436
|
+
auth_configurations = SiteAuthConfiguration.from_response(server_response.content, self.parent_srv.namespace)
|
|
437
|
+
return auth_configurations
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Union
|
|
2
|
+
from typing import Optional, Union, TYPE_CHECKING
|
|
3
3
|
from collections.abc import Iterable
|
|
4
4
|
|
|
5
|
+
from tableauserverclient.models.permissions_item import PermissionsRule
|
|
5
6
|
from tableauserverclient.server.endpoint.dqw_endpoint import _DataQualityWarningEndpoint
|
|
6
7
|
from tableauserverclient.server.endpoint.endpoint import api, Endpoint
|
|
7
8
|
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
|
|
@@ -12,6 +13,10 @@ from tableauserverclient.models import TableItem, ColumnItem, PaginationItem
|
|
|
12
13
|
from tableauserverclient.server.pager import Pager
|
|
13
14
|
|
|
14
15
|
from tableauserverclient.helpers.logging import logger
|
|
16
|
+
from tableauserverclient.server.request_options import RequestOptions
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from tableauserverclient.models import DQWItem, PermissionsRule
|
|
15
20
|
|
|
16
21
|
|
|
17
22
|
class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
@@ -22,11 +27,29 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
22
27
|
self._data_quality_warnings = _DataQualityWarningEndpoint(self.parent_srv, "table")
|
|
23
28
|
|
|
24
29
|
@property
|
|
25
|
-
def baseurl(self):
|
|
30
|
+
def baseurl(self) -> str:
|
|
26
31
|
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tables"
|
|
27
32
|
|
|
28
33
|
@api(version="3.5")
|
|
29
|
-
def get(self, req_options=None):
|
|
34
|
+
def get(self, req_options: Optional[RequestOptions] = None) -> tuple[list[TableItem], PaginationItem]:
|
|
35
|
+
"""
|
|
36
|
+
Get information about all tables on the site. Endpoint is paginated, and
|
|
37
|
+
will return a default of 100 items per page. Use the `req_options`
|
|
38
|
+
parameter to customize the request.
|
|
39
|
+
|
|
40
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_tables
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
req_options : RequestOptions, optional
|
|
45
|
+
Options to customize the request. If not provided, defaults to None.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
tuple[list[TableItem], PaginationItem]
|
|
50
|
+
A tuple containing a list of TableItem objects and a PaginationItem
|
|
51
|
+
object.
|
|
52
|
+
"""
|
|
30
53
|
logger.info("Querying all tables on site")
|
|
31
54
|
url = self.baseurl
|
|
32
55
|
server_response = self.get_request(url, req_options)
|
|
@@ -36,7 +59,27 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
36
59
|
|
|
37
60
|
# Get 1 table
|
|
38
61
|
@api(version="3.5")
|
|
39
|
-
def get_by_id(self, table_id):
|
|
62
|
+
def get_by_id(self, table_id: str) -> TableItem:
|
|
63
|
+
"""
|
|
64
|
+
Get information about a single table on the site.
|
|
65
|
+
|
|
66
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_table
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
table_id : str
|
|
71
|
+
The ID of the table to retrieve.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
TableItem
|
|
76
|
+
A TableItem object representing the table.
|
|
77
|
+
|
|
78
|
+
Raises
|
|
79
|
+
------
|
|
80
|
+
ValueError
|
|
81
|
+
If the table ID is not provided.
|
|
82
|
+
"""
|
|
40
83
|
if not table_id:
|
|
41
84
|
error = "table ID undefined."
|
|
42
85
|
raise ValueError(error)
|
|
@@ -46,7 +89,24 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
46
89
|
return TableItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
47
90
|
|
|
48
91
|
@api(version="3.5")
|
|
49
|
-
def delete(self, table_id):
|
|
92
|
+
def delete(self, table_id: str) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Delete a single table from the server.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
table_id : str
|
|
99
|
+
The ID of the table to delete.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
None
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
ValueError
|
|
108
|
+
If the table ID is not provided.
|
|
109
|
+
"""
|
|
50
110
|
if not table_id:
|
|
51
111
|
error = "Database ID undefined."
|
|
52
112
|
raise ValueError(error)
|
|
@@ -55,7 +115,27 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
55
115
|
logger.info(f"Deleted single table (ID: {table_id})")
|
|
56
116
|
|
|
57
117
|
@api(version="3.5")
|
|
58
|
-
def update(self, table_item):
|
|
118
|
+
def update(self, table_item: TableItem) -> TableItem:
|
|
119
|
+
"""
|
|
120
|
+
Update a table on the server.
|
|
121
|
+
|
|
122
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#update_table
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
table_item : TableItem
|
|
127
|
+
The TableItem object to update.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
TableItem
|
|
132
|
+
The updated TableItem object.
|
|
133
|
+
|
|
134
|
+
Raises
|
|
135
|
+
------
|
|
136
|
+
MissingRequiredFieldError
|
|
137
|
+
If the table item is missing an ID.
|
|
138
|
+
"""
|
|
59
139
|
if not table_item.id:
|
|
60
140
|
error = "table item missing ID."
|
|
61
141
|
raise MissingRequiredFieldError(error)
|
|
@@ -69,21 +149,46 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
69
149
|
|
|
70
150
|
# Get all columns of the table
|
|
71
151
|
@api(version="3.5")
|
|
72
|
-
def populate_columns(self, table_item, req_options=None):
|
|
152
|
+
def populate_columns(self, table_item: TableItem, req_options: Optional[RequestOptions] = None) -> None:
|
|
153
|
+
"""
|
|
154
|
+
Populate the columns of a table item. Sets a fetcher function to
|
|
155
|
+
retrieve the columns when needed.
|
|
156
|
+
|
|
157
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_columns
|
|
158
|
+
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
table_item : TableItem
|
|
162
|
+
The TableItem object to populate columns for.
|
|
163
|
+
|
|
164
|
+
req_options : RequestOptions, optional
|
|
165
|
+
Options to customize the request. If not provided, defaults to None.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
None
|
|
170
|
+
|
|
171
|
+
Raises
|
|
172
|
+
------
|
|
173
|
+
MissingRequiredFieldError
|
|
174
|
+
If the table item is missing an ID.
|
|
175
|
+
"""
|
|
73
176
|
if not table_item.id:
|
|
74
177
|
error = "Table item missing ID. table must be retrieved from server first."
|
|
75
178
|
raise MissingRequiredFieldError(error)
|
|
76
179
|
|
|
77
180
|
def column_fetcher():
|
|
78
181
|
return Pager(
|
|
79
|
-
lambda options: self._get_columns_for_table(table_item, options),
|
|
182
|
+
lambda options: self._get_columns_for_table(table_item, options), # type: ignore
|
|
80
183
|
req_options,
|
|
81
184
|
)
|
|
82
185
|
|
|
83
186
|
table_item._set_columns(column_fetcher)
|
|
84
187
|
logger.info(f"Populated columns for table (ID: {table_item.id}")
|
|
85
188
|
|
|
86
|
-
def _get_columns_for_table(
|
|
189
|
+
def _get_columns_for_table(
|
|
190
|
+
self, table_item: TableItem, req_options: Optional[RequestOptions] = None
|
|
191
|
+
) -> tuple[list[ColumnItem], PaginationItem]:
|
|
87
192
|
url = f"{self.baseurl}/{table_item.id}/columns"
|
|
88
193
|
server_response = self.get_request(url, req_options)
|
|
89
194
|
columns = ColumnItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
@@ -91,7 +196,25 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
91
196
|
return columns, pagination_item
|
|
92
197
|
|
|
93
198
|
@api(version="3.5")
|
|
94
|
-
def update_column(self, table_item, column_item):
|
|
199
|
+
def update_column(self, table_item: TableItem, column_item: ColumnItem) -> ColumnItem:
|
|
200
|
+
"""
|
|
201
|
+
Update the description of a column in a table.
|
|
202
|
+
|
|
203
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#update_column
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
table_item : TableItem
|
|
208
|
+
The TableItem object representing the table.
|
|
209
|
+
|
|
210
|
+
column_item : ColumnItem
|
|
211
|
+
The ColumnItem object representing the column to update.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
ColumnItem
|
|
216
|
+
The updated ColumnItem object.
|
|
217
|
+
"""
|
|
95
218
|
url = f"{self.baseurl}/{table_item.id}/columns/{column_item.id}"
|
|
96
219
|
update_req = RequestFactory.Column.update_req(column_item)
|
|
97
220
|
server_response = self.put_request(url, update_req)
|
|
@@ -101,31 +224,31 @@ class Tables(Endpoint, TaggingMixin[TableItem]):
|
|
|
101
224
|
return column
|
|
102
225
|
|
|
103
226
|
@api(version="3.5")
|
|
104
|
-
def populate_permissions(self, item):
|
|
227
|
+
def populate_permissions(self, item: TableItem) -> None:
|
|
105
228
|
self._permissions.populate(item)
|
|
106
229
|
|
|
107
230
|
@api(version="3.5")
|
|
108
|
-
def update_permissions(self, item, rules):
|
|
231
|
+
def update_permissions(self, item: TableItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
|
|
109
232
|
return self._permissions.update(item, rules)
|
|
110
233
|
|
|
111
234
|
@api(version="3.5")
|
|
112
|
-
def delete_permission(self, item, rules):
|
|
235
|
+
def delete_permission(self, item: TableItem, rules: list[PermissionsRule]) -> None:
|
|
113
236
|
return self._permissions.delete(item, rules)
|
|
114
237
|
|
|
115
238
|
@api(version="3.5")
|
|
116
|
-
def populate_dqw(self, item):
|
|
239
|
+
def populate_dqw(self, item: TableItem) -> None:
|
|
117
240
|
self._data_quality_warnings.populate(item)
|
|
118
241
|
|
|
119
242
|
@api(version="3.5")
|
|
120
|
-
def update_dqw(self, item, warning):
|
|
243
|
+
def update_dqw(self, item: TableItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
121
244
|
return self._data_quality_warnings.update(item, warning)
|
|
122
245
|
|
|
123
246
|
@api(version="3.5")
|
|
124
|
-
def add_dqw(self, item, warning):
|
|
247
|
+
def add_dqw(self, item: TableItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
125
248
|
return self._data_quality_warnings.add(item, warning)
|
|
126
249
|
|
|
127
250
|
@api(version="3.5")
|
|
128
|
-
def delete_dqw(self, item):
|
|
251
|
+
def delete_dqw(self, item: TableItem) -> None:
|
|
129
252
|
self._data_quality_warnings.clear(item)
|
|
130
253
|
|
|
131
254
|
@api(version="3.9")
|