tableauserverclient 0.37__py3-none-any.whl → 0.39__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/bin/_version.py → _version.py +3 -3
- bin/__init__.py +3 -0
- bin/_version.py +21 -0
- {tableauserverclient/helpers → helpers}/strings.py +25 -1
- {tableauserverclient/models → models}/__init__.py +15 -1
- models/collection_item.py +52 -0
- {tableauserverclient/models → models}/connection_item.py +16 -2
- {tableauserverclient/models → models}/custom_view_item.py +8 -0
- {tableauserverclient/models → models}/data_freshness_policy_item.py +3 -3
- {tableauserverclient/models → models}/datasource_item.py +113 -3
- models/extensions_item.py +186 -0
- models/extract_item.py +82 -0
- {tableauserverclient/models → models}/favorites_item.py +21 -8
- {tableauserverclient/models → models}/flow_item.py +3 -3
- {tableauserverclient/models → models}/group_item.py +18 -1
- {tableauserverclient/models → models}/groupset_item.py +14 -0
- {tableauserverclient/models → models}/interval_item.py +42 -1
- models/location_item.py +53 -0
- models/oidc_item.py +82 -0
- {tableauserverclient/models → models}/permissions_item.py +2 -0
- {tableauserverclient/models → models}/project_item.py +141 -29
- {tableauserverclient/models → models}/property_decorators.py +2 -2
- {tableauserverclient/models → models}/reference_item.py +12 -6
- {tableauserverclient/models → models}/schedule_item.py +67 -1
- {tableauserverclient/models → models}/site_item.py +54 -0
- {tableauserverclient/models → models}/table_item.py +7 -3
- {tableauserverclient/models → models}/tableau_auth.py +13 -6
- {tableauserverclient/models → models}/tableau_types.py +13 -1
- {tableauserverclient/models → models}/user_item.py +111 -4
- {tableauserverclient/models → models}/view_item.py +79 -5
- {tableauserverclient/models → models}/workbook_item.py +153 -3
- {tableauserverclient/server → server}/endpoint/__init__.py +4 -0
- {tableauserverclient/server → server}/endpoint/databases_endpoint.py +101 -18
- {tableauserverclient/server → server}/endpoint/datasources_endpoint.py +155 -25
- {tableauserverclient/server → server}/endpoint/dqw_endpoint.py +16 -6
- {tableauserverclient/server → server}/endpoint/endpoint.py +39 -0
- server/endpoint/extensions_endpoint.py +79 -0
- {tableauserverclient/server → server}/endpoint/flow_task_endpoint.py +1 -1
- {tableauserverclient/server → server}/endpoint/flows_endpoint.py +5 -4
- server/endpoint/oidc_endpoint.py +157 -0
- {tableauserverclient/server → server}/endpoint/projects_endpoint.py +12 -0
- server/endpoint/schedules_endpoint.py +328 -0
- {tableauserverclient/server → server}/endpoint/sites_endpoint.py +18 -1
- {tableauserverclient/server → server}/endpoint/tables_endpoint.py +140 -17
- {tableauserverclient/server → server}/endpoint/users_endpoint.py +296 -10
- {tableauserverclient/server → server}/endpoint/views_endpoint.py +23 -0
- {tableauserverclient/server → server}/endpoint/workbooks_endpoint.py +124 -9
- {tableauserverclient/server → server}/query.py +36 -0
- {tableauserverclient/server → server}/request_factory.py +286 -2
- {tableauserverclient/server → server}/request_options.py +139 -3
- {tableauserverclient/server → server}/server.py +46 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/METADATA +5 -26
- tableauserverclient-0.39.dist-info/RECORD +107 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/WHEEL +1 -1
- tableauserverclient-0.39.dist-info/top_level.txt +4 -0
- tableauserverclient/__init__.py +0 -141
- tableauserverclient/config.py +0 -27
- tableauserverclient/datetime_helpers.py +0 -45
- tableauserverclient/exponential_backoff.py +0 -30
- tableauserverclient/filesys_helpers.py +0 -63
- tableauserverclient/namespace.py +0 -37
- tableauserverclient/py.typed +0 -0
- tableauserverclient/server/endpoint/schedules_endpoint.py +0 -151
- tableauserverclient-0.37.dist-info/RECORD +0 -106
- tableauserverclient-0.37.dist-info/licenses/LICENSE.versioneer +0 -7
- tableauserverclient-0.37.dist-info/top_level.txt +0 -1
- {tableauserverclient/helpers → helpers}/__init__.py +0 -0
- {tableauserverclient/helpers → helpers}/headers.py +0 -0
- {tableauserverclient/helpers → helpers}/logging.py +0 -0
- {tableauserverclient/models → models}/column_item.py +0 -0
- {tableauserverclient/models → models}/connection_credentials.py +0 -0
- {tableauserverclient/models → models}/data_acceleration_report_item.py +0 -0
- {tableauserverclient/models → models}/data_alert_item.py +0 -0
- {tableauserverclient/models → models}/database_item.py +0 -0
- {tableauserverclient/models → models}/dqw_item.py +0 -0
- {tableauserverclient/models → models}/exceptions.py +0 -0
- {tableauserverclient/models → models}/fileupload_item.py +0 -0
- {tableauserverclient/models → models}/flow_run_item.py +0 -0
- {tableauserverclient/models → models}/job_item.py +0 -0
- {tableauserverclient/models → models}/linked_tasks_item.py +0 -0
- {tableauserverclient/models → models}/metric_item.py +0 -0
- {tableauserverclient/models → models}/pagination_item.py +0 -0
- {tableauserverclient/models → models}/revision_item.py +0 -0
- {tableauserverclient/models → models}/server_info_item.py +0 -0
- {tableauserverclient/models → models}/subscription_item.py +0 -0
- {tableauserverclient/models → models}/tag_item.py +0 -0
- {tableauserverclient/models → models}/target.py +0 -0
- {tableauserverclient/models → models}/task_item.py +0 -0
- {tableauserverclient/models → models}/virtual_connection_item.py +0 -0
- {tableauserverclient/models → models}/webhook_item.py +0 -0
- {tableauserverclient/server → server}/__init__.py +0 -0
- {tableauserverclient/server → server}/endpoint/auth_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/custom_views_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/data_acceleration_report_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/data_alert_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/default_permissions_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/exceptions.py +0 -0
- {tableauserverclient/server → server}/endpoint/favorites_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/fileuploads_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/flow_runs_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/groups_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/groupsets_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/jobs_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/linked_tasks_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/metadata_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/metrics_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/permissions_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/resource_tagger.py +0 -0
- {tableauserverclient/server → server}/endpoint/server_info_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/subscriptions_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/tasks_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/virtual_connections_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/webhooks_endpoint.py +0 -0
- {tableauserverclient/server → server}/exceptions.py +0 -0
- {tableauserverclient/server → server}/filter.py +0 -0
- {tableauserverclient/server → server}/pager.py +0 -0
- {tableauserverclient/server → server}/sort.py +0 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from tableauserverclient.models.extensions_item import ExtensionsServer, ExtensionsSiteSettings
|
|
2
|
+
from tableauserverclient.server.endpoint.endpoint import Endpoint
|
|
3
|
+
from tableauserverclient.server.endpoint.endpoint import api
|
|
4
|
+
from tableauserverclient.server.request_factory import RequestFactory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Extensions(Endpoint):
|
|
8
|
+
def __init__(self, parent_srv):
|
|
9
|
+
super().__init__(parent_srv)
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def _server_baseurl(self) -> str:
|
|
13
|
+
return f"{self.parent_srv.baseurl}/settings/extensions"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def baseurl(self) -> str:
|
|
17
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/settings/extensions"
|
|
18
|
+
|
|
19
|
+
@api(version="3.21")
|
|
20
|
+
def get_server_settings(self) -> ExtensionsServer:
|
|
21
|
+
"""Lists the settings for extensions of a server
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
ExtensionsServer
|
|
26
|
+
The server extensions settings
|
|
27
|
+
"""
|
|
28
|
+
response = self.get_request(self._server_baseurl)
|
|
29
|
+
return ExtensionsServer.from_response(response.content, self.parent_srv.namespace)
|
|
30
|
+
|
|
31
|
+
@api(version="3.21")
|
|
32
|
+
def update_server_settings(self, extensions_server: ExtensionsServer) -> ExtensionsServer:
|
|
33
|
+
"""Updates the settings for extensions of a server. Overwrites all existing settings. Any
|
|
34
|
+
sites omitted from the block list will be unblocked.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
extensions_server : ExtensionsServer
|
|
39
|
+
The server extensions settings to update
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
ExtensionsServer
|
|
44
|
+
The updated server extensions settings
|
|
45
|
+
"""
|
|
46
|
+
req = RequestFactory.Extensions.update_server_extensions(extensions_server)
|
|
47
|
+
response = self.put_request(self._server_baseurl, req)
|
|
48
|
+
return ExtensionsServer.from_response(response.content, self.parent_srv.namespace)
|
|
49
|
+
|
|
50
|
+
@api(version="3.21")
|
|
51
|
+
def get(self) -> ExtensionsSiteSettings:
|
|
52
|
+
"""Lists the extensions settings for the site
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
ExtensionsSiteSettings
|
|
57
|
+
The site extensions settings
|
|
58
|
+
"""
|
|
59
|
+
response = self.get_request(self.baseurl)
|
|
60
|
+
return ExtensionsSiteSettings.from_response(response.content, self.parent_srv.namespace)
|
|
61
|
+
|
|
62
|
+
@api(version="3.21")
|
|
63
|
+
def update(self, extensions_site_settings: ExtensionsSiteSettings) -> ExtensionsSiteSettings:
|
|
64
|
+
"""Updates the extensions settings for the site. Any extensions omitted
|
|
65
|
+
from the safe extensions list will be removed.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
extensions_site_settings : ExtensionsSiteSettings
|
|
70
|
+
The site extensions settings to update
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
ExtensionsSiteSettings
|
|
75
|
+
The updated site extensions settings
|
|
76
|
+
"""
|
|
77
|
+
req = RequestFactory.Extensions.update_site_extensions(extensions_site_settings)
|
|
78
|
+
response = self.put_request(self.baseurl, req)
|
|
79
|
+
return ExtensionsSiteSettings.from_response(response.content, self.parent_srv.namespace)
|
|
@@ -18,7 +18,7 @@ class FlowTasks(Endpoint):
|
|
|
18
18
|
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tasks/flows"
|
|
19
19
|
|
|
20
20
|
@api(version="3.22")
|
|
21
|
-
def create(self, flow_item: TaskItem) ->
|
|
21
|
+
def create(self, flow_item: TaskItem) -> bytes:
|
|
22
22
|
if not flow_item:
|
|
23
23
|
error = "No flow provided"
|
|
24
24
|
raise ValueError(error)
|
|
@@ -308,7 +308,7 @@ class Flows(QuerysetEndpoint[FlowItem], TaggingMixin[FlowItem]):
|
|
|
308
308
|
return connection
|
|
309
309
|
|
|
310
310
|
@api(version="3.3")
|
|
311
|
-
def refresh(self, flow_item: FlowItem) -> JobItem:
|
|
311
|
+
def refresh(self, flow_item: Union[FlowItem, str]) -> JobItem:
|
|
312
312
|
"""
|
|
313
313
|
Runs the flow to refresh the data.
|
|
314
314
|
|
|
@@ -316,15 +316,16 @@ class Flows(QuerysetEndpoint[FlowItem], TaggingMixin[FlowItem]):
|
|
|
316
316
|
|
|
317
317
|
Parameters
|
|
318
318
|
----------
|
|
319
|
-
flow_item: FlowItem
|
|
320
|
-
The flow
|
|
319
|
+
flow_item: FlowItem | str
|
|
320
|
+
The FlowItem or str of the flow id to refresh.
|
|
321
321
|
|
|
322
322
|
Returns
|
|
323
323
|
-------
|
|
324
324
|
JobItem
|
|
325
325
|
The job item that was created to refresh the flow.
|
|
326
326
|
"""
|
|
327
|
-
|
|
327
|
+
flow_id = getattr(flow_item, "id", flow_item)
|
|
328
|
+
url = f"{self.baseurl}/{flow_id}/run"
|
|
328
329
|
empty_req = RequestFactory.Empty.empty_req()
|
|
329
330
|
server_response = self.post_request(url, empty_req)
|
|
330
331
|
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from typing import Protocol, Union, TYPE_CHECKING
|
|
2
|
+
from tableauserverclient.models.oidc_item import SiteOIDCConfiguration
|
|
3
|
+
from tableauserverclient.server.endpoint import Endpoint
|
|
4
|
+
from tableauserverclient.server.request_factory import RequestFactory
|
|
5
|
+
from tableauserverclient.server.endpoint.endpoint import api
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from tableauserverclient.models.site_item import SiteAuthConfiguration
|
|
9
|
+
from tableauserverclient.server.server import Server
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IDPAttributes(Protocol):
|
|
13
|
+
idp_configuration_id: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class IDPProperty(Protocol):
|
|
17
|
+
@property
|
|
18
|
+
def idp_configuration_id(self) -> str: ...
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
HasIdpConfigurationID = Union[str, IDPAttributes]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OIDC(Endpoint):
|
|
25
|
+
def __init__(self, server: "Server") -> None:
|
|
26
|
+
self.parent_srv = server
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def baseurl(self) -> str:
|
|
30
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/site-oidc-configuration"
|
|
31
|
+
|
|
32
|
+
@api(version="3.24")
|
|
33
|
+
def get(self) -> list["SiteAuthConfiguration"]:
|
|
34
|
+
"""
|
|
35
|
+
Get all OpenID Connect (OIDC) configurations for the currently
|
|
36
|
+
authenticated Tableau Cloud site. To get all of the configuration
|
|
37
|
+
details, use the get_by_id method.
|
|
38
|
+
|
|
39
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_identity_pools.htm#AuthnService_ListAuthConfigurations
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
list[SiteAuthConfiguration]
|
|
44
|
+
"""
|
|
45
|
+
return self.parent_srv.sites.list_auth_configurations()
|
|
46
|
+
|
|
47
|
+
@api(version="3.24")
|
|
48
|
+
def get_by_id(self, id: Union[str, HasIdpConfigurationID]) -> SiteOIDCConfiguration:
|
|
49
|
+
"""
|
|
50
|
+
Get details about a specific OpenID Connect (OIDC) configuration on the
|
|
51
|
+
current Tableau Cloud site. Only retrieves configurations for the
|
|
52
|
+
currently authenticated site.
|
|
53
|
+
|
|
54
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_openid_connect.htm#get_openid_connect_configuration
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
id : Union[str, HasID]
|
|
59
|
+
The ID of the OIDC configuration to retrieve. Can be either the
|
|
60
|
+
ID string or an object with an id attribute.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
SiteOIDCConfiguration
|
|
65
|
+
The OIDC configuration for the specified site.
|
|
66
|
+
"""
|
|
67
|
+
target = getattr(id, "idp_configuration_id", id)
|
|
68
|
+
url = f"{self.baseurl}/{target}"
|
|
69
|
+
response = self.get_request(url)
|
|
70
|
+
return SiteOIDCConfiguration.from_response(response.content, self.parent_srv.namespace)
|
|
71
|
+
|
|
72
|
+
@api(version="3.22")
|
|
73
|
+
def create(self, config_item: SiteOIDCConfiguration) -> SiteOIDCConfiguration:
|
|
74
|
+
"""
|
|
75
|
+
Create the OpenID Connect (OIDC) configuration for the currently
|
|
76
|
+
authenticated Tableau Cloud site. The config_item must have the
|
|
77
|
+
following attributes set, others are optional:
|
|
78
|
+
|
|
79
|
+
idp_configuration_name
|
|
80
|
+
client_id
|
|
81
|
+
client_secret
|
|
82
|
+
authorization_endpoint
|
|
83
|
+
token_endpoint
|
|
84
|
+
userinfo_endpoint
|
|
85
|
+
enabled
|
|
86
|
+
jwks_uri
|
|
87
|
+
|
|
88
|
+
The secret in the returned config will be masked.
|
|
89
|
+
|
|
90
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_openid_connect.htm#create_openid_connect_configuration
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
config : SiteOIDCConfiguration
|
|
95
|
+
The OIDC configuration to create.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
SiteOIDCConfiguration
|
|
100
|
+
The created OIDC configuration.
|
|
101
|
+
"""
|
|
102
|
+
url = self.baseurl
|
|
103
|
+
create_req = RequestFactory.OIDC.create_req(config_item)
|
|
104
|
+
response = self.put_request(url, create_req)
|
|
105
|
+
return SiteOIDCConfiguration.from_response(response.content, self.parent_srv.namespace)
|
|
106
|
+
|
|
107
|
+
@api(version="3.24")
|
|
108
|
+
def delete_configuration(self, config: Union[str, HasIdpConfigurationID]) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Delete the OpenID Connect (OIDC) configuration for the currently
|
|
111
|
+
authenticated Tableau Cloud site. The config parameter can be either
|
|
112
|
+
the ID of the configuration or the configuration object itself.
|
|
113
|
+
|
|
114
|
+
**Important**: Before removing the OIDC configuration, make sure that
|
|
115
|
+
users who are set to authenticate with OIDC are set to use a different
|
|
116
|
+
authentication type. Users who are not set with a different
|
|
117
|
+
authentication type before removing the OIDC configuration will not be
|
|
118
|
+
able to sign in to Tableau Cloud.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_openid_connect.htm#remove_openid_connect_configuration
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
config : Union[str, HasID]
|
|
126
|
+
The OIDC configuration to delete. Can be either the ID of the
|
|
127
|
+
configuration or the configuration object itself.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
target = getattr(config, "idp_configuration_id", config)
|
|
131
|
+
|
|
132
|
+
url = f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/disable-site-oidc-configuration?idpConfigurationId={target}"
|
|
133
|
+
_ = self.put_request(url)
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
@api(version="3.22")
|
|
137
|
+
def update(self, config: SiteOIDCConfiguration) -> SiteOIDCConfiguration:
|
|
138
|
+
"""
|
|
139
|
+
Update the Tableau Cloud site's OpenID Connect (OIDC) configuration. The
|
|
140
|
+
secret in the returned config will be masked.
|
|
141
|
+
|
|
142
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_openid_connect.htm#update_openid_connect_configuration
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
config : SiteOIDCConfiguration
|
|
147
|
+
The OIDC configuration to update. Must have the id attribute set.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
SiteOIDCConfiguration
|
|
152
|
+
The updated OIDC configuration.
|
|
153
|
+
"""
|
|
154
|
+
url = f"{self.baseurl}/{config.idp_configuration_id}"
|
|
155
|
+
update_req = RequestFactory.OIDC.update_req(config)
|
|
156
|
+
response = self.put_request(url, update_req)
|
|
157
|
+
return SiteOIDCConfiguration.from_response(response.content, self.parent_srv.namespace)
|
|
@@ -89,6 +89,18 @@ class Projects(QuerysetEndpoint[ProjectItem]):
|
|
|
89
89
|
self.delete_request(url)
|
|
90
90
|
logger.info(f"Deleted single project (ID: {project_id})")
|
|
91
91
|
|
|
92
|
+
@api(version="2.0")
|
|
93
|
+
def get_by_id(self, project_id: str) -> ProjectItem:
|
|
94
|
+
"""
|
|
95
|
+
Fetch a project by ID. This is a convenience method making up for a gap in the server API.
|
|
96
|
+
It uses the same endpoint as the update method, but without the ability to update the project.
|
|
97
|
+
"""
|
|
98
|
+
if not project_id:
|
|
99
|
+
error = "Project ID undefined."
|
|
100
|
+
raise ValueError(error)
|
|
101
|
+
project = ProjectItem(id=project_id)
|
|
102
|
+
return self.update(project, samples=False)
|
|
103
|
+
|
|
92
104
|
@api(version="2.0")
|
|
93
105
|
def update(self, project_item: ProjectItem, samples: bool = False) -> ProjectItem:
|
|
94
106
|
"""
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
import copy
|
|
3
|
+
import logging
|
|
4
|
+
import warnings
|
|
5
|
+
from collections import namedtuple
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, overload
|
|
7
|
+
|
|
8
|
+
from .endpoint import Endpoint, api, parameter_added_in
|
|
9
|
+
from .exceptions import MissingRequiredFieldError
|
|
10
|
+
from tableauserverclient.server import RequestFactory
|
|
11
|
+
from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem, ExtractItem
|
|
12
|
+
from tableauserverclient.models.schedule_item import parse_batch_schedule_state
|
|
13
|
+
|
|
14
|
+
from tableauserverclient.helpers.logging import logger
|
|
15
|
+
|
|
16
|
+
AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created"))
|
|
17
|
+
OK = AddResponse(result=True, error=None, warnings=None, task_created=None)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from ..request_options import RequestOptions
|
|
21
|
+
from ...models import DatasourceItem, WorkbookItem, FlowItem
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Schedules(Endpoint):
|
|
25
|
+
@property
|
|
26
|
+
def baseurl(self) -> str:
|
|
27
|
+
return f"{self.parent_srv.baseurl}/schedules"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def siteurl(self) -> str:
|
|
31
|
+
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/schedules"
|
|
32
|
+
|
|
33
|
+
@api(version="2.3")
|
|
34
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[ScheduleItem], PaginationItem]:
|
|
35
|
+
"""
|
|
36
|
+
Returns a list of flows, extract, and subscription server schedules on
|
|
37
|
+
Tableau Server. For each schedule, the API returns name, frequency,
|
|
38
|
+
priority, and other information.
|
|
39
|
+
|
|
40
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_schedules
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
req_options : Optional[RequestOptions]
|
|
45
|
+
Filtering and paginating options for request.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
Tuple[List[ScheduleItem], PaginationItem]
|
|
50
|
+
A tuple of list of ScheduleItem and PaginationItem
|
|
51
|
+
"""
|
|
52
|
+
logger.info("Querying all schedules")
|
|
53
|
+
url = self.baseurl
|
|
54
|
+
server_response = self.get_request(url, req_options)
|
|
55
|
+
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
56
|
+
all_schedule_items = ScheduleItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
57
|
+
return all_schedule_items, pagination_item
|
|
58
|
+
|
|
59
|
+
@api(version="3.8")
|
|
60
|
+
def get_by_id(self, schedule_id: str) -> ScheduleItem:
|
|
61
|
+
"""
|
|
62
|
+
Returns detailed information about the specified server schedule.
|
|
63
|
+
|
|
64
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#get-schedule
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
schedule_id : str
|
|
69
|
+
The ID of the schedule to get information for.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
ScheduleItem
|
|
74
|
+
The schedule item that corresponds to the given ID.
|
|
75
|
+
"""
|
|
76
|
+
if not schedule_id:
|
|
77
|
+
error = "No Schedule ID provided"
|
|
78
|
+
raise ValueError(error)
|
|
79
|
+
logger.info(f"Querying a single schedule by id ({schedule_id})")
|
|
80
|
+
url = f"{self.baseurl}/{schedule_id}"
|
|
81
|
+
server_response = self.get_request(url)
|
|
82
|
+
return ScheduleItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
83
|
+
|
|
84
|
+
@api(version="2.3")
|
|
85
|
+
def delete(self, schedule_id: str) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Deletes the specified schedule from the server.
|
|
88
|
+
|
|
89
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#delete_schedule
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
schedule_id : str
|
|
94
|
+
The ID of the schedule to delete.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
None
|
|
99
|
+
"""
|
|
100
|
+
if not schedule_id:
|
|
101
|
+
error = "Schedule ID undefined"
|
|
102
|
+
raise ValueError(error)
|
|
103
|
+
url = f"{self.baseurl}/{schedule_id}"
|
|
104
|
+
self.delete_request(url)
|
|
105
|
+
logger.info(f"Deleted single schedule (ID: {schedule_id})")
|
|
106
|
+
|
|
107
|
+
@api(version="2.3")
|
|
108
|
+
def update(self, schedule_item: ScheduleItem) -> ScheduleItem:
|
|
109
|
+
"""
|
|
110
|
+
Modifies settings for the specified server schedule, including the name,
|
|
111
|
+
priority, and frequency details on Tableau Server. For Tableau Cloud,
|
|
112
|
+
see the tasks and subscritpions API.
|
|
113
|
+
|
|
114
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#update_schedule
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
schedule_item : ScheduleItem
|
|
119
|
+
The schedule item to update.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
ScheduleItem
|
|
124
|
+
The updated schedule item.
|
|
125
|
+
"""
|
|
126
|
+
if not schedule_item.id:
|
|
127
|
+
error = "Schedule item missing ID."
|
|
128
|
+
raise MissingRequiredFieldError(error)
|
|
129
|
+
|
|
130
|
+
url = f"{self.baseurl}/{schedule_item.id}"
|
|
131
|
+
update_req = RequestFactory.Schedule.update_req(schedule_item)
|
|
132
|
+
server_response = self.put_request(url, update_req)
|
|
133
|
+
logger.info(f"Updated schedule item (ID: {schedule_item.id})")
|
|
134
|
+
updated_schedule = copy.copy(schedule_item)
|
|
135
|
+
return updated_schedule._parse_common_tags(server_response.content, self.parent_srv.namespace)
|
|
136
|
+
|
|
137
|
+
@api(version="2.3")
|
|
138
|
+
def create(self, schedule_item: ScheduleItem) -> ScheduleItem:
|
|
139
|
+
"""
|
|
140
|
+
Creates a new server schedule on Tableau Server. For Tableau Cloud, use
|
|
141
|
+
the tasks and subscriptions API.
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
schedule_item : ScheduleItem
|
|
146
|
+
The schedule item to create.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
ScheduleItem
|
|
151
|
+
The newly created schedule.
|
|
152
|
+
"""
|
|
153
|
+
if schedule_item.interval_item is None:
|
|
154
|
+
error = "Interval item must be defined."
|
|
155
|
+
raise MissingRequiredFieldError(error)
|
|
156
|
+
|
|
157
|
+
url = self.baseurl
|
|
158
|
+
create_req = RequestFactory.Schedule.create_req(schedule_item)
|
|
159
|
+
server_response = self.post_request(url, create_req)
|
|
160
|
+
new_schedule = ScheduleItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
161
|
+
logger.info(f"Created new schedule (ID: {new_schedule.id})")
|
|
162
|
+
return new_schedule
|
|
163
|
+
|
|
164
|
+
@api(version="2.8")
|
|
165
|
+
@parameter_added_in(flow="3.3")
|
|
166
|
+
def add_to_schedule(
|
|
167
|
+
self,
|
|
168
|
+
schedule_id: str,
|
|
169
|
+
workbook: Optional["WorkbookItem"] = None,
|
|
170
|
+
datasource: Optional["DatasourceItem"] = None,
|
|
171
|
+
flow: Optional["FlowItem"] = None,
|
|
172
|
+
task_type: Optional[str] = None,
|
|
173
|
+
) -> list[AddResponse]:
|
|
174
|
+
"""
|
|
175
|
+
Adds a workbook, datasource, or flow to a schedule on Tableau Server.
|
|
176
|
+
Only one of workbook, datasource, or flow can be passed in at a time.
|
|
177
|
+
|
|
178
|
+
The task type is optional and will default to ExtractRefresh if a
|
|
179
|
+
workbook or datasource is passed in, and RunFlow if a flow is passed in.
|
|
180
|
+
|
|
181
|
+
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
|
|
182
|
+
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
|
|
183
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_flow.htm#add_flow_task_to_schedule
|
|
184
|
+
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
schedule_id : str
|
|
188
|
+
The ID of the schedule to add the item to.
|
|
189
|
+
|
|
190
|
+
workbook : Optional[WorkbookItem]
|
|
191
|
+
The workbook to add to the schedule.
|
|
192
|
+
|
|
193
|
+
datasource : Optional[DatasourceItem]
|
|
194
|
+
The datasource to add to the schedule.
|
|
195
|
+
|
|
196
|
+
flow : Optional[FlowItem]
|
|
197
|
+
The flow to add to the schedule.
|
|
198
|
+
|
|
199
|
+
task_type : Optional[str]
|
|
200
|
+
The type of task to add to the schedule. If not provided, it will
|
|
201
|
+
default to ExtractRefresh if a workbook or datasource is passed in,
|
|
202
|
+
and RunFlow if a flow is passed in.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
list[AddResponse]
|
|
207
|
+
A list of responses for each item added to the schedule.
|
|
208
|
+
"""
|
|
209
|
+
# There doesn't seem to be a good reason to allow one item of each type?
|
|
210
|
+
if workbook and datasource:
|
|
211
|
+
warnings.warn("Passing in multiple items for add_to_schedule will be deprecated", PendingDeprecationWarning)
|
|
212
|
+
items: list[
|
|
213
|
+
tuple[str, Union[WorkbookItem, FlowItem, DatasourceItem], str, Callable[[Optional[str], str], bytes], str]
|
|
214
|
+
] = []
|
|
215
|
+
|
|
216
|
+
if workbook is not None:
|
|
217
|
+
if not task_type:
|
|
218
|
+
task_type = TaskItem.Type.ExtractRefresh
|
|
219
|
+
items.append((schedule_id, workbook, "workbook", RequestFactory.Schedule.add_workbook_req, task_type))
|
|
220
|
+
if datasource is not None:
|
|
221
|
+
if not task_type:
|
|
222
|
+
task_type = TaskItem.Type.ExtractRefresh
|
|
223
|
+
items.append((schedule_id, datasource, "datasource", RequestFactory.Schedule.add_datasource_req, task_type))
|
|
224
|
+
if flow is not None and not (workbook or datasource): # Cannot pass a flow with any other type
|
|
225
|
+
if not task_type:
|
|
226
|
+
task_type = TaskItem.Type.RunFlow
|
|
227
|
+
items.append(
|
|
228
|
+
(schedule_id, flow, "flow", RequestFactory.Schedule.add_flow_req, task_type)
|
|
229
|
+
) # type:ignore[arg-type]
|
|
230
|
+
|
|
231
|
+
results = (self._add_to(*x) for x in items)
|
|
232
|
+
return [x for x in results if not x.result]
|
|
233
|
+
|
|
234
|
+
def _add_to(
|
|
235
|
+
self,
|
|
236
|
+
schedule_id,
|
|
237
|
+
resource: Union["DatasourceItem", "WorkbookItem", "FlowItem"],
|
|
238
|
+
type_: str,
|
|
239
|
+
req_factory: Callable[
|
|
240
|
+
[
|
|
241
|
+
str,
|
|
242
|
+
str,
|
|
243
|
+
],
|
|
244
|
+
bytes,
|
|
245
|
+
],
|
|
246
|
+
item_task_type,
|
|
247
|
+
) -> AddResponse:
|
|
248
|
+
id_ = resource.id
|
|
249
|
+
url = f"{self.siteurl}/{schedule_id}/{type_}s"
|
|
250
|
+
add_req = req_factory(id_, task_type=item_task_type) # type: ignore[call-arg, arg-type]
|
|
251
|
+
response = self.put_request(url, add_req)
|
|
252
|
+
|
|
253
|
+
error, warnings, task_created = ScheduleItem.parse_add_to_schedule_response(response, self.parent_srv.namespace)
|
|
254
|
+
if task_created:
|
|
255
|
+
logger.info(f"Added {type_} to {id_} to schedule {schedule_id}")
|
|
256
|
+
|
|
257
|
+
if error is not None or warnings is not None:
|
|
258
|
+
return AddResponse(
|
|
259
|
+
result=False,
|
|
260
|
+
error=error,
|
|
261
|
+
warnings=warnings,
|
|
262
|
+
task_created=task_created,
|
|
263
|
+
)
|
|
264
|
+
else:
|
|
265
|
+
return OK
|
|
266
|
+
|
|
267
|
+
@api(version="2.3")
|
|
268
|
+
def get_extract_refresh_tasks(
|
|
269
|
+
self, schedule_id: str, req_options: Optional["RequestOptions"] = None
|
|
270
|
+
) -> tuple[list["ExtractItem"], "PaginationItem"]:
|
|
271
|
+
"""Get all extract refresh tasks for the specified schedule."""
|
|
272
|
+
if not schedule_id:
|
|
273
|
+
error = "Schedule ID undefined"
|
|
274
|
+
raise ValueError(error)
|
|
275
|
+
|
|
276
|
+
logger.info(f"Querying extract refresh tasks for schedule (ID: {schedule_id})")
|
|
277
|
+
url = f"{self.siteurl}/{schedule_id}/extracts"
|
|
278
|
+
server_response = self.get_request(url, req_options)
|
|
279
|
+
|
|
280
|
+
pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
281
|
+
extract_items = ExtractItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
282
|
+
|
|
283
|
+
return extract_items, pagination_item
|
|
284
|
+
|
|
285
|
+
@overload
|
|
286
|
+
def batch_update_state(
|
|
287
|
+
self,
|
|
288
|
+
schedules: Iterable[ScheduleItem | str],
|
|
289
|
+
state: Literal["active", "suspended"],
|
|
290
|
+
update_all: Literal[False] = False,
|
|
291
|
+
) -> list[str]: ...
|
|
292
|
+
|
|
293
|
+
@overload
|
|
294
|
+
def batch_update_state(
|
|
295
|
+
self, schedules: Any, state: Literal["active", "suspended"], update_all: Literal[True]
|
|
296
|
+
) -> list[str]: ...
|
|
297
|
+
|
|
298
|
+
@api(version="3.27")
|
|
299
|
+
def batch_update_state(self, schedules, state, update_all=False) -> list[str]:
|
|
300
|
+
"""
|
|
301
|
+
Batch update the status of one or more scheudles. If update_all is set,
|
|
302
|
+
all schedules on the Tableau Server are affected.
|
|
303
|
+
|
|
304
|
+
Parameters
|
|
305
|
+
----------
|
|
306
|
+
schedules: Iterable[ScheudleItem | str] | Any
|
|
307
|
+
The schedules to be updated. If update_all=True, this is ignored.
|
|
308
|
+
|
|
309
|
+
state: Literal["active", "suspended"]
|
|
310
|
+
The state of the schedules, whether active or suspended.
|
|
311
|
+
|
|
312
|
+
update_all: bool
|
|
313
|
+
Whether or not to apply the status to all schedules.
|
|
314
|
+
|
|
315
|
+
Returns
|
|
316
|
+
-------
|
|
317
|
+
List[str]
|
|
318
|
+
The IDs of the affected schedules.
|
|
319
|
+
"""
|
|
320
|
+
params = {"state": state}
|
|
321
|
+
if update_all:
|
|
322
|
+
params["updateAll"] = "true"
|
|
323
|
+
payload = RequestFactory.Empty.empty_req()
|
|
324
|
+
else:
|
|
325
|
+
payload = RequestFactory.Schedule.batch_update_state(schedules)
|
|
326
|
+
|
|
327
|
+
response = self.put_request(self.baseurl, payload, parameters={"params": params})
|
|
328
|
+
return parse_batch_schedule_state(response, self.parent_srv.namespace)
|
|
@@ -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
|