tableauserverclient 0.36__py3-none-any.whl → 0.38__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tableauserverclient/__init__.py +6 -0
- tableauserverclient/bin/_version.py +3 -3
- tableauserverclient/helpers/strings.py +25 -1
- tableauserverclient/models/__init__.py +6 -1
- tableauserverclient/models/connection_item.py +3 -3
- tableauserverclient/models/datasource_item.py +218 -23
- tableauserverclient/models/extract_item.py +82 -0
- tableauserverclient/models/flow_item.py +2 -2
- tableauserverclient/models/group_item.py +11 -0
- tableauserverclient/models/interval_item.py +40 -0
- tableauserverclient/models/job_item.py +1 -0
- tableauserverclient/models/location_item.py +53 -0
- tableauserverclient/models/project_item.py +138 -27
- tableauserverclient/models/schedule_item.py +57 -0
- tableauserverclient/models/site_item.py +28 -0
- tableauserverclient/models/table_item.py +7 -3
- tableauserverclient/models/tableau_types.py +13 -1
- tableauserverclient/models/user_item.py +101 -1
- tableauserverclient/models/view_item.py +79 -5
- tableauserverclient/models/workbook_item.py +151 -1
- tableauserverclient/server/__init__.py +2 -0
- tableauserverclient/server/endpoint/databases_endpoint.py +101 -18
- tableauserverclient/server/endpoint/datasources_endpoint.py +562 -7
- tableauserverclient/server/endpoint/dqw_endpoint.py +16 -6
- tableauserverclient/server/endpoint/endpoint.py +39 -0
- tableauserverclient/server/endpoint/exceptions.py +4 -0
- tableauserverclient/server/endpoint/fileuploads_endpoint.py +1 -1
- tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
- tableauserverclient/server/endpoint/jobs_endpoint.py +1 -1
- tableauserverclient/server/endpoint/schedules_endpoint.py +132 -2
- tableauserverclient/server/endpoint/sites_endpoint.py +18 -1
- tableauserverclient/server/endpoint/tables_endpoint.py +140 -17
- tableauserverclient/server/endpoint/users_endpoint.py +22 -5
- tableauserverclient/server/endpoint/views_endpoint.py +5 -1
- tableauserverclient/server/endpoint/workbooks_endpoint.py +24 -10
- tableauserverclient/server/query.py +36 -0
- tableauserverclient/server/request_factory.py +16 -5
- tableauserverclient/server/request_options.py +162 -2
- tableauserverclient/server/server.py +42 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/METADATA +3 -2
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/RECORD +45 -43
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/WHEEL +1 -1
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE +0 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE.versioneer +0 -0
- {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,13 @@ from .property_decorators import property_is_valid_time, property_not_nullable
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class IntervalItem:
|
|
5
|
+
"""
|
|
6
|
+
This class sets the frequency and start time of the scheduled item. This
|
|
7
|
+
class contains the classes for the hourly, daily, weekly, and monthly
|
|
8
|
+
intervals. This class mirrors the options you can set using the REST API and
|
|
9
|
+
the Tableau Server interface.
|
|
10
|
+
"""
|
|
11
|
+
|
|
5
12
|
class Frequency:
|
|
6
13
|
Hourly = "Hourly"
|
|
7
14
|
Daily = "Daily"
|
|
@@ -26,6 +33,19 @@ class IntervalItem:
|
|
|
26
33
|
|
|
27
34
|
|
|
28
35
|
class HourlyInterval:
|
|
36
|
+
"""
|
|
37
|
+
Runs scheduled item hourly. To set the hourly interval, you create an
|
|
38
|
+
instance of the HourlyInterval class and assign the following values:
|
|
39
|
+
start_time, end_time, and interval_value. To set the start_time and
|
|
40
|
+
end_time, assign the time value using this syntax: start_time=time(hour, minute)
|
|
41
|
+
and end_time=time(hour, minute). The hour is specified in 24 hour time.
|
|
42
|
+
The interval_value specifies how often the to run the task within the
|
|
43
|
+
start and end time. The options are expressed in hours. For example,
|
|
44
|
+
interval_value=.25 is every 15 minutes. The values are .25, .5, 1, 2, 4, 6,
|
|
45
|
+
8, 12. Hourly schedules that run more frequently than every 60 minutes must
|
|
46
|
+
have start and end times that are on the hour.
|
|
47
|
+
"""
|
|
48
|
+
|
|
29
49
|
def __init__(self, start_time, end_time, interval_value):
|
|
30
50
|
self.start_time = start_time
|
|
31
51
|
self.end_time = end_time
|
|
@@ -109,6 +129,12 @@ class HourlyInterval:
|
|
|
109
129
|
|
|
110
130
|
|
|
111
131
|
class DailyInterval:
|
|
132
|
+
"""
|
|
133
|
+
Runs the scheduled item daily. To set the daily interval, you create an
|
|
134
|
+
instance of the DailyInterval and assign the start_time. The start time uses
|
|
135
|
+
the syntax start_time=time(hour, minute).
|
|
136
|
+
"""
|
|
137
|
+
|
|
112
138
|
def __init__(self, start_time, *interval_values):
|
|
113
139
|
self.start_time = start_time
|
|
114
140
|
self.interval = interval_values
|
|
@@ -177,6 +203,15 @@ class DailyInterval:
|
|
|
177
203
|
|
|
178
204
|
|
|
179
205
|
class WeeklyInterval:
|
|
206
|
+
"""
|
|
207
|
+
Runs the scheduled item once a week. To set the weekly interval, you create
|
|
208
|
+
an instance of the WeeklyInterval and assign the start time and multiple
|
|
209
|
+
instances for the interval_value (days of week and start time). The start
|
|
210
|
+
time uses the syntax time(hour, minute). The interval_value is the day of
|
|
211
|
+
the week, expressed as a IntervalItem. For example
|
|
212
|
+
TSC.IntervalItem.Day.Monday for Monday.
|
|
213
|
+
"""
|
|
214
|
+
|
|
180
215
|
def __init__(self, start_time, *interval_values):
|
|
181
216
|
self.start_time = start_time
|
|
182
217
|
self.interval = interval_values
|
|
@@ -214,6 +249,11 @@ class WeeklyInterval:
|
|
|
214
249
|
|
|
215
250
|
|
|
216
251
|
class MonthlyInterval:
|
|
252
|
+
"""
|
|
253
|
+
Runs the scheduled item once a month. To set the monthly interval, you
|
|
254
|
+
create an instance of the MonthlyInterval and assign the start time and day.
|
|
255
|
+
"""
|
|
256
|
+
|
|
217
257
|
def __init__(self, start_time, interval_value):
|
|
218
258
|
self.start_time = start_time
|
|
219
259
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import xml.etree.ElementTree as ET
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LocationItem:
|
|
6
|
+
"""
|
|
7
|
+
Details of where an item is located, such as a personal space or project.
|
|
8
|
+
|
|
9
|
+
Attributes
|
|
10
|
+
----------
|
|
11
|
+
id : str | None
|
|
12
|
+
The ID of the location.
|
|
13
|
+
|
|
14
|
+
type : str | None
|
|
15
|
+
The type of location, such as PersonalSpace or Project.
|
|
16
|
+
|
|
17
|
+
name : str | None
|
|
18
|
+
The name of the location.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
class Type:
|
|
22
|
+
PersonalSpace = "PersonalSpace"
|
|
23
|
+
Project = "Project"
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self._id: Optional[str] = None
|
|
27
|
+
self._type: Optional[str] = None
|
|
28
|
+
self._name: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
def __repr__(self):
|
|
31
|
+
return f"{self.__class__.__name__}({self.__dict__!r})"
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def id(self) -> Optional[str]:
|
|
35
|
+
return self._id
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def type(self) -> Optional[str]:
|
|
39
|
+
return self._type
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def name(self) -> Optional[str]:
|
|
43
|
+
return self._name
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_xml(cls, xml: ET.Element, ns: Optional[dict] = None) -> "LocationItem":
|
|
47
|
+
if ns is None:
|
|
48
|
+
ns = {}
|
|
49
|
+
location = cls()
|
|
50
|
+
location._id = xml.get("id", None)
|
|
51
|
+
location._type = xml.get("type", None)
|
|
52
|
+
location._name = xml.get("name", None)
|
|
53
|
+
return location
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
import xml.etree.ElementTree as ET
|
|
3
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional, overload
|
|
4
3
|
|
|
5
4
|
from defusedxml.ElementTree import fromstring
|
|
6
5
|
|
|
7
6
|
from tableauserverclient.models.exceptions import UnpopulatedPropertyError
|
|
8
|
-
from tableauserverclient.models.property_decorators import property_is_enum
|
|
7
|
+
from tableauserverclient.models.property_decorators import property_is_enum
|
|
8
|
+
from tableauserverclient.models.user_item import UserItem
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class ProjectItem:
|
|
@@ -39,12 +39,32 @@ class ProjectItem:
|
|
|
39
39
|
|
|
40
40
|
Attributes
|
|
41
41
|
----------
|
|
42
|
+
datasource_count : int
|
|
43
|
+
The number of data sources in the project.
|
|
44
|
+
|
|
42
45
|
id : str
|
|
43
46
|
The unique identifier for the project.
|
|
44
47
|
|
|
48
|
+
owner: Optional[UserItem]
|
|
49
|
+
The UserItem owner of the project.
|
|
50
|
+
|
|
45
51
|
owner_id : str
|
|
46
52
|
The unique identifier for the UserItem owner of the project.
|
|
47
53
|
|
|
54
|
+
project_count : int
|
|
55
|
+
The number of projects in the project.
|
|
56
|
+
|
|
57
|
+
top_level_project : bool
|
|
58
|
+
True if the project is a top-level project.
|
|
59
|
+
|
|
60
|
+
view_count : int
|
|
61
|
+
The number of views in the project.
|
|
62
|
+
|
|
63
|
+
workbook_count : int
|
|
64
|
+
The number of workbooks in the project.
|
|
65
|
+
|
|
66
|
+
writeable : bool
|
|
67
|
+
True if the project is writeable.
|
|
48
68
|
"""
|
|
49
69
|
|
|
50
70
|
ERROR_MSG = "Project item must be populated with permissions first."
|
|
@@ -75,6 +95,8 @@ class ProjectItem:
|
|
|
75
95
|
self.parent_id: Optional[str] = parent_id
|
|
76
96
|
self._samples: Optional[bool] = samples
|
|
77
97
|
self._owner_id: Optional[str] = None
|
|
98
|
+
self._top_level_project: Optional[bool] = None
|
|
99
|
+
self._writeable: Optional[bool] = None
|
|
78
100
|
|
|
79
101
|
self._permissions = None
|
|
80
102
|
self._default_workbook_permissions = None
|
|
@@ -87,6 +109,13 @@ class ProjectItem:
|
|
|
87
109
|
self._default_database_permissions = None
|
|
88
110
|
self._default_table_permissions = None
|
|
89
111
|
|
|
112
|
+
self._project_count: Optional[int] = None
|
|
113
|
+
self._workbook_count: Optional[int] = None
|
|
114
|
+
self._view_count: Optional[int] = None
|
|
115
|
+
self._datasource_count: Optional[int] = None
|
|
116
|
+
|
|
117
|
+
self._owner: Optional[UserItem] = None
|
|
118
|
+
|
|
90
119
|
@property
|
|
91
120
|
def content_permissions(self):
|
|
92
121
|
return self._content_permissions
|
|
@@ -176,25 +205,53 @@ class ProjectItem:
|
|
|
176
205
|
def owner_id(self, value: str) -> None:
|
|
177
206
|
self._owner_id = value
|
|
178
207
|
|
|
208
|
+
@property
|
|
209
|
+
def top_level_project(self) -> Optional[bool]:
|
|
210
|
+
return self._top_level_project
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def writeable(self) -> Optional[bool]:
|
|
214
|
+
return self._writeable
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def project_count(self) -> Optional[int]:
|
|
218
|
+
return self._project_count
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def workbook_count(self) -> Optional[int]:
|
|
222
|
+
return self._workbook_count
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def view_count(self) -> Optional[int]:
|
|
226
|
+
return self._view_count
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def datasource_count(self) -> Optional[int]:
|
|
230
|
+
return self._datasource_count
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def owner(self) -> Optional[UserItem]:
|
|
234
|
+
return self._owner
|
|
235
|
+
|
|
179
236
|
def is_default(self):
|
|
180
237
|
return self.name.lower() == "default"
|
|
181
238
|
|
|
182
|
-
def
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
239
|
+
def _set_values(
|
|
240
|
+
self,
|
|
241
|
+
project_id,
|
|
242
|
+
name,
|
|
243
|
+
description,
|
|
244
|
+
content_permissions,
|
|
245
|
+
parent_id,
|
|
246
|
+
owner_id,
|
|
247
|
+
top_level_project,
|
|
248
|
+
writeable,
|
|
249
|
+
project_count,
|
|
250
|
+
workbook_count,
|
|
251
|
+
view_count,
|
|
252
|
+
datasource_count,
|
|
253
|
+
owner,
|
|
254
|
+
):
|
|
198
255
|
if project_id is not None:
|
|
199
256
|
self._id = project_id
|
|
200
257
|
if name:
|
|
@@ -207,6 +264,20 @@ class ProjectItem:
|
|
|
207
264
|
self.parent_id = parent_id
|
|
208
265
|
if owner_id:
|
|
209
266
|
self._owner_id = owner_id
|
|
267
|
+
if project_count is not None:
|
|
268
|
+
self._project_count = project_count
|
|
269
|
+
if workbook_count is not None:
|
|
270
|
+
self._workbook_count = workbook_count
|
|
271
|
+
if view_count is not None:
|
|
272
|
+
self._view_count = view_count
|
|
273
|
+
if datasource_count is not None:
|
|
274
|
+
self._datasource_count = datasource_count
|
|
275
|
+
if top_level_project is not None:
|
|
276
|
+
self._top_level_project = top_level_project
|
|
277
|
+
if writeable is not None:
|
|
278
|
+
self._writeable = writeable
|
|
279
|
+
if owner is not None:
|
|
280
|
+
self._owner = owner
|
|
210
281
|
|
|
211
282
|
def _set_permissions(self, permissions):
|
|
212
283
|
self._permissions = permissions
|
|
@@ -220,31 +291,71 @@ class ProjectItem:
|
|
|
220
291
|
)
|
|
221
292
|
|
|
222
293
|
@classmethod
|
|
223
|
-
def from_response(cls, resp, ns) -> list["ProjectItem"]:
|
|
294
|
+
def from_response(cls, resp: bytes, ns: Optional[dict]) -> list["ProjectItem"]:
|
|
224
295
|
all_project_items = list()
|
|
225
296
|
parsed_response = fromstring(resp)
|
|
226
297
|
all_project_xml = parsed_response.findall(".//t:project", namespaces=ns)
|
|
227
298
|
|
|
228
299
|
for project_xml in all_project_xml:
|
|
229
|
-
project_item = cls.from_xml(project_xml)
|
|
300
|
+
project_item = cls.from_xml(project_xml, namespace=ns)
|
|
230
301
|
all_project_items.append(project_item)
|
|
231
302
|
return all_project_items
|
|
232
303
|
|
|
233
304
|
@classmethod
|
|
234
|
-
def from_xml(cls, project_xml, namespace=None) -> "ProjectItem":
|
|
305
|
+
def from_xml(cls, project_xml: ET.Element, namespace: Optional[dict] = None) -> "ProjectItem":
|
|
235
306
|
project_item = cls()
|
|
236
|
-
project_item._set_values(*cls._parse_element(project_xml))
|
|
307
|
+
project_item._set_values(*cls._parse_element(project_xml, namespace))
|
|
237
308
|
return project_item
|
|
238
309
|
|
|
239
310
|
@staticmethod
|
|
240
|
-
def _parse_element(project_xml):
|
|
311
|
+
def _parse_element(project_xml: ET.Element, namespace: Optional[dict]) -> tuple:
|
|
241
312
|
id = project_xml.get("id", None)
|
|
242
313
|
name = project_xml.get("name", None)
|
|
243
314
|
description = project_xml.get("description", None)
|
|
244
315
|
content_permissions = project_xml.get("contentPermissions", None)
|
|
245
316
|
parent_id = project_xml.get("parentProjectId", None)
|
|
317
|
+
top_level_project = str_to_bool(project_xml.get("topLevelProject", None))
|
|
318
|
+
writeable = str_to_bool(project_xml.get("writeable", None))
|
|
246
319
|
owner_id = None
|
|
247
|
-
|
|
248
|
-
|
|
320
|
+
owner = None
|
|
321
|
+
if (owner_elem := project_xml.find(".//t:owner", namespaces=namespace)) is not None:
|
|
322
|
+
owner = UserItem.from_xml(owner_elem, namespace)
|
|
323
|
+
owner_id = owner_elem.get("id", None)
|
|
324
|
+
|
|
325
|
+
project_count = None
|
|
326
|
+
workbook_count = None
|
|
327
|
+
view_count = None
|
|
328
|
+
datasource_count = None
|
|
329
|
+
if (count_elem := project_xml.find(".//t:contentsCounts", namespaces=namespace)) is not None:
|
|
330
|
+
project_count = int(count_elem.get("projectCount", 0))
|
|
331
|
+
workbook_count = int(count_elem.get("workbookCount", 0))
|
|
332
|
+
view_count = int(count_elem.get("viewCount", 0))
|
|
333
|
+
datasource_count = int(count_elem.get("dataSourceCount", 0))
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
id,
|
|
337
|
+
name,
|
|
338
|
+
description,
|
|
339
|
+
content_permissions,
|
|
340
|
+
parent_id,
|
|
341
|
+
owner_id,
|
|
342
|
+
top_level_project,
|
|
343
|
+
writeable,
|
|
344
|
+
project_count,
|
|
345
|
+
workbook_count,
|
|
346
|
+
view_count,
|
|
347
|
+
datasource_count,
|
|
348
|
+
owner,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
@overload
|
|
353
|
+
def str_to_bool(value: str) -> bool: ...
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@overload
|
|
357
|
+
def str_to_bool(value: None) -> None: ...
|
|
358
|
+
|
|
249
359
|
|
|
250
|
-
|
|
360
|
+
def str_to_bool(value):
|
|
361
|
+
return value.lower() == "true" if value is not None else None
|
|
@@ -20,6 +20,63 @@ Interval = Union[HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval]
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class ScheduleItem:
|
|
23
|
+
"""
|
|
24
|
+
Using the TSC library, you can schedule extract refresh or subscription
|
|
25
|
+
tasks on Tableau Server. You can also get and update information about the
|
|
26
|
+
scheduled tasks, or delete scheduled tasks.
|
|
27
|
+
|
|
28
|
+
If you have the identifier of the job, you can use the TSC library to find
|
|
29
|
+
out the status of the asynchronous job.
|
|
30
|
+
|
|
31
|
+
The schedule properties are defined in the ScheduleItem class. The class
|
|
32
|
+
corresponds to the properties for schedules you can access in Tableau
|
|
33
|
+
Server or by using the Tableau Server REST API. The Schedule methods are
|
|
34
|
+
based upon the endpoints for jobs in the REST API and operate on the JobItem
|
|
35
|
+
class.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
name : str
|
|
40
|
+
The name of the schedule.
|
|
41
|
+
|
|
42
|
+
priority : int
|
|
43
|
+
The priority of the schedule. Lower values represent higher priority,
|
|
44
|
+
with 0 indicating the highest priority.
|
|
45
|
+
|
|
46
|
+
schedule_type : str
|
|
47
|
+
The type of task schedule. See ScheduleItem.Type for the possible values.
|
|
48
|
+
|
|
49
|
+
execution_order : str
|
|
50
|
+
Specifies how the scheduled tasks should run. The choices are Parallel
|
|
51
|
+
which uses all avaiable background processes for a scheduled task, or
|
|
52
|
+
Serial, which limits the schedule to one background process.
|
|
53
|
+
|
|
54
|
+
interval_item : Interval
|
|
55
|
+
Specifies the frequency that the scheduled task should run. The
|
|
56
|
+
interval_item is an instance of the IntervalItem class. The
|
|
57
|
+
interval_item has properties for frequency (hourly, daily, weekly,
|
|
58
|
+
monthly), and what time and date the scheduled item runs. You set this
|
|
59
|
+
value by declaring an IntervalItem object that is one of the following:
|
|
60
|
+
HourlyInterval, DailyInterval, WeeklyInterval, or MonthlyInterval.
|
|
61
|
+
|
|
62
|
+
Attributes
|
|
63
|
+
----------
|
|
64
|
+
created_at : datetime
|
|
65
|
+
The date and time the schedule was created.
|
|
66
|
+
|
|
67
|
+
end_schedule_at : datetime
|
|
68
|
+
The date and time the schedule ends.
|
|
69
|
+
|
|
70
|
+
id : str
|
|
71
|
+
The unique identifier for the schedule.
|
|
72
|
+
|
|
73
|
+
next_run_at : datetime
|
|
74
|
+
The date and time the schedule is next run.
|
|
75
|
+
|
|
76
|
+
state : str
|
|
77
|
+
The state of the schedule. See ScheduleItem.State for the possible values.
|
|
78
|
+
"""
|
|
79
|
+
|
|
23
80
|
class Type:
|
|
24
81
|
Extract = "Extract"
|
|
25
82
|
Flow = "Flow"
|
|
@@ -1188,6 +1188,34 @@ class SiteItem:
|
|
|
1188
1188
|
)
|
|
1189
1189
|
|
|
1190
1190
|
|
|
1191
|
+
class SiteAuthConfiguration:
|
|
1192
|
+
"""
|
|
1193
|
+
Authentication configuration for a site.
|
|
1194
|
+
"""
|
|
1195
|
+
|
|
1196
|
+
def __init__(self):
|
|
1197
|
+
self.auth_setting: Optional[str] = None
|
|
1198
|
+
self.enabled: Optional[bool] = None
|
|
1199
|
+
self.idp_configuration_id: Optional[str] = None
|
|
1200
|
+
self.idp_configuration_name: Optional[str] = None
|
|
1201
|
+
self.known_provider_alias: Optional[str] = None
|
|
1202
|
+
|
|
1203
|
+
@classmethod
|
|
1204
|
+
def from_response(cls, resp: bytes, ns: dict) -> list["SiteAuthConfiguration"]:
|
|
1205
|
+
all_auth_configs = list()
|
|
1206
|
+
parsed_response = fromstring(resp)
|
|
1207
|
+
all_auth_xml = parsed_response.findall(".//t:siteAuthConfiguration", namespaces=ns)
|
|
1208
|
+
for auth_xml in all_auth_xml:
|
|
1209
|
+
auth_config = cls()
|
|
1210
|
+
auth_config.auth_setting = auth_xml.get("authSetting", None)
|
|
1211
|
+
auth_config.enabled = string_to_bool(auth_xml.get("enabled", ""))
|
|
1212
|
+
auth_config.idp_configuration_id = auth_xml.get("idpConfigurationId", None)
|
|
1213
|
+
auth_config.idp_configuration_name = auth_xml.get("idpConfigurationName", None)
|
|
1214
|
+
auth_config.known_provider_alias = auth_xml.get("knownProviderAlias", None)
|
|
1215
|
+
all_auth_configs.append(auth_config)
|
|
1216
|
+
return all_auth_configs
|
|
1217
|
+
|
|
1218
|
+
|
|
1191
1219
|
# Used to convert string represented boolean to a boolean type
|
|
1192
1220
|
def string_to_bool(s: str) -> bool:
|
|
1193
1221
|
return s.lower() == "true"
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
from typing import Callable, Optional, TYPE_CHECKING
|
|
1
2
|
from defusedxml.ElementTree import fromstring
|
|
2
3
|
|
|
3
4
|
from .exceptions import UnpopulatedPropertyError
|
|
4
5
|
from .property_decorators import property_not_empty, property_is_boolean
|
|
5
6
|
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from tableauserverclient.models import DQWItem
|
|
9
|
+
|
|
6
10
|
|
|
7
11
|
class TableItem:
|
|
8
12
|
def __init__(self, name, description=None):
|
|
@@ -40,7 +44,7 @@ class TableItem:
|
|
|
40
44
|
return self._data_quality_warnings()
|
|
41
45
|
|
|
42
46
|
@property
|
|
43
|
-
def id(self):
|
|
47
|
+
def id(self) -> Optional[str]:
|
|
44
48
|
return self._id
|
|
45
49
|
|
|
46
50
|
@property
|
|
@@ -100,8 +104,8 @@ class TableItem:
|
|
|
100
104
|
def _set_columns(self, columns):
|
|
101
105
|
self._columns = columns
|
|
102
106
|
|
|
103
|
-
def _set_data_quality_warnings(self,
|
|
104
|
-
self._data_quality_warnings =
|
|
107
|
+
def _set_data_quality_warnings(self, dqw: Callable[[], list["DQWItem"]]) -> None:
|
|
108
|
+
self._data_quality_warnings = dqw
|
|
105
109
|
|
|
106
110
|
def _set_values(self, table_values):
|
|
107
111
|
if "id" in table_values:
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from typing import Union
|
|
2
2
|
|
|
3
|
+
from tableauserverclient.models.database_item import DatabaseItem
|
|
3
4
|
from tableauserverclient.models.datasource_item import DatasourceItem
|
|
4
5
|
from tableauserverclient.models.flow_item import FlowItem
|
|
5
6
|
from tableauserverclient.models.project_item import ProjectItem
|
|
7
|
+
from tableauserverclient.models.table_item import TableItem
|
|
6
8
|
from tableauserverclient.models.view_item import ViewItem
|
|
7
9
|
from tableauserverclient.models.workbook_item import WorkbookItem
|
|
8
10
|
from tableauserverclient.models.metric_item import MetricItem
|
|
@@ -25,7 +27,17 @@ class Resource:
|
|
|
25
27
|
|
|
26
28
|
# resource types that have permissions, can be renamed, etc
|
|
27
29
|
# todo: refactoring: should actually define TableauItem as an interface and let all these implement it
|
|
28
|
-
TableauItem = Union[
|
|
30
|
+
TableauItem = Union[
|
|
31
|
+
DatasourceItem,
|
|
32
|
+
FlowItem,
|
|
33
|
+
MetricItem,
|
|
34
|
+
ProjectItem,
|
|
35
|
+
ViewItem,
|
|
36
|
+
WorkbookItem,
|
|
37
|
+
VirtualConnectionItem,
|
|
38
|
+
DatabaseItem,
|
|
39
|
+
TableItem,
|
|
40
|
+
]
|
|
29
41
|
|
|
30
42
|
|
|
31
43
|
def plural_type(content_type: Union[Resource, str]) -> str:
|