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
models/oidc_item.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from defusedxml.ElementTree import fromstring
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SiteOIDCConfiguration:
|
|
6
|
+
def __init__(self) -> None:
|
|
7
|
+
self.enabled: bool = False
|
|
8
|
+
self.test_login_url: Optional[str] = None
|
|
9
|
+
self.known_provider_alias: Optional[str] = None
|
|
10
|
+
self.allow_embedded_authentication: bool = False
|
|
11
|
+
self.use_full_name: bool = False
|
|
12
|
+
self.idp_configuration_name: Optional[str] = None
|
|
13
|
+
self.idp_configuration_id: Optional[str] = None
|
|
14
|
+
self.client_id: Optional[str] = None
|
|
15
|
+
self.client_secret: Optional[str] = None
|
|
16
|
+
self.authorization_endpoint: Optional[str] = None
|
|
17
|
+
self.token_endpoint: Optional[str] = None
|
|
18
|
+
self.userinfo_endpoint: Optional[str] = None
|
|
19
|
+
self.jwks_uri: Optional[str] = None
|
|
20
|
+
self.end_session_endpoint: Optional[str] = None
|
|
21
|
+
self.custom_scope: Optional[str] = None
|
|
22
|
+
self.essential_acr_values: Optional[str] = None
|
|
23
|
+
self.email_mapping: Optional[str] = None
|
|
24
|
+
self.first_name_mapping: Optional[str] = None
|
|
25
|
+
self.last_name_mapping: Optional[str] = None
|
|
26
|
+
self.full_name_mapping: Optional[str] = None
|
|
27
|
+
self.prompt: Optional[str] = None
|
|
28
|
+
self.client_authentication: Optional[str] = None
|
|
29
|
+
self.voluntary_acr_values: Optional[str] = None
|
|
30
|
+
|
|
31
|
+
def __str__(self) -> str:
|
|
32
|
+
return (
|
|
33
|
+
f"{self.__class__.__qualname__}(enabled={self.enabled}, "
|
|
34
|
+
f"test_login_url={self.test_login_url}, "
|
|
35
|
+
f"idp_configuration_name={self.idp_configuration_name}, "
|
|
36
|
+
f"idp_configuration_id={self.idp_configuration_id}, "
|
|
37
|
+
f"client_id={self.client_id})"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def __repr__(self) -> str:
|
|
41
|
+
return f"<{str(self)}>"
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def from_response(cls, raw_xml: bytes, ns) -> "SiteOIDCConfiguration":
|
|
45
|
+
"""
|
|
46
|
+
Parses the raw XML bytes and returns a SiteOIDCConfiguration object.
|
|
47
|
+
"""
|
|
48
|
+
root = fromstring(raw_xml)
|
|
49
|
+
elem = root.find("t:siteOIDCConfiguration", namespaces=ns)
|
|
50
|
+
if elem is None:
|
|
51
|
+
raise ValueError("No siteOIDCConfiguration element found in the XML.")
|
|
52
|
+
config = cls()
|
|
53
|
+
|
|
54
|
+
config.enabled = str_to_bool(elem.get("enabled", "false"))
|
|
55
|
+
config.test_login_url = elem.get("testLoginUrl")
|
|
56
|
+
config.known_provider_alias = elem.get("knownProviderAlias")
|
|
57
|
+
config.allow_embedded_authentication = str_to_bool(elem.get("allowEmbeddedAuthentication", "false").lower())
|
|
58
|
+
config.use_full_name = str_to_bool(elem.get("useFullName", "false").lower())
|
|
59
|
+
config.idp_configuration_name = elem.get("idpConfigurationName")
|
|
60
|
+
config.idp_configuration_id = elem.get("idpConfigurationId")
|
|
61
|
+
config.client_id = elem.get("clientId")
|
|
62
|
+
config.client_secret = elem.get("clientSecret")
|
|
63
|
+
config.authorization_endpoint = elem.get("authorizationEndpoint")
|
|
64
|
+
config.token_endpoint = elem.get("tokenEndpoint")
|
|
65
|
+
config.userinfo_endpoint = elem.get("userinfoEndpoint")
|
|
66
|
+
config.jwks_uri = elem.get("jwksUri")
|
|
67
|
+
config.end_session_endpoint = elem.get("endSessionEndpoint")
|
|
68
|
+
config.custom_scope = elem.get("customScope")
|
|
69
|
+
config.essential_acr_values = elem.get("essentialAcrValues")
|
|
70
|
+
config.email_mapping = elem.get("emailMapping")
|
|
71
|
+
config.first_name_mapping = elem.get("firstNameMapping")
|
|
72
|
+
config.last_name_mapping = elem.get("lastNameMapping")
|
|
73
|
+
config.full_name_mapping = elem.get("fullNameMapping")
|
|
74
|
+
config.prompt = elem.get("prompt")
|
|
75
|
+
config.client_authentication = elem.get("clientAuthentication")
|
|
76
|
+
config.voluntary_acr_values = elem.get("voluntaryAcrValues")
|
|
77
|
+
|
|
78
|
+
return config
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def str_to_bool(s: str) -> bool:
|
|
82
|
+
return s == "true"
|
|
@@ -43,6 +43,8 @@ class Permission:
|
|
|
43
43
|
CreateRefreshMetrics = "CreateRefreshMetrics"
|
|
44
44
|
SaveAs = "SaveAs"
|
|
45
45
|
PulseMetricDefine = "PulseMetricDefine"
|
|
46
|
+
ExtractRefresh = "ExtractRefresh"
|
|
47
|
+
WebAuthoringForFlows = "WebAuthoringForFlows"
|
|
46
48
|
|
|
47
49
|
def __repr__(self):
|
|
48
50
|
return "<Enum Capability: AddComment | ChangeHierarchy | ChangePermission ... (17 more) >"
|
|
@@ -86,9 +86,10 @@ class ProjectItem:
|
|
|
86
86
|
content_permissions: Optional[str] = None,
|
|
87
87
|
parent_id: Optional[str] = None,
|
|
88
88
|
samples: Optional[bool] = None,
|
|
89
|
+
id: Optional[str] = None,
|
|
89
90
|
) -> None:
|
|
90
91
|
self._content_permissions = None
|
|
91
|
-
self._id: Optional[str] =
|
|
92
|
+
self._id: Optional[str] = id
|
|
92
93
|
self.description: Optional[str] = description
|
|
93
94
|
self.name: str = name
|
|
94
95
|
self.content_permissions: Optional[str] = content_permissions
|
|
@@ -194,7 +195,7 @@ class ProjectItem:
|
|
|
194
195
|
return self._name
|
|
195
196
|
|
|
196
197
|
@name.setter
|
|
197
|
-
def name(self, value: str) -> None:
|
|
198
|
+
def name(self, value: Optional[str]) -> None:
|
|
198
199
|
self._name = value
|
|
199
200
|
|
|
200
201
|
@property
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import re
|
|
3
3
|
from functools import wraps
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
from collections.abc import Container
|
|
6
6
|
|
|
7
7
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
@@ -67,7 +67,7 @@ def property_is_valid_time(func):
|
|
|
67
67
|
return wrapper
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def property_is_int(range: tuple[int, int], allowed:
|
|
70
|
+
def property_is_int(range: tuple[int, int], allowed: Container[Any] | None = None):
|
|
71
71
|
"""Takes a range of ints and a list of exemptions to check against
|
|
72
72
|
when setting a property on a model. The range is a tuple of (min, max) and the
|
|
73
73
|
allowed list (empty by default) allows values outside that range.
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from typing_extensions import Self
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class ResourceReference:
|
|
2
|
-
def __init__(self, id_, tag_name):
|
|
5
|
+
def __init__(self, id_: str | None, tag_name: str) -> None:
|
|
3
6
|
self.id = id_
|
|
4
7
|
self.tag_name = tag_name
|
|
5
8
|
|
|
6
|
-
def __str__(self):
|
|
9
|
+
def __str__(self) -> str:
|
|
7
10
|
return f"<ResourceReference id={self._id} tag={self._tag_name}>"
|
|
8
11
|
|
|
9
12
|
__repr__ = __str__
|
|
@@ -13,18 +16,21 @@ class ResourceReference:
|
|
|
13
16
|
return False
|
|
14
17
|
return (self.id == other.id) and (self.tag_name == other.tag_name)
|
|
15
18
|
|
|
19
|
+
def __hash__(self: Self) -> int:
|
|
20
|
+
return hash((self.id, self.tag_name))
|
|
21
|
+
|
|
16
22
|
@property
|
|
17
|
-
def id(self):
|
|
23
|
+
def id(self) -> str | None:
|
|
18
24
|
return self._id
|
|
19
25
|
|
|
20
26
|
@id.setter
|
|
21
|
-
def id(self, value):
|
|
27
|
+
def id(self, value: str | None) -> None:
|
|
22
28
|
self._id = value
|
|
23
29
|
|
|
24
30
|
@property
|
|
25
|
-
def tag_name(self):
|
|
31
|
+
def tag_name(self) -> str:
|
|
26
32
|
return self._tag_name
|
|
27
33
|
|
|
28
34
|
@tag_name.setter
|
|
29
|
-
def tag_name(self, value):
|
|
35
|
+
def tag_name(self, value: str) -> None:
|
|
30
36
|
self._tag_name = value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import xml.etree.ElementTree as ET
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from typing import Optional, Union
|
|
3
|
+
from typing import Optional, Union, TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from defusedxml.ElementTree import fromstring
|
|
6
6
|
|
|
@@ -16,6 +16,10 @@ from .property_decorators import (
|
|
|
16
16
|
property_is_enum,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from requests import Response
|
|
21
|
+
|
|
22
|
+
|
|
19
23
|
Interval = Union[HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval]
|
|
20
24
|
|
|
21
25
|
|
|
@@ -407,3 +411,8 @@ class ScheduleItem:
|
|
|
407
411
|
for warning_xml in all_warning_xml:
|
|
408
412
|
warnings.append(warning_xml.get("message", None))
|
|
409
413
|
return warnings
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def parse_batch_schedule_state(response: "Response", ns) -> list[str]:
|
|
417
|
+
xml = fromstring(response.content)
|
|
418
|
+
return [text for tag in xml.findall(".//t:scheduleLuid", namespaces=ns) if (text := tag.text)]
|
|
@@ -85,6 +85,9 @@ class SiteItem:
|
|
|
85
85
|
state: str
|
|
86
86
|
Shows the current state of the site (Active or Suspended).
|
|
87
87
|
|
|
88
|
+
attribute_capture_enabled: Optional[str]
|
|
89
|
+
Enables user attributes for all Tableau Server embedding workflows.
|
|
90
|
+
|
|
88
91
|
"""
|
|
89
92
|
|
|
90
93
|
_user_quota: Optional[int] = None
|
|
@@ -164,6 +167,7 @@ class SiteItem:
|
|
|
164
167
|
time_zone=None,
|
|
165
168
|
auto_suspend_refresh_enabled: bool = True,
|
|
166
169
|
auto_suspend_refresh_inactivity_window: int = 30,
|
|
170
|
+
attribute_capture_enabled: Optional[bool] = None,
|
|
167
171
|
):
|
|
168
172
|
self._admin_mode = None
|
|
169
173
|
self._id: Optional[str] = None
|
|
@@ -217,6 +221,7 @@ class SiteItem:
|
|
|
217
221
|
self.time_zone = time_zone
|
|
218
222
|
self.auto_suspend_refresh_enabled = auto_suspend_refresh_enabled
|
|
219
223
|
self.auto_suspend_refresh_inactivity_window = auto_suspend_refresh_inactivity_window
|
|
224
|
+
self.attribute_capture_enabled = attribute_capture_enabled
|
|
220
225
|
|
|
221
226
|
@property
|
|
222
227
|
def admin_mode(self) -> Optional[str]:
|
|
@@ -720,6 +725,7 @@ class SiteItem:
|
|
|
720
725
|
time_zone,
|
|
721
726
|
auto_suspend_refresh_enabled,
|
|
722
727
|
auto_suspend_refresh_inactivity_window,
|
|
728
|
+
attribute_capture_enabled,
|
|
723
729
|
) = self._parse_element(site_xml, ns)
|
|
724
730
|
|
|
725
731
|
self._set_values(
|
|
@@ -774,6 +780,7 @@ class SiteItem:
|
|
|
774
780
|
time_zone,
|
|
775
781
|
auto_suspend_refresh_enabled,
|
|
776
782
|
auto_suspend_refresh_inactivity_window,
|
|
783
|
+
attribute_capture_enabled,
|
|
777
784
|
)
|
|
778
785
|
return self
|
|
779
786
|
|
|
@@ -830,6 +837,7 @@ class SiteItem:
|
|
|
830
837
|
time_zone,
|
|
831
838
|
auto_suspend_refresh_enabled,
|
|
832
839
|
auto_suspend_refresh_inactivity_window,
|
|
840
|
+
attribute_capture_enabled,
|
|
833
841
|
):
|
|
834
842
|
if id is not None:
|
|
835
843
|
self._id = id
|
|
@@ -937,6 +945,7 @@ class SiteItem:
|
|
|
937
945
|
self.auto_suspend_refresh_enabled = auto_suspend_refresh_enabled
|
|
938
946
|
if auto_suspend_refresh_inactivity_window is not None:
|
|
939
947
|
self.auto_suspend_refresh_inactivity_window = auto_suspend_refresh_inactivity_window
|
|
948
|
+
self.attribute_capture_enabled = attribute_capture_enabled
|
|
940
949
|
|
|
941
950
|
@classmethod
|
|
942
951
|
def from_response(cls, resp, ns) -> list["SiteItem"]:
|
|
@@ -996,6 +1005,7 @@ class SiteItem:
|
|
|
996
1005
|
time_zone,
|
|
997
1006
|
auto_suspend_refresh_enabled,
|
|
998
1007
|
auto_suspend_refresh_inactivity_window,
|
|
1008
|
+
attribute_capture_enabled,
|
|
999
1009
|
) = cls._parse_element(site_xml, ns)
|
|
1000
1010
|
|
|
1001
1011
|
site_item = cls(name, content_url)
|
|
@@ -1051,6 +1061,7 @@ class SiteItem:
|
|
|
1051
1061
|
time_zone,
|
|
1052
1062
|
auto_suspend_refresh_enabled,
|
|
1053
1063
|
auto_suspend_refresh_inactivity_window,
|
|
1064
|
+
attribute_capture_enabled,
|
|
1054
1065
|
)
|
|
1055
1066
|
all_site_items.append(site_item)
|
|
1056
1067
|
return all_site_items
|
|
@@ -1132,6 +1143,9 @@ class SiteItem:
|
|
|
1132
1143
|
|
|
1133
1144
|
flows_enabled = string_to_bool(site_xml.get("flowsEnabled", ""))
|
|
1134
1145
|
cataloging_enabled = string_to_bool(site_xml.get("catalogingEnabled", ""))
|
|
1146
|
+
attribute_capture_enabled = (
|
|
1147
|
+
string_to_bool(ace) if (ace := site_xml.get("attributeCaptureEnabled")) is not None else None
|
|
1148
|
+
)
|
|
1135
1149
|
|
|
1136
1150
|
return (
|
|
1137
1151
|
id,
|
|
@@ -1185,6 +1199,7 @@ class SiteItem:
|
|
|
1185
1199
|
time_zone,
|
|
1186
1200
|
auto_suspend_refresh_enabled,
|
|
1187
1201
|
auto_suspend_refresh_inactivity_window,
|
|
1202
|
+
attribute_capture_enabled,
|
|
1188
1203
|
)
|
|
1189
1204
|
|
|
1190
1205
|
|
|
@@ -1215,6 +1230,17 @@ class SiteAuthConfiguration:
|
|
|
1215
1230
|
all_auth_configs.append(auth_config)
|
|
1216
1231
|
return all_auth_configs
|
|
1217
1232
|
|
|
1233
|
+
def __str__(self):
|
|
1234
|
+
return (
|
|
1235
|
+
f"{self.__class__.__qualname__}(auth_setting={self.auth_setting}, "
|
|
1236
|
+
f"enabled={self.enabled}, "
|
|
1237
|
+
f"idp_configuration_id={self.idp_configuration_id}, "
|
|
1238
|
+
f"idp_configuration_name={self.idp_configuration_name})"
|
|
1239
|
+
)
|
|
1240
|
+
|
|
1241
|
+
def __repr__(self):
|
|
1242
|
+
return f"<{str(self)}>"
|
|
1243
|
+
|
|
1218
1244
|
|
|
1219
1245
|
# Used to convert string represented boolean to a boolean type
|
|
1220
1246
|
def string_to_bool(s: str) -> bool:
|
|
@@ -87,7 +87,7 @@ class TableauAuth(Credentials):
|
|
|
87
87
|
uid = f", user_id_to_impersonate=f{self.user_id_to_impersonate}"
|
|
88
88
|
else:
|
|
89
89
|
uid = ""
|
|
90
|
-
return f"<
|
|
90
|
+
return f"<{self.__class__.__qualname__} username={self.username} password=redacted (site={self.site_id}{uid})>"
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
# A Tableau-generated Personal Access Token
|
|
@@ -155,8 +155,8 @@ class PersonalAccessTokenAuth(Credentials):
|
|
|
155
155
|
else:
|
|
156
156
|
uid = ""
|
|
157
157
|
return (
|
|
158
|
-
f"<
|
|
159
|
-
f"
|
|
158
|
+
f"<{self.__class__.__qualname__}(name={self.token_name} token={self.personal_access_token[:2]}..."
|
|
159
|
+
f"site={self.site_id}{uid}) >"
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
|
|
@@ -198,19 +198,26 @@ class JWTAuth(Credentials):
|
|
|
198
198
|
|
|
199
199
|
"""
|
|
200
200
|
|
|
201
|
-
def __init__(
|
|
201
|
+
def __init__(
|
|
202
|
+
self,
|
|
203
|
+
jwt: str,
|
|
204
|
+
isUat: bool = False,
|
|
205
|
+
site_id: Optional[str] = None,
|
|
206
|
+
user_id_to_impersonate: Optional[str] = None,
|
|
207
|
+
) -> None:
|
|
202
208
|
if jwt is None:
|
|
203
209
|
raise TabError("Must provide a JWT token when using JWT authentication")
|
|
204
210
|
super().__init__(site_id, user_id_to_impersonate)
|
|
205
211
|
self.jwt = jwt
|
|
212
|
+
self.isUat = isUat
|
|
206
213
|
|
|
207
214
|
@property
|
|
208
215
|
def credentials(self) -> dict[str, str]:
|
|
209
|
-
return {"jwt": self.jwt}
|
|
216
|
+
return {"jwt": self.jwt, "isUat": str(self.isUat).lower()}
|
|
210
217
|
|
|
211
218
|
def __repr__(self):
|
|
212
219
|
if self.user_id_to_impersonate:
|
|
213
220
|
uid = f", user_id_to_impersonate=f{self.user_id_to_impersonate}"
|
|
214
221
|
else:
|
|
215
222
|
uid = ""
|
|
216
|
-
return f"<{self.__class__.__qualname__} jwt={self.jwt[:5]}... (site={self.site_id}{uid})>"
|
|
223
|
+
return f"<{self.__class__.__qualname__} jwt={self.jwt[:5]}... isUat={self.isUat} (site={self.site_id}{uid})>"
|
|
@@ -5,6 +5,7 @@ from enum import IntEnum
|
|
|
5
5
|
from typing import Optional, TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from defusedxml.ElementTree import fromstring
|
|
8
|
+
from typing_extensions import Self
|
|
8
9
|
|
|
9
10
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
10
11
|
from tableauserverclient.models.site_item import SiteAuthConfiguration
|
|
@@ -17,6 +18,7 @@ from .reference_item import ResourceReference
|
|
|
17
18
|
|
|
18
19
|
if TYPE_CHECKING:
|
|
19
20
|
from tableauserverclient.server import Pager
|
|
21
|
+
from tableauserverclient.models.favorites_item import FavoriteType
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class UserItem:
|
|
@@ -131,7 +133,7 @@ class UserItem:
|
|
|
131
133
|
self._id: Optional[str] = None
|
|
132
134
|
self._last_login: Optional[datetime] = None
|
|
133
135
|
self._workbooks = None
|
|
134
|
-
self._favorites: Optional[
|
|
136
|
+
self._favorites: Optional["FavoriteType"] = None
|
|
135
137
|
self._groups = None
|
|
136
138
|
self.email: Optional[str] = None
|
|
137
139
|
self.fullname: Optional[str] = None
|
|
@@ -185,7 +187,7 @@ class UserItem:
|
|
|
185
187
|
return self._name
|
|
186
188
|
|
|
187
189
|
@name.setter
|
|
188
|
-
def name(self, value: str):
|
|
190
|
+
def name(self, value: Optional[str]):
|
|
189
191
|
self._name = value
|
|
190
192
|
|
|
191
193
|
# valid: username, domain/username, username@domain, domain/username@email
|
|
@@ -218,7 +220,7 @@ class UserItem:
|
|
|
218
220
|
return self._workbooks()
|
|
219
221
|
|
|
220
222
|
@property
|
|
221
|
-
def favorites(self) ->
|
|
223
|
+
def favorites(self) -> "FavoriteType":
|
|
222
224
|
if self._favorites is None:
|
|
223
225
|
error = "User item must be populated with favorites first."
|
|
224
226
|
raise UnpopulatedPropertyError(error)
|
|
@@ -376,6 +378,11 @@ class UserItem:
|
|
|
376
378
|
def as_reference(id_) -> ResourceReference:
|
|
377
379
|
return ResourceReference(id_, UserItem.tag_name)
|
|
378
380
|
|
|
381
|
+
def to_reference(self: Self) -> ResourceReference:
|
|
382
|
+
if self.id is None:
|
|
383
|
+
raise ValueError(f"{self.__class__.__qualname__} must have id to be converted to reference")
|
|
384
|
+
return ResourceReference(self.id, self.tag_name)
|
|
385
|
+
|
|
379
386
|
@staticmethod
|
|
380
387
|
def _parse_element(user_xml, ns):
|
|
381
388
|
id = user_xml.get("id", None)
|
|
@@ -330,7 +330,7 @@ class WorkbookItem:
|
|
|
330
330
|
return self._thumbnails_user_id
|
|
331
331
|
|
|
332
332
|
@thumbnails_user_id.setter
|
|
333
|
-
def thumbnails_user_id(self, value: str):
|
|
333
|
+
def thumbnails_user_id(self, value: Optional[str]):
|
|
334
334
|
self._thumbnails_user_id = value
|
|
335
335
|
|
|
336
336
|
@property
|
|
@@ -338,7 +338,7 @@ class WorkbookItem:
|
|
|
338
338
|
return self._thumbnails_group_id
|
|
339
339
|
|
|
340
340
|
@thumbnails_group_id.setter
|
|
341
|
-
def thumbnails_group_id(self, value: str):
|
|
341
|
+
def thumbnails_group_id(self, value: Optional[str]):
|
|
342
342
|
self._thumbnails_group_id = value
|
|
343
343
|
|
|
344
344
|
@property
|
|
@@ -6,6 +6,7 @@ from tableauserverclient.server.endpoint.databases_endpoint import Databases
|
|
|
6
6
|
from tableauserverclient.server.endpoint.datasources_endpoint import Datasources
|
|
7
7
|
from tableauserverclient.server.endpoint.endpoint import Endpoint, QuerysetEndpoint
|
|
8
8
|
from tableauserverclient.server.endpoint.exceptions import ServerResponseError, MissingRequiredFieldError
|
|
9
|
+
from tableauserverclient.server.endpoint.extensions_endpoint import Extensions
|
|
9
10
|
from tableauserverclient.server.endpoint.favorites_endpoint import Favorites
|
|
10
11
|
from tableauserverclient.server.endpoint.fileuploads_endpoint import Fileuploads
|
|
11
12
|
from tableauserverclient.server.endpoint.flow_runs_endpoint import FlowRuns
|
|
@@ -17,6 +18,7 @@ from tableauserverclient.server.endpoint.jobs_endpoint import Jobs
|
|
|
17
18
|
from tableauserverclient.server.endpoint.linked_tasks_endpoint import LinkedTasks
|
|
18
19
|
from tableauserverclient.server.endpoint.metadata_endpoint import Metadata
|
|
19
20
|
from tableauserverclient.server.endpoint.metrics_endpoint import Metrics
|
|
21
|
+
from tableauserverclient.server.endpoint.oidc_endpoint import OIDC
|
|
20
22
|
from tableauserverclient.server.endpoint.projects_endpoint import Projects
|
|
21
23
|
from tableauserverclient.server.endpoint.schedules_endpoint import Schedules
|
|
22
24
|
from tableauserverclient.server.endpoint.server_info_endpoint import ServerInfo
|
|
@@ -41,6 +43,7 @@ __all__ = [
|
|
|
41
43
|
"QuerysetEndpoint",
|
|
42
44
|
"MissingRequiredFieldError",
|
|
43
45
|
"Endpoint",
|
|
46
|
+
"Extensions",
|
|
44
47
|
"Favorites",
|
|
45
48
|
"Fileuploads",
|
|
46
49
|
"FlowRuns",
|
|
@@ -52,6 +55,7 @@ __all__ = [
|
|
|
52
55
|
"LinkedTasks",
|
|
53
56
|
"Metadata",
|
|
54
57
|
"Metrics",
|
|
58
|
+
"OIDC",
|
|
55
59
|
"Projects",
|
|
56
60
|
"Schedules",
|
|
57
61
|
"ServerInfo",
|