tableauserverclient 0.32__py3-none-any.whl → 0.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tableauserverclient/__init__.py +34 -18
- tableauserverclient/_version.py +3 -3
- tableauserverclient/config.py +20 -6
- tableauserverclient/models/__init__.py +12 -0
- tableauserverclient/models/column_item.py +1 -1
- tableauserverclient/models/connection_credentials.py +1 -1
- tableauserverclient/models/connection_item.py +10 -8
- tableauserverclient/models/custom_view_item.py +29 -6
- tableauserverclient/models/data_acceleration_report_item.py +2 -2
- tableauserverclient/models/data_alert_item.py +5 -5
- tableauserverclient/models/data_freshness_policy_item.py +6 -6
- tableauserverclient/models/database_item.py +8 -2
- tableauserverclient/models/datasource_item.py +10 -10
- tableauserverclient/models/dqw_item.py +1 -1
- tableauserverclient/models/favorites_item.py +5 -6
- tableauserverclient/models/fileupload_item.py +1 -1
- tableauserverclient/models/flow_item.py +12 -12
- tableauserverclient/models/flow_run_item.py +3 -3
- tableauserverclient/models/group_item.py +4 -4
- tableauserverclient/models/groupset_item.py +53 -0
- tableauserverclient/models/interval_item.py +36 -23
- tableauserverclient/models/job_item.py +26 -10
- tableauserverclient/models/linked_tasks_item.py +102 -0
- tableauserverclient/models/metric_item.py +5 -5
- tableauserverclient/models/pagination_item.py +1 -1
- tableauserverclient/models/permissions_item.py +19 -14
- tableauserverclient/models/project_item.py +35 -19
- tableauserverclient/models/property_decorators.py +12 -11
- tableauserverclient/models/reference_item.py +2 -2
- tableauserverclient/models/revision_item.py +3 -3
- tableauserverclient/models/schedule_item.py +2 -2
- tableauserverclient/models/server_info_item.py +26 -6
- tableauserverclient/models/site_item.py +69 -3
- tableauserverclient/models/subscription_item.py +3 -3
- tableauserverclient/models/table_item.py +1 -1
- tableauserverclient/models/tableau_auth.py +115 -5
- tableauserverclient/models/tableau_types.py +11 -9
- tableauserverclient/models/tag_item.py +3 -4
- tableauserverclient/models/task_item.py +4 -4
- tableauserverclient/models/user_item.py +47 -17
- tableauserverclient/models/view_item.py +11 -10
- tableauserverclient/models/virtual_connection_item.py +78 -0
- tableauserverclient/models/webhook_item.py +6 -6
- tableauserverclient/models/workbook_item.py +90 -12
- tableauserverclient/namespace.py +1 -1
- tableauserverclient/server/__init__.py +2 -1
- tableauserverclient/server/endpoint/__init__.py +8 -0
- tableauserverclient/server/endpoint/auth_endpoint.py +68 -11
- tableauserverclient/server/endpoint/custom_views_endpoint.py +124 -19
- tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
- tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
- tableauserverclient/server/endpoint/databases_endpoint.py +32 -17
- tableauserverclient/server/endpoint/datasources_endpoint.py +150 -59
- tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
- tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
- tableauserverclient/server/endpoint/endpoint.py +47 -31
- tableauserverclient/server/endpoint/exceptions.py +23 -7
- tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
- tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -13
- tableauserverclient/server/endpoint/flow_runs_endpoint.py +59 -17
- tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
- tableauserverclient/server/endpoint/flows_endpoint.py +73 -35
- tableauserverclient/server/endpoint/groups_endpoint.py +96 -27
- tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
- tableauserverclient/server/endpoint/jobs_endpoint.py +79 -12
- tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
- tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
- tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
- tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
- tableauserverclient/server/endpoint/projects_endpoint.py +124 -30
- tableauserverclient/server/endpoint/resource_tagger.py +139 -6
- tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
- tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
- tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
- tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
- tableauserverclient/server/endpoint/tables_endpoint.py +33 -19
- tableauserverclient/server/endpoint/tasks_endpoint.py +8 -8
- tableauserverclient/server/endpoint/users_endpoint.py +405 -19
- tableauserverclient/server/endpoint/views_endpoint.py +111 -25
- tableauserverclient/server/endpoint/virtual_connections_endpoint.py +174 -0
- tableauserverclient/server/endpoint/webhooks_endpoint.py +11 -11
- tableauserverclient/server/endpoint/workbooks_endpoint.py +735 -68
- tableauserverclient/server/filter.py +2 -2
- tableauserverclient/server/pager.py +8 -10
- tableauserverclient/server/query.py +70 -20
- tableauserverclient/server/request_factory.py +213 -41
- tableauserverclient/server/request_options.py +125 -145
- tableauserverclient/server/server.py +73 -9
- tableauserverclient/server/sort.py +2 -2
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/METADATA +17 -17
- tableauserverclient-0.34.dist-info/RECORD +106 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/WHEEL +1 -1
- tableauserverclient-0.32.dist-info/RECORD +0 -100
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE +0 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import xml.etree.ElementTree as ET
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from defusedxml.ElementTree import fromstring
|
|
6
6
|
|
|
@@ -8,14 +8,16 @@ from tableauserverclient.models.exceptions import UnpopulatedPropertyError
|
|
|
8
8
|
from tableauserverclient.models.property_decorators import property_is_enum, property_not_empty
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class ProjectItem
|
|
11
|
+
class ProjectItem:
|
|
12
|
+
ERROR_MSG = "Project item must be populated with permissions first."
|
|
13
|
+
|
|
12
14
|
class ContentPermissions:
|
|
13
15
|
LockedToProject: str = "LockedToProject"
|
|
14
16
|
ManagedByOwner: str = "ManagedByOwner"
|
|
15
17
|
LockedToProjectWithoutNested: str = "LockedToProjectWithoutNested"
|
|
16
18
|
|
|
17
19
|
def __repr__(self):
|
|
18
|
-
return "<Project {
|
|
20
|
+
return "<Project {} {} parent={} permissions={}>".format(
|
|
19
21
|
self._id, self.name, self.parent_id or "None (Top level)", self.content_permissions or "Not Set"
|
|
20
22
|
)
|
|
21
23
|
|
|
@@ -43,6 +45,9 @@ class ProjectItem(object):
|
|
|
43
45
|
self._default_lens_permissions = None
|
|
44
46
|
self._default_datarole_permissions = None
|
|
45
47
|
self._default_metric_permissions = None
|
|
48
|
+
self._default_virtualconnection_permissions = None
|
|
49
|
+
self._default_database_permissions = None
|
|
50
|
+
self._default_table_permissions = None
|
|
46
51
|
|
|
47
52
|
@property
|
|
48
53
|
def content_permissions(self):
|
|
@@ -56,52 +61,63 @@ class ProjectItem(object):
|
|
|
56
61
|
@property
|
|
57
62
|
def permissions(self):
|
|
58
63
|
if self._permissions is None:
|
|
59
|
-
|
|
60
|
-
raise UnpopulatedPropertyError(error)
|
|
64
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
61
65
|
return self._permissions()
|
|
62
66
|
|
|
63
67
|
@property
|
|
64
68
|
def default_datasource_permissions(self):
|
|
65
69
|
if self._default_datasource_permissions is None:
|
|
66
|
-
|
|
67
|
-
raise UnpopulatedPropertyError(error)
|
|
70
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
68
71
|
return self._default_datasource_permissions()
|
|
69
72
|
|
|
70
73
|
@property
|
|
71
74
|
def default_workbook_permissions(self):
|
|
72
75
|
if self._default_workbook_permissions is None:
|
|
73
|
-
|
|
74
|
-
raise UnpopulatedPropertyError(error)
|
|
76
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
75
77
|
return self._default_workbook_permissions()
|
|
76
78
|
|
|
77
79
|
@property
|
|
78
80
|
def default_flow_permissions(self):
|
|
79
81
|
if self._default_flow_permissions is None:
|
|
80
|
-
|
|
81
|
-
raise UnpopulatedPropertyError(error)
|
|
82
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
82
83
|
return self._default_flow_permissions()
|
|
83
84
|
|
|
84
85
|
@property
|
|
85
86
|
def default_lens_permissions(self):
|
|
86
87
|
if self._default_lens_permissions is None:
|
|
87
|
-
|
|
88
|
-
raise UnpopulatedPropertyError(error)
|
|
88
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
89
89
|
return self._default_lens_permissions()
|
|
90
90
|
|
|
91
91
|
@property
|
|
92
92
|
def default_datarole_permissions(self):
|
|
93
93
|
if self._default_datarole_permissions is None:
|
|
94
|
-
|
|
95
|
-
raise UnpopulatedPropertyError(error)
|
|
94
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
96
95
|
return self._default_datarole_permissions()
|
|
97
96
|
|
|
98
97
|
@property
|
|
99
98
|
def default_metric_permissions(self):
|
|
100
99
|
if self._default_metric_permissions is None:
|
|
101
|
-
|
|
102
|
-
raise UnpopulatedPropertyError(error)
|
|
100
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
103
101
|
return self._default_metric_permissions()
|
|
104
102
|
|
|
103
|
+
@property
|
|
104
|
+
def default_virtualconnection_permissions(self):
|
|
105
|
+
if self._default_virtualconnection_permissions is None:
|
|
106
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
107
|
+
return self._default_virtualconnection_permissions()
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def default_database_permissions(self):
|
|
111
|
+
if self._default_database_permissions is None:
|
|
112
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
113
|
+
return self._default_database_permissions()
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def default_table_permissions(self):
|
|
117
|
+
if self._default_table_permissions is None:
|
|
118
|
+
raise UnpopulatedPropertyError(self.ERROR_MSG)
|
|
119
|
+
return self._default_table_permissions()
|
|
120
|
+
|
|
105
121
|
@property
|
|
106
122
|
def id(self) -> Optional[str]:
|
|
107
123
|
return self._id
|
|
@@ -158,7 +174,7 @@ class ProjectItem(object):
|
|
|
158
174
|
self._permissions = permissions
|
|
159
175
|
|
|
160
176
|
def _set_default_permissions(self, permissions, content_type):
|
|
161
|
-
attr = "_default_{
|
|
177
|
+
attr = f"_default_{content_type}_permissions"
|
|
162
178
|
setattr(
|
|
163
179
|
self,
|
|
164
180
|
attr,
|
|
@@ -166,7 +182,7 @@ class ProjectItem(object):
|
|
|
166
182
|
)
|
|
167
183
|
|
|
168
184
|
@classmethod
|
|
169
|
-
def from_response(cls, resp, ns) ->
|
|
185
|
+
def from_response(cls, resp, ns) -> list["ProjectItem"]:
|
|
170
186
|
all_project_items = list()
|
|
171
187
|
parsed_response = fromstring(resp)
|
|
172
188
|
all_project_xml = parsed_response.findall(".//t:project", namespaces=ns)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import re
|
|
3
3
|
from functools import wraps
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
from collections.abc import Container
|
|
5
6
|
|
|
6
7
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
7
8
|
|
|
@@ -11,7 +12,7 @@ def property_is_enum(enum_type):
|
|
|
11
12
|
@wraps(func)
|
|
12
13
|
def wrapper(self, value):
|
|
13
14
|
if value is not None and not hasattr(enum_type, value):
|
|
14
|
-
error = "Invalid value: {
|
|
15
|
+
error = f"Invalid value: {value}. {func.__name__} must be of type {enum_type.__name__}."
|
|
15
16
|
raise ValueError(error)
|
|
16
17
|
return func(self, value)
|
|
17
18
|
|
|
@@ -24,7 +25,7 @@ def property_is_boolean(func):
|
|
|
24
25
|
@wraps(func)
|
|
25
26
|
def wrapper(self, value):
|
|
26
27
|
if not isinstance(value, bool):
|
|
27
|
-
error = "Boolean expected for {
|
|
28
|
+
error = f"Boolean expected for {func.__name__} flag."
|
|
28
29
|
raise ValueError(error)
|
|
29
30
|
return func(self, value)
|
|
30
31
|
|
|
@@ -35,7 +36,7 @@ def property_not_nullable(func):
|
|
|
35
36
|
@wraps(func)
|
|
36
37
|
def wrapper(self, value):
|
|
37
38
|
if value is None:
|
|
38
|
-
error = "{
|
|
39
|
+
error = f"{func.__name__} must be defined."
|
|
39
40
|
raise ValueError(error)
|
|
40
41
|
return func(self, value)
|
|
41
42
|
|
|
@@ -46,7 +47,7 @@ def property_not_empty(func):
|
|
|
46
47
|
@wraps(func)
|
|
47
48
|
def wrapper(self, value):
|
|
48
49
|
if not value:
|
|
49
|
-
error = "{
|
|
50
|
+
error = f"{func.__name__} must not be empty."
|
|
50
51
|
raise ValueError(error)
|
|
51
52
|
return func(self, value)
|
|
52
53
|
|
|
@@ -66,7 +67,7 @@ def property_is_valid_time(func):
|
|
|
66
67
|
return wrapper
|
|
67
68
|
|
|
68
69
|
|
|
69
|
-
def property_is_int(range:
|
|
70
|
+
def property_is_int(range: tuple[int, int], allowed: Optional[Container[Any]] = None):
|
|
70
71
|
"""Takes a range of ints and a list of exemptions to check against
|
|
71
72
|
when setting a property on a model. The range is a tuple of (min, max) and the
|
|
72
73
|
allowed list (empty by default) allows values outside that range.
|
|
@@ -81,7 +82,7 @@ def property_is_int(range: Tuple[int, int], allowed: Optional[Container[Any]] =
|
|
|
81
82
|
def property_type_decorator(func):
|
|
82
83
|
@wraps(func)
|
|
83
84
|
def wrapper(self, value):
|
|
84
|
-
error = "Invalid property defined: '{}'. Integer value expected."
|
|
85
|
+
error = f"Invalid property defined: '{value}'. Integer value expected."
|
|
85
86
|
|
|
86
87
|
if range is None:
|
|
87
88
|
if isinstance(value, int):
|
|
@@ -133,7 +134,7 @@ def property_is_datetime(func):
|
|
|
133
134
|
return func(self, value)
|
|
134
135
|
if not isinstance(value, str):
|
|
135
136
|
raise ValueError(
|
|
136
|
-
"Cannot convert {} into a datetime, cannot update {
|
|
137
|
+
f"Cannot convert {value.__class__.__name__} into a datetime, cannot update {func.__name__}"
|
|
137
138
|
)
|
|
138
139
|
|
|
139
140
|
dt = parse_datetime(value)
|
|
@@ -146,11 +147,11 @@ def property_is_data_acceleration_config(func):
|
|
|
146
147
|
@wraps(func)
|
|
147
148
|
def wrapper(self, value):
|
|
148
149
|
if not isinstance(value, dict):
|
|
149
|
-
raise ValueError("{} is not type 'dict', cannot update {
|
|
150
|
+
raise ValueError(f"{value.__class__.__name__} is not type 'dict', cannot update {func.__name__})")
|
|
150
151
|
if len(value) < 2 or not all(attr in value.keys() for attr in ("acceleration_enabled", "accelerate_now")):
|
|
151
|
-
error = "{} should have 2 keys "
|
|
152
|
+
error = f"{func.__name__} should have 2 keys "
|
|
152
153
|
error += "'acceleration_enabled' and 'accelerate_now'"
|
|
153
|
-
error += "instead you have {
|
|
154
|
+
error += f"instead you have {value.keys()}"
|
|
154
155
|
raise ValueError(error)
|
|
155
156
|
return func(self, value)
|
|
156
157
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
class ResourceReference
|
|
1
|
+
class ResourceReference:
|
|
2
2
|
def __init__(self, id_, tag_name):
|
|
3
3
|
self.id = id_
|
|
4
4
|
self.tag_name = tag_name
|
|
5
5
|
|
|
6
6
|
def __str__(self):
|
|
7
|
-
return "<ResourceReference id={} tag={}>"
|
|
7
|
+
return f"<ResourceReference id={self._id} tag={self._tag_name}>"
|
|
8
8
|
|
|
9
9
|
__repr__ = __str__
|
|
10
10
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
4
|
from defusedxml.ElementTree import fromstring
|
|
5
5
|
|
|
6
6
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class RevisionItem
|
|
9
|
+
class RevisionItem:
|
|
10
10
|
def __init__(self):
|
|
11
11
|
self._resource_id: Optional[str] = None
|
|
12
12
|
self._resource_name: Optional[str] = None
|
|
@@ -56,7 +56,7 @@ class RevisionItem(object):
|
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
@classmethod
|
|
59
|
-
def from_response(cls, resp: bytes, ns, resource_item) ->
|
|
59
|
+
def from_response(cls, resp: bytes, ns, resource_item) -> list["RevisionItem"]:
|
|
60
60
|
all_revision_items = list()
|
|
61
61
|
parsed_response = fromstring(resp)
|
|
62
62
|
all_revision_xml = parsed_response.findall(".//t:revision", namespaces=ns)
|
|
@@ -19,7 +19,7 @@ from .property_decorators import (
|
|
|
19
19
|
Interval = Union[HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval]
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class ScheduleItem
|
|
22
|
+
class ScheduleItem:
|
|
23
23
|
class Type:
|
|
24
24
|
Extract = "Extract"
|
|
25
25
|
Flow = "Flow"
|
|
@@ -336,7 +336,7 @@ class ScheduleItem(object):
|
|
|
336
336
|
all_task_xml = parsed_response.findall(".//t:task", namespaces=ns)
|
|
337
337
|
|
|
338
338
|
error = (
|
|
339
|
-
"Status {}: {
|
|
339
|
+
f"Status {response.status_code}: {response.reason}"
|
|
340
340
|
if response.status_code < 200 or response.status_code >= 300
|
|
341
341
|
else None
|
|
342
342
|
)
|
|
@@ -6,7 +6,29 @@ from defusedxml.ElementTree import fromstring
|
|
|
6
6
|
from tableauserverclient.helpers.logging import logger
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class ServerInfoItem
|
|
9
|
+
class ServerInfoItem:
|
|
10
|
+
"""
|
|
11
|
+
The ServerInfoItem class contains the build and version information for
|
|
12
|
+
Tableau Server. The server information is accessed with the
|
|
13
|
+
server_info.get() method, which returns an instance of the ServerInfo class.
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
product_version : str
|
|
18
|
+
Shows the version of the Tableau Server or Tableau Cloud
|
|
19
|
+
(for example, 10.2.0).
|
|
20
|
+
|
|
21
|
+
build_number : str
|
|
22
|
+
Shows the specific build number (for example, 10200.17.0329.1446).
|
|
23
|
+
|
|
24
|
+
rest_api_version : str
|
|
25
|
+
Shows the supported REST API version number. Note that this might be
|
|
26
|
+
different from the default value specified for the server, with the
|
|
27
|
+
Server.version attribute. To take advantage of new features, you should
|
|
28
|
+
query the server and set the Server.version to match the supported REST
|
|
29
|
+
API version number.
|
|
30
|
+
"""
|
|
31
|
+
|
|
10
32
|
def __init__(self, product_version, build_number, rest_api_version):
|
|
11
33
|
self._product_version = product_version
|
|
12
34
|
self._build_number = build_number
|
|
@@ -40,13 +62,11 @@ class ServerInfoItem(object):
|
|
|
40
62
|
try:
|
|
41
63
|
parsed_response = fromstring(resp)
|
|
42
64
|
except xml.etree.ElementTree.ParseError as error:
|
|
43
|
-
logger.
|
|
44
|
-
logger.info(error)
|
|
65
|
+
logger.exception(f"Unexpected response for ServerInfo: {resp}")
|
|
45
66
|
return cls("Unknown", "Unknown", "Unknown")
|
|
46
67
|
except Exception as error:
|
|
47
|
-
logger.
|
|
48
|
-
|
|
49
|
-
return cls("Unknown", "Unknown", "Unknown")
|
|
68
|
+
logger.exception(f"Unexpected response for ServerInfo: {resp}")
|
|
69
|
+
raise error
|
|
50
70
|
|
|
51
71
|
product_version_tag = parsed_response.find(".//t:productVersion", namespaces=ns)
|
|
52
72
|
rest_api_version_tag = parsed_response.find(".//t:restApiVersion", namespaces=ns)
|
|
@@ -14,13 +14,79 @@ from .property_decorators import (
|
|
|
14
14
|
|
|
15
15
|
VALID_CONTENT_URL_RE = r"^[a-zA-Z0-9_\-]*$"
|
|
16
16
|
|
|
17
|
-
from typing import
|
|
17
|
+
from typing import Optional, Union, TYPE_CHECKING
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from tableauserverclient.server import Server
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
class SiteItem
|
|
23
|
+
class SiteItem:
|
|
24
|
+
"""
|
|
25
|
+
The SiteItem class contains the members or attributes for the site resources
|
|
26
|
+
on Tableau Server or Tableau Cloud. The SiteItem class defines the
|
|
27
|
+
information you can request or query from Tableau Server or Tableau Cloud.
|
|
28
|
+
The class members correspond to the attributes of a server request or
|
|
29
|
+
response payload.
|
|
30
|
+
|
|
31
|
+
Attributes
|
|
32
|
+
----------
|
|
33
|
+
name: str
|
|
34
|
+
The name of the site. The name of the default site is "".
|
|
35
|
+
|
|
36
|
+
content_url: str
|
|
37
|
+
The path to the site.
|
|
38
|
+
|
|
39
|
+
admin_mode: str
|
|
40
|
+
(Optional) For Tableau Server only. Specify ContentAndUsers to allow
|
|
41
|
+
site administrators to use the server interface and tabcmd commands to
|
|
42
|
+
add and remove users. (Specifying this option does not give site
|
|
43
|
+
administrators permissions to manage users using the REST API.) Specify
|
|
44
|
+
ContentOnly to prevent site administrators from adding or removing
|
|
45
|
+
users. (Server administrators can always add or remove users.)
|
|
46
|
+
|
|
47
|
+
user_quota: int
|
|
48
|
+
(Optional) Specifies the total number of users for the site. The number
|
|
49
|
+
can't exceed the number of licenses activated for the site; and if
|
|
50
|
+
tiered capacity attributes are set, then user_quota will equal the sum
|
|
51
|
+
of the tiered capacity values, and attempting to set user_quota will
|
|
52
|
+
cause an error.
|
|
53
|
+
|
|
54
|
+
tier_explorer_capacity: int
|
|
55
|
+
tier_creator_capacity: int
|
|
56
|
+
tier_viewer_capacity: int
|
|
57
|
+
(Optional) The maximum number of licenses for users with the Creator,
|
|
58
|
+
Explorer, or Viewer role, respectively, allowed on a site.
|
|
59
|
+
|
|
60
|
+
storage_quota: int
|
|
61
|
+
(Optional) Specifies the maximum amount of space for the new site, in
|
|
62
|
+
megabytes. If you set a quota and the site exceeds it, publishers will
|
|
63
|
+
be prevented from uploading new content until the site is under the
|
|
64
|
+
limit again.
|
|
65
|
+
|
|
66
|
+
disable_subscriptions: bool
|
|
67
|
+
(Optional) Specify true to prevent users from being able to subscribe
|
|
68
|
+
to workbooks on the specified site. The default is False.
|
|
69
|
+
|
|
70
|
+
subscribe_others_enabled: bool
|
|
71
|
+
(Optional) Specify false to prevent server administrators, site
|
|
72
|
+
administrators, and project or content owners from being able to
|
|
73
|
+
subscribe other users to workbooks on the specified site. The default
|
|
74
|
+
is True.
|
|
75
|
+
|
|
76
|
+
revision_history_enabled: bool
|
|
77
|
+
(Optional) Specify true to enable revision history for content resources
|
|
78
|
+
(workbooks and datasources). The default is False.
|
|
79
|
+
|
|
80
|
+
revision_limit: int
|
|
81
|
+
(Optional) Specifies the number of revisions of a content source
|
|
82
|
+
(workbook or data source) to allow. On Tableau Server, the default is
|
|
83
|
+
25.
|
|
84
|
+
|
|
85
|
+
state: str
|
|
86
|
+
Shows the current state of the site (Active or Suspended).
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
|
|
24
90
|
_user_quota: Optional[int] = None
|
|
25
91
|
_tier_creator_capacity: Optional[int] = None
|
|
26
92
|
_tier_explorer_capacity: Optional[int] = None
|
|
@@ -873,7 +939,7 @@ class SiteItem(object):
|
|
|
873
939
|
self.auto_suspend_refresh_inactivity_window = auto_suspend_refresh_inactivity_window
|
|
874
940
|
|
|
875
941
|
@classmethod
|
|
876
|
-
def from_response(cls, resp, ns) ->
|
|
942
|
+
def from_response(cls, resp, ns) -> list["SiteItem"]:
|
|
877
943
|
all_site_items = list()
|
|
878
944
|
parsed_response = fromstring(resp)
|
|
879
945
|
all_site_xml = parsed_response.findall(".//t:site", namespaces=ns)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
3
|
from defusedxml.ElementTree import fromstring
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from .target import Target
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class SubscriptionItem
|
|
13
|
+
class SubscriptionItem:
|
|
14
14
|
def __init__(self, subject: str, schedule_id: str, user_id: str, target: "Target") -> None:
|
|
15
15
|
self._id = None
|
|
16
16
|
self.attach_image = True
|
|
@@ -79,7 +79,7 @@ class SubscriptionItem(object):
|
|
|
79
79
|
self._suspended = value
|
|
80
80
|
|
|
81
81
|
@classmethod
|
|
82
|
-
def from_response(cls:
|
|
82
|
+
def from_response(cls: type, xml: bytes, ns) -> list["SubscriptionItem"]:
|
|
83
83
|
parsed_response = fromstring(xml)
|
|
84
84
|
all_subscriptions_xml = parsed_response.findall(".//t:subscription", namespaces=ns)
|
|
85
85
|
|
|
@@ -4,7 +4,7 @@ from .exceptions import UnpopulatedPropertyError
|
|
|
4
4
|
from .property_decorators import property_not_empty, property_is_boolean
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class TableItem
|
|
7
|
+
class TableItem:
|
|
8
8
|
def __init__(self, name, description=None):
|
|
9
9
|
self._id = None
|
|
10
10
|
self.description = description
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Credentials(abc.ABC):
|
|
@@ -9,7 +9,7 @@ class Credentials(abc.ABC):
|
|
|
9
9
|
|
|
10
10
|
@property
|
|
11
11
|
@abc.abstractmethod
|
|
12
|
-
def credentials(self) ->
|
|
12
|
+
def credentials(self) -> dict[str, str]:
|
|
13
13
|
credentials = (
|
|
14
14
|
"Credentials can be username/password, Personal Access Token, or JWT"
|
|
15
15
|
"This method returns values to set as an attribute on the credentials element of the request"
|
|
@@ -32,6 +32,43 @@ def deprecate_site_attribute():
|
|
|
32
32
|
|
|
33
33
|
# The traditional auth type: username/password
|
|
34
34
|
class TableauAuth(Credentials):
|
|
35
|
+
"""
|
|
36
|
+
The TableauAuth class defines the information you can set in a sign-in
|
|
37
|
+
request. The class members correspond to the attributes of a server request
|
|
38
|
+
or response payload. To use this class, create a new instance, supplying
|
|
39
|
+
user name, password, and site information if necessary, and pass the
|
|
40
|
+
request object to the Auth.sign_in method.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
username : str
|
|
45
|
+
The user name for the sign-in request.
|
|
46
|
+
|
|
47
|
+
password : str
|
|
48
|
+
The password for the sign-in request.
|
|
49
|
+
|
|
50
|
+
site_id : str, optional
|
|
51
|
+
This corresponds to the contentUrl attribute in the Tableau REST API.
|
|
52
|
+
The site_id is the portion of the URL that follows the /site/ in the
|
|
53
|
+
URL. For example, "MarketingTeam" is the site_id in the following URL
|
|
54
|
+
MyServer/#/site/MarketingTeam/projects. To specify the default site on
|
|
55
|
+
Tableau Server, you can use an empty string '' (single quotes, no
|
|
56
|
+
space). For Tableau Cloud, you must provide a value for the site_id.
|
|
57
|
+
|
|
58
|
+
user_id_to_impersonate : str, optional
|
|
59
|
+
Specifies the id (not the name) of the user to sign in as. This is not
|
|
60
|
+
available for Tableau Online.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
>>> import tableauserverclient as TSC
|
|
65
|
+
|
|
66
|
+
>>> tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD', site_id='CONTENTURL')
|
|
67
|
+
>>> server = TSC.Server('https://SERVER_URL', use_server_version=True)
|
|
68
|
+
>>> server.auth.sign_in(tableau_auth)
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
|
|
35
72
|
def __init__(
|
|
36
73
|
self, username: str, password: str, site_id: Optional[str] = None, user_id_to_impersonate: Optional[str] = None
|
|
37
74
|
) -> None:
|
|
@@ -42,7 +79,7 @@ class TableauAuth(Credentials):
|
|
|
42
79
|
self.username = username
|
|
43
80
|
|
|
44
81
|
@property
|
|
45
|
-
def credentials(self) ->
|
|
82
|
+
def credentials(self) -> dict[str, str]:
|
|
46
83
|
return {"name": self.username, "password": self.password}
|
|
47
84
|
|
|
48
85
|
def __repr__(self):
|
|
@@ -55,6 +92,43 @@ class TableauAuth(Credentials):
|
|
|
55
92
|
|
|
56
93
|
# A Tableau-generated Personal Access Token
|
|
57
94
|
class PersonalAccessTokenAuth(Credentials):
|
|
95
|
+
"""
|
|
96
|
+
The PersonalAccessTokenAuth class defines the information you can set in a sign-in
|
|
97
|
+
request. The class members correspond to the attributes of a server request
|
|
98
|
+
or response payload. To use this class, create a new instance, supplying
|
|
99
|
+
token name, token secret, and site information if necessary, and pass the
|
|
100
|
+
request object to the Auth.sign_in method.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
token_name : str
|
|
105
|
+
The name of the personal access token.
|
|
106
|
+
|
|
107
|
+
personal_access_token : str
|
|
108
|
+
The personal access token secret for the sign in request.
|
|
109
|
+
|
|
110
|
+
site_id : str, optional
|
|
111
|
+
This corresponds to the contentUrl attribute in the Tableau REST API.
|
|
112
|
+
The site_id is the portion of the URL that follows the /site/ in the
|
|
113
|
+
URL. For example, "MarketingTeam" is the site_id in the following URL
|
|
114
|
+
MyServer/#/site/MarketingTeam/projects. To specify the default site on
|
|
115
|
+
Tableau Server, you can use an empty string '' (single quotes, no
|
|
116
|
+
space). For Tableau Cloud, you must provide a value for the site_id.
|
|
117
|
+
|
|
118
|
+
user_id_to_impersonate : str, optional
|
|
119
|
+
Specifies the id (not the name) of the user to sign in as. This is not
|
|
120
|
+
available for Tableau Online.
|
|
121
|
+
|
|
122
|
+
Examples
|
|
123
|
+
--------
|
|
124
|
+
>>> import tableauserverclient as TSC
|
|
125
|
+
|
|
126
|
+
>>> tableau_auth = TSC.PersonalAccessTokenAuth("token_name", "token_secret", site_id='CONTENTURL')
|
|
127
|
+
>>> server = TSC.Server('https://SERVER_URL', use_server_version=True)
|
|
128
|
+
>>> server.auth.sign_in(tableau_auth)
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
|
|
58
132
|
def __init__(
|
|
59
133
|
self,
|
|
60
134
|
token_name: str,
|
|
@@ -69,7 +143,7 @@ class PersonalAccessTokenAuth(Credentials):
|
|
|
69
143
|
self.personal_access_token = personal_access_token
|
|
70
144
|
|
|
71
145
|
@property
|
|
72
|
-
def credentials(self) ->
|
|
146
|
+
def credentials(self) -> dict[str, str]:
|
|
73
147
|
return {
|
|
74
148
|
"personalAccessTokenName": self.token_name,
|
|
75
149
|
"personalAccessTokenSecret": self.personal_access_token,
|
|
@@ -88,6 +162,42 @@ class PersonalAccessTokenAuth(Credentials):
|
|
|
88
162
|
|
|
89
163
|
# A standard JWT generated specifically for Tableau
|
|
90
164
|
class JWTAuth(Credentials):
|
|
165
|
+
"""
|
|
166
|
+
The JWTAuth class defines the information you can set in a sign-in
|
|
167
|
+
request. The class members correspond to the attributes of a server request
|
|
168
|
+
or response payload. To use this class, create a new instance, supplying
|
|
169
|
+
an encoded JSON Web Token, and site information if necessary, and pass the
|
|
170
|
+
request object to the Auth.sign_in method.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
token : str
|
|
175
|
+
The encoded JSON Web Token.
|
|
176
|
+
|
|
177
|
+
site_id : str, optional
|
|
178
|
+
This corresponds to the contentUrl attribute in the Tableau REST API.
|
|
179
|
+
The site_id is the portion of the URL that follows the /site/ in the
|
|
180
|
+
URL. For example, "MarketingTeam" is the site_id in the following URL
|
|
181
|
+
MyServer/#/site/MarketingTeam/projects. To specify the default site on
|
|
182
|
+
Tableau Server, you can use an empty string '' (single quotes, no
|
|
183
|
+
space). For Tableau Cloud, you must provide a value for the site_id.
|
|
184
|
+
|
|
185
|
+
user_id_to_impersonate : str, optional
|
|
186
|
+
Specifies the id (not the name) of the user to sign in as. This is not
|
|
187
|
+
available for Tableau Online.
|
|
188
|
+
|
|
189
|
+
Examples
|
|
190
|
+
--------
|
|
191
|
+
>>> import jwt
|
|
192
|
+
>>> import tableauserverclient as TSC
|
|
193
|
+
|
|
194
|
+
>>> jwt_token = jwt.encode(...)
|
|
195
|
+
>>> tableau_auth = TSC.JWTAuth(token, site_id='CONTENTURL')
|
|
196
|
+
>>> server = TSC.Server('https://SERVER_URL', use_server_version=True)
|
|
197
|
+
>>> server.auth.sign_in(tableau_auth)
|
|
198
|
+
|
|
199
|
+
"""
|
|
200
|
+
|
|
91
201
|
def __init__(self, jwt: str, site_id: Optional[str] = None, user_id_to_impersonate: Optional[str] = None) -> None:
|
|
92
202
|
if jwt is None:
|
|
93
203
|
raise TabError("Must provide a JWT token when using JWT authentication")
|
|
@@ -95,7 +205,7 @@ class JWTAuth(Credentials):
|
|
|
95
205
|
self.jwt = jwt
|
|
96
206
|
|
|
97
207
|
@property
|
|
98
|
-
def credentials(self) ->
|
|
208
|
+
def credentials(self) -> dict[str, str]:
|
|
99
209
|
return {"jwt": self.jwt}
|
|
100
210
|
|
|
101
211
|
def __repr__(self):
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from typing import Union
|
|
2
2
|
|
|
3
|
-
from .datasource_item import DatasourceItem
|
|
4
|
-
from .flow_item import FlowItem
|
|
5
|
-
from .project_item import ProjectItem
|
|
6
|
-
from .view_item import ViewItem
|
|
7
|
-
from .workbook_item import WorkbookItem
|
|
8
|
-
from .metric_item import MetricItem
|
|
3
|
+
from tableauserverclient.models.datasource_item import DatasourceItem
|
|
4
|
+
from tableauserverclient.models.flow_item import FlowItem
|
|
5
|
+
from tableauserverclient.models.project_item import ProjectItem
|
|
6
|
+
from tableauserverclient.models.view_item import ViewItem
|
|
7
|
+
from tableauserverclient.models.workbook_item import WorkbookItem
|
|
8
|
+
from tableauserverclient.models.metric_item import MetricItem
|
|
9
|
+
from tableauserverclient.models.virtual_connection_item import VirtualConnectionItem
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class Resource:
|
|
@@ -18,16 +19,17 @@ class Resource:
|
|
|
18
19
|
Metric = "metric"
|
|
19
20
|
Project = "project"
|
|
20
21
|
View = "view"
|
|
22
|
+
VirtualConnection = "virtualConnection"
|
|
21
23
|
Workbook = "workbook"
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
# resource types that have permissions, can be renamed, etc
|
|
25
27
|
# todo: refactoring: should actually define TableauItem as an interface and let all these implement it
|
|
26
|
-
TableauItem = Union[DatasourceItem, FlowItem, MetricItem, ProjectItem, ViewItem, WorkbookItem]
|
|
28
|
+
TableauItem = Union[DatasourceItem, FlowItem, MetricItem, ProjectItem, ViewItem, WorkbookItem, VirtualConnectionItem]
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def plural_type(content_type: Resource) -> str:
|
|
31
|
+
def plural_type(content_type: Union[Resource, str]) -> str:
|
|
30
32
|
if content_type == Resource.Lens:
|
|
31
33
|
return "lenses"
|
|
32
34
|
else:
|
|
33
|
-
return "{}s"
|
|
35
|
+
return f"{content_type}s"
|