tableauserverclient 0.38__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/models → models}/__init__.py +9 -0
- 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 +3 -1
- models/extensions_item.py +186 -0
- {tableauserverclient/models → models}/favorites_item.py +21 -8
- {tableauserverclient/models → models}/flow_item.py +1 -1
- {tableauserverclient/models → models}/group_item.py +7 -1
- {tableauserverclient/models → models}/groupset_item.py +14 -0
- {tableauserverclient/models → models}/interval_item.py +2 -1
- models/oidc_item.py +82 -0
- {tableauserverclient/models → models}/permissions_item.py +2 -0
- {tableauserverclient/models → models}/project_item.py +3 -2
- {tableauserverclient/models → models}/property_decorators.py +2 -2
- {tableauserverclient/models → models}/reference_item.py +12 -6
- {tableauserverclient/models → models}/schedule_item.py +10 -1
- {tableauserverclient/models → models}/site_item.py +26 -0
- {tableauserverclient/models → models}/tableau_auth.py +13 -6
- {tableauserverclient/models → models}/user_item.py +10 -3
- {tableauserverclient/models → models}/workbook_item.py +2 -2
- {tableauserverclient/server → server}/endpoint/__init__.py +4 -0
- {tableauserverclient/server → server}/endpoint/datasources_endpoint.py +152 -22
- 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
- {tableauserverclient/server → server}/endpoint/schedules_endpoint.py +48 -1
- {tableauserverclient/server → server}/endpoint/users_endpoint.py +274 -5
- {tableauserverclient/server → server}/endpoint/views_endpoint.py +23 -0
- {tableauserverclient/server → server}/endpoint/workbooks_endpoint.py +124 -9
- {tableauserverclient/server → server}/request_factory.py +281 -2
- {tableauserverclient/server → server}/request_options.py +12 -2
- {tableauserverclient/server → server}/server.py +4 -0
- {tableauserverclient-0.38.dist-info → tableauserverclient-0.39.dist-info}/METADATA +5 -26
- tableauserverclient-0.39.dist-info/RECORD +107 -0
- {tableauserverclient-0.38.dist-info → tableauserverclient-0.39.dist-info}/WHEEL +1 -1
- tableauserverclient-0.39.dist-info/top_level.txt +4 -0
- tableauserverclient/__init__.py +0 -145
- 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-0.38.dist-info/RECORD +0 -108
- tableauserverclient-0.38.dist-info/licenses/LICENSE.versioneer +0 -7
- tableauserverclient-0.38.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/helpers → helpers}/strings.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}/extract_item.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}/location_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}/table_item.py +0 -0
- {tableauserverclient/models → models}/tableau_types.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}/view_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/databases_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/default_permissions_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/dqw_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/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/sites_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/subscriptions_endpoint.py +0 -0
- {tableauserverclient/server → server}/endpoint/tables_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}/query.py +0 -0
- {tableauserverclient/server → server}/sort.py +0 -0
- {tableauserverclient-0.38.dist-info → tableauserverclient-0.39.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,8 +6,8 @@ import os
|
|
|
6
6
|
|
|
7
7
|
from contextlib import closing
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Literal, Optional, TYPE_CHECKING, Union, overload
|
|
10
|
-
from collections.abc import Iterable,
|
|
9
|
+
from typing import Literal, Optional, TYPE_CHECKING, TypedDict, TypeVar, Union, overload
|
|
10
|
+
from collections.abc import Iterable, Sequence
|
|
11
11
|
|
|
12
12
|
from tableauserverclient.helpers.headers import fix_filename
|
|
13
13
|
from tableauserverclient.models.dqw_item import DQWItem
|
|
@@ -50,13 +50,50 @@ FilePath = Union[str, os.PathLike]
|
|
|
50
50
|
FileObject = Union[io.BufferedReader, io.BytesIO]
|
|
51
51
|
PathOrFile = Union[FilePath, FileObject]
|
|
52
52
|
|
|
53
|
-
FilePath = Union[str, os.PathLike]
|
|
54
53
|
FileObjectR = Union[io.BufferedReader, io.BytesIO]
|
|
55
54
|
FileObjectW = Union[io.BufferedWriter, io.BytesIO]
|
|
56
55
|
PathOrFileR = Union[FilePath, FileObjectR]
|
|
57
56
|
PathOrFileW = Union[FilePath, FileObjectW]
|
|
58
57
|
|
|
59
58
|
|
|
59
|
+
HyperActionCondition = TypedDict(
|
|
60
|
+
"HyperActionCondition",
|
|
61
|
+
{
|
|
62
|
+
"op": str,
|
|
63
|
+
"target-col": str,
|
|
64
|
+
"source-col": str,
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
HyperActionRow = TypedDict(
|
|
69
|
+
"HyperActionRow",
|
|
70
|
+
{
|
|
71
|
+
"action": Literal[
|
|
72
|
+
"update",
|
|
73
|
+
"upsert",
|
|
74
|
+
"delete",
|
|
75
|
+
],
|
|
76
|
+
"source-table": str,
|
|
77
|
+
"target-table": str,
|
|
78
|
+
"condition": HyperActionCondition,
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
HyperActionTable = TypedDict(
|
|
83
|
+
"HyperActionTable",
|
|
84
|
+
{
|
|
85
|
+
"action": Literal[
|
|
86
|
+
"insert",
|
|
87
|
+
"replace",
|
|
88
|
+
],
|
|
89
|
+
"source-table": str,
|
|
90
|
+
"target-table": str,
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
HyperAction = Union[HyperActionTable, HyperActionRow]
|
|
95
|
+
|
|
96
|
+
|
|
60
97
|
class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]):
|
|
61
98
|
def __init__(self, parent_srv: "Server") -> None:
|
|
62
99
|
super().__init__(parent_srv)
|
|
@@ -191,16 +228,34 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
191
228
|
self.delete_request(url)
|
|
192
229
|
logger.info(f"Deleted single datasource (ID: {datasource_id})")
|
|
193
230
|
|
|
231
|
+
T = TypeVar("T", bound=FileObjectW)
|
|
232
|
+
|
|
233
|
+
@overload
|
|
234
|
+
def download(
|
|
235
|
+
self,
|
|
236
|
+
datasource_id: str,
|
|
237
|
+
filepath: T,
|
|
238
|
+
include_extract: bool = True,
|
|
239
|
+
) -> T: ...
|
|
240
|
+
|
|
241
|
+
@overload
|
|
242
|
+
def download(
|
|
243
|
+
self,
|
|
244
|
+
datasource_id: str,
|
|
245
|
+
filepath: Optional[FilePath] = None,
|
|
246
|
+
include_extract: bool = True,
|
|
247
|
+
) -> str: ...
|
|
248
|
+
|
|
194
249
|
# Download 1 datasource by id
|
|
195
250
|
@api(version="2.0")
|
|
196
251
|
@parameter_added_in(no_extract="2.5")
|
|
197
252
|
@parameter_added_in(include_extract="2.5")
|
|
198
253
|
def download(
|
|
199
254
|
self,
|
|
200
|
-
datasource_id
|
|
201
|
-
filepath
|
|
202
|
-
include_extract
|
|
203
|
-
)
|
|
255
|
+
datasource_id,
|
|
256
|
+
filepath=None,
|
|
257
|
+
include_extract=True,
|
|
258
|
+
):
|
|
204
259
|
"""
|
|
205
260
|
Downloads the specified data source from a site. The data source is
|
|
206
261
|
downloaded as a .tdsx file.
|
|
@@ -319,8 +374,63 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
319
374
|
logger.info(f"Updated datasource item (ID: {datasource_item.id} & connection item {connection_item.id}")
|
|
320
375
|
return connection
|
|
321
376
|
|
|
377
|
+
@api(version="3.26")
|
|
378
|
+
def update_connections(
|
|
379
|
+
self,
|
|
380
|
+
datasource_item: DatasourceItem,
|
|
381
|
+
connection_luids: Iterable[str],
|
|
382
|
+
authentication_type: str,
|
|
383
|
+
username: Optional[str] = None,
|
|
384
|
+
password: Optional[str] = None,
|
|
385
|
+
embed_password: Optional[bool] = None,
|
|
386
|
+
) -> list[ConnectionItem]:
|
|
387
|
+
"""
|
|
388
|
+
Bulk updates one or more datasource connections by LUID.
|
|
389
|
+
|
|
390
|
+
Parameters
|
|
391
|
+
----------
|
|
392
|
+
datasource_item : DatasourceItem
|
|
393
|
+
The datasource item containing the connections.
|
|
394
|
+
|
|
395
|
+
connection_luids : Iterable of str
|
|
396
|
+
The connection LUIDs to update.
|
|
397
|
+
|
|
398
|
+
authentication_type : str
|
|
399
|
+
The authentication type to use (e.g., 'auth-keypair').
|
|
400
|
+
|
|
401
|
+
username : str, optional
|
|
402
|
+
The username to set.
|
|
403
|
+
|
|
404
|
+
password : str, optional
|
|
405
|
+
The password or secret to set.
|
|
406
|
+
|
|
407
|
+
embed_password : bool, optional
|
|
408
|
+
Whether to embed the password.
|
|
409
|
+
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
Iterable of str
|
|
413
|
+
The connection LUIDs that were updated.
|
|
414
|
+
"""
|
|
415
|
+
|
|
416
|
+
url = f"{self.baseurl}/{datasource_item.id}/connections"
|
|
417
|
+
|
|
418
|
+
request_body = RequestFactory.Datasource.update_connections_req(
|
|
419
|
+
connection_luids=connection_luids,
|
|
420
|
+
authentication_type=authentication_type,
|
|
421
|
+
username=username,
|
|
422
|
+
password=password,
|
|
423
|
+
embed_password=embed_password,
|
|
424
|
+
)
|
|
425
|
+
server_response = self.put_request(url, request_body)
|
|
426
|
+
connection_items = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
427
|
+
updated_ids: list[str] = [conn.id for conn in connection_items]
|
|
428
|
+
|
|
429
|
+
logger.info(f"Updated connections for datasource {datasource_item.id}: {', '.join(updated_ids)}")
|
|
430
|
+
return connection_items
|
|
431
|
+
|
|
322
432
|
@api(version="2.8")
|
|
323
|
-
def refresh(self, datasource_item: DatasourceItem, incremental: bool = False) -> JobItem:
|
|
433
|
+
def refresh(self, datasource_item: Union[DatasourceItem, str], incremental: bool = False) -> JobItem:
|
|
324
434
|
"""
|
|
325
435
|
Refreshes the extract of an existing workbook.
|
|
326
436
|
|
|
@@ -328,8 +438,8 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
328
438
|
|
|
329
439
|
Parameters
|
|
330
440
|
----------
|
|
331
|
-
workbook_item :
|
|
332
|
-
The
|
|
441
|
+
workbook_item : DatasourceItem | str
|
|
442
|
+
The datasource item or datasource ID.
|
|
333
443
|
incremental: bool
|
|
334
444
|
Whether to do a full refresh or incremental refresh of the extract data
|
|
335
445
|
|
|
@@ -424,13 +534,13 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
424
534
|
@parameter_added_in(as_job="3.0")
|
|
425
535
|
def publish(
|
|
426
536
|
self,
|
|
427
|
-
datasource_item
|
|
428
|
-
file
|
|
429
|
-
mode
|
|
430
|
-
connection_credentials
|
|
431
|
-
connections
|
|
432
|
-
as_job
|
|
433
|
-
)
|
|
537
|
+
datasource_item,
|
|
538
|
+
file,
|
|
539
|
+
mode,
|
|
540
|
+
connection_credentials=None,
|
|
541
|
+
connections=None,
|
|
542
|
+
as_job=False,
|
|
543
|
+
):
|
|
434
544
|
"""
|
|
435
545
|
Publishes a data source to a server, or appends data to an existing
|
|
436
546
|
data source.
|
|
@@ -576,7 +686,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
576
686
|
datasource_or_connection_item: Union[DatasourceItem, ConnectionItem, str],
|
|
577
687
|
*,
|
|
578
688
|
request_id: str,
|
|
579
|
-
actions: Sequence[
|
|
689
|
+
actions: Sequence[HyperAction],
|
|
580
690
|
payload: Optional[FilePath] = None,
|
|
581
691
|
) -> JobItem:
|
|
582
692
|
"""
|
|
@@ -843,15 +953,35 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
843
953
|
revisions = RevisionItem.from_response(server_response.content, self.parent_srv.namespace, datasource_item)
|
|
844
954
|
return revisions
|
|
845
955
|
|
|
846
|
-
|
|
847
|
-
|
|
956
|
+
T = TypeVar("T", bound=FileObjectW)
|
|
957
|
+
|
|
958
|
+
@overload
|
|
848
959
|
def download_revision(
|
|
849
960
|
self,
|
|
850
961
|
datasource_id: str,
|
|
851
962
|
revision_number: Optional[str],
|
|
852
|
-
filepath:
|
|
963
|
+
filepath: T,
|
|
853
964
|
include_extract: bool = True,
|
|
854
|
-
) ->
|
|
965
|
+
) -> T: ...
|
|
966
|
+
|
|
967
|
+
@overload
|
|
968
|
+
def download_revision(
|
|
969
|
+
self,
|
|
970
|
+
datasource_id: str,
|
|
971
|
+
revision_number: Optional[str],
|
|
972
|
+
filepath: Optional[FilePath] = None,
|
|
973
|
+
include_extract: bool = True,
|
|
974
|
+
) -> str: ...
|
|
975
|
+
|
|
976
|
+
# Download 1 datasource revision by revision number
|
|
977
|
+
@api(version="2.3")
|
|
978
|
+
def download_revision(
|
|
979
|
+
self,
|
|
980
|
+
datasource_id,
|
|
981
|
+
revision_number,
|
|
982
|
+
filepath=None,
|
|
983
|
+
include_extract=True,
|
|
984
|
+
):
|
|
855
985
|
"""
|
|
856
986
|
Downloads a specific version of a data source prior to the current one
|
|
857
987
|
in .tdsx format. To download the current version of a data source set
|
|
@@ -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
|
"""
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
1
2
|
import copy
|
|
2
3
|
import logging
|
|
3
4
|
import warnings
|
|
4
5
|
from collections import namedtuple
|
|
5
|
-
from typing import TYPE_CHECKING, Callable, Optional, Union
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, overload
|
|
6
7
|
|
|
7
8
|
from .endpoint import Endpoint, api, parameter_added_in
|
|
8
9
|
from .exceptions import MissingRequiredFieldError
|
|
9
10
|
from tableauserverclient.server import RequestFactory
|
|
10
11
|
from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem, ExtractItem
|
|
12
|
+
from tableauserverclient.models.schedule_item import parse_batch_schedule_state
|
|
11
13
|
|
|
12
14
|
from tableauserverclient.helpers.logging import logger
|
|
13
15
|
|
|
@@ -279,3 +281,48 @@ class Schedules(Endpoint):
|
|
|
279
281
|
extract_items = ExtractItem.from_response(server_response.content, self.parent_srv.namespace)
|
|
280
282
|
|
|
281
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)
|