tableauserverclient 0.37__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 +4 -0
- tableauserverclient/bin/_version.py +3 -3
- tableauserverclient/helpers/strings.py +25 -1
- tableauserverclient/models/__init__.py +6 -1
- tableauserverclient/models/datasource_item.py +110 -2
- 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/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/endpoint/databases_endpoint.py +101 -18
- tableauserverclient/server/endpoint/datasources_endpoint.py +3 -3
- tableauserverclient/server/endpoint/dqw_endpoint.py +16 -6
- tableauserverclient/server/endpoint/endpoint.py +39 -0
- 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/query.py +36 -0
- tableauserverclient/server/request_factory.py +5 -0
- tableauserverclient/server/request_options.py +128 -2
- tableauserverclient/server/server.py +42 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/METADATA +1 -1
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/RECORD +36 -34
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/WHEEL +1 -1
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/licenses/LICENSE +0 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/licenses/LICENSE.versioneer +0 -0
- {tableauserverclient-0.37.dist-info → tableauserverclient-0.38.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
from requests import Response
|
|
4
|
-
from typing import Callable, Optional
|
|
4
|
+
from typing import TYPE_CHECKING, Callable, Optional, overload
|
|
5
5
|
from collections.abc import Iterator
|
|
6
6
|
|
|
7
7
|
from defusedxml.ElementTree import fromstring
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
10
10
|
from tableauserverclient.models.exceptions import UnpopulatedPropertyError
|
|
11
|
+
from tableauserverclient.models.location_item import LocationItem
|
|
11
12
|
from tableauserverclient.models.permissions_item import PermissionsRule
|
|
13
|
+
from tableauserverclient.models.project_item import ProjectItem
|
|
12
14
|
from tableauserverclient.models.tag_item import TagItem
|
|
15
|
+
from tableauserverclient.models.user_item import UserItem
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from tableauserverclient.models.workbook_item import WorkbookItem
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
class ViewItem:
|
|
@@ -34,9 +40,16 @@ class ViewItem:
|
|
|
34
40
|
The image of the view. You must first call the `views.populate_image`
|
|
35
41
|
method to access the image.
|
|
36
42
|
|
|
43
|
+
location: Optional[LocationItem], default None
|
|
44
|
+
The location of the view. The location can be a personal space or a
|
|
45
|
+
project.
|
|
46
|
+
|
|
37
47
|
name: Optional[str], default None
|
|
38
48
|
The name of the view.
|
|
39
49
|
|
|
50
|
+
owner: Optional[UserItem], default None
|
|
51
|
+
The owner of the view.
|
|
52
|
+
|
|
40
53
|
owner_id: Optional[str], default None
|
|
41
54
|
The ID for the owner of the view.
|
|
42
55
|
|
|
@@ -48,6 +61,9 @@ class ViewItem:
|
|
|
48
61
|
The preview image of the view. You must first call the
|
|
49
62
|
`views.populate_preview_image` method to access the preview image.
|
|
50
63
|
|
|
64
|
+
project: Optional[ProjectItem], default None
|
|
65
|
+
The project that contains the view.
|
|
66
|
+
|
|
51
67
|
project_id: Optional[str], default None
|
|
52
68
|
The ID for the project that contains the view.
|
|
53
69
|
|
|
@@ -60,9 +76,11 @@ class ViewItem:
|
|
|
60
76
|
updated_at: Optional[datetime], default None
|
|
61
77
|
The date and time when the view was last updated.
|
|
62
78
|
|
|
79
|
+
workbook: Optional[WorkbookItem], default None
|
|
80
|
+
The workbook that contains the view.
|
|
81
|
+
|
|
63
82
|
workbook_id: Optional[str], default None
|
|
64
83
|
The ID for the workbook that contains the view.
|
|
65
|
-
|
|
66
84
|
"""
|
|
67
85
|
|
|
68
86
|
def __init__(self) -> None:
|
|
@@ -84,11 +102,18 @@ class ViewItem:
|
|
|
84
102
|
self._workbook_id: Optional[str] = None
|
|
85
103
|
self._permissions: Optional[Callable[[], list[PermissionsRule]]] = None
|
|
86
104
|
self.tags: set[str] = set()
|
|
105
|
+
self._favorites_total: Optional[int] = None
|
|
106
|
+
self._view_url_name: Optional[str] = None
|
|
87
107
|
self._data_acceleration_config = {
|
|
88
108
|
"acceleration_enabled": None,
|
|
89
109
|
"acceleration_status": None,
|
|
90
110
|
}
|
|
91
111
|
|
|
112
|
+
self._owner: Optional[UserItem] = None
|
|
113
|
+
self._project: Optional[ProjectItem] = None
|
|
114
|
+
self._workbook: Optional["WorkbookItem"] = None
|
|
115
|
+
self._location: Optional[LocationItem] = None
|
|
116
|
+
|
|
92
117
|
def __str__(self):
|
|
93
118
|
return "<ViewItem {} '{}' contentUrl='{}' project={}>".format(
|
|
94
119
|
self._id, self.name, self.content_url, self.project_id
|
|
@@ -190,6 +215,14 @@ class ViewItem:
|
|
|
190
215
|
def workbook_id(self) -> Optional[str]:
|
|
191
216
|
return self._workbook_id
|
|
192
217
|
|
|
218
|
+
@property
|
|
219
|
+
def view_url_name(self) -> Optional[str]:
|
|
220
|
+
return self._view_url_name
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def favorites_total(self) -> Optional[int]:
|
|
224
|
+
return self._favorites_total
|
|
225
|
+
|
|
193
226
|
@property
|
|
194
227
|
def data_acceleration_config(self):
|
|
195
228
|
return self._data_acceleration_config
|
|
@@ -198,6 +231,22 @@ class ViewItem:
|
|
|
198
231
|
def data_acceleration_config(self, value):
|
|
199
232
|
self._data_acceleration_config = value
|
|
200
233
|
|
|
234
|
+
@property
|
|
235
|
+
def project(self) -> Optional["ProjectItem"]:
|
|
236
|
+
return self._project
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def workbook(self) -> Optional["WorkbookItem"]:
|
|
240
|
+
return self._workbook
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def owner(self) -> Optional[UserItem]:
|
|
244
|
+
return self._owner
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def location(self) -> Optional[LocationItem]:
|
|
248
|
+
return self._location
|
|
249
|
+
|
|
201
250
|
@property
|
|
202
251
|
def permissions(self) -> list[PermissionsRule]:
|
|
203
252
|
if self._permissions is None:
|
|
@@ -228,7 +277,7 @@ class ViewItem:
|
|
|
228
277
|
workbook_elem = view_xml.find(".//t:workbook", namespaces=ns)
|
|
229
278
|
owner_elem = view_xml.find(".//t:owner", namespaces=ns)
|
|
230
279
|
project_elem = view_xml.find(".//t:project", namespaces=ns)
|
|
231
|
-
tags_elem = view_xml.find("
|
|
280
|
+
tags_elem = view_xml.find("./t:tags", namespaces=ns)
|
|
232
281
|
data_acceleration_config_elem = view_xml.find(".//t:dataAccelerationConfig", namespaces=ns)
|
|
233
282
|
view_item._created_at = parse_datetime(view_xml.get("createdAt", None))
|
|
234
283
|
view_item._updated_at = parse_datetime(view_xml.get("updatedAt", None))
|
|
@@ -236,22 +285,35 @@ class ViewItem:
|
|
|
236
285
|
view_item._name = view_xml.get("name", None)
|
|
237
286
|
view_item._content_url = view_xml.get("contentUrl", None)
|
|
238
287
|
view_item._sheet_type = view_xml.get("sheetType", None)
|
|
288
|
+
view_item._favorites_total = string_to_int(view_xml.get("favoritesTotal", None))
|
|
289
|
+
view_item._view_url_name = view_xml.get("viewUrlName", None)
|
|
239
290
|
if usage_elem is not None:
|
|
240
291
|
total_view = usage_elem.get("totalViewCount", None)
|
|
241
292
|
if total_view:
|
|
242
293
|
view_item._total_views = int(total_view)
|
|
243
294
|
if owner_elem is not None:
|
|
295
|
+
user = UserItem.from_xml(owner_elem, ns)
|
|
296
|
+
view_item._owner = user
|
|
244
297
|
view_item._owner_id = owner_elem.get("id", None)
|
|
245
298
|
if project_elem is not None:
|
|
246
|
-
|
|
299
|
+
project_item = ProjectItem.from_xml(project_elem, ns)
|
|
300
|
+
view_item._project = project_item
|
|
301
|
+
view_item._project_id = project_item.id
|
|
247
302
|
if workbook_id:
|
|
248
303
|
view_item._workbook_id = workbook_id
|
|
249
304
|
elif workbook_elem is not None:
|
|
250
|
-
|
|
305
|
+
from tableauserverclient.models.workbook_item import WorkbookItem
|
|
306
|
+
|
|
307
|
+
workbook_item = WorkbookItem.from_xml(workbook_elem, ns)
|
|
308
|
+
view_item._workbook = workbook_item
|
|
309
|
+
view_item._workbook_id = workbook_item.id
|
|
251
310
|
if tags_elem is not None:
|
|
252
311
|
tags = TagItem.from_xml_element(tags_elem, ns)
|
|
253
312
|
view_item.tags = tags
|
|
254
313
|
view_item._initial_tags = copy.copy(tags)
|
|
314
|
+
if (location_elem := view_xml.find(".//t:location", namespaces=ns)) is not None:
|
|
315
|
+
location = LocationItem.from_xml(location_elem, ns)
|
|
316
|
+
view_item._location = location
|
|
255
317
|
if data_acceleration_config_elem is not None:
|
|
256
318
|
data_acceleration_config = parse_data_acceleration_config(data_acceleration_config_elem)
|
|
257
319
|
view_item.data_acceleration_config = data_acceleration_config
|
|
@@ -274,3 +336,15 @@ def parse_data_acceleration_config(data_acceleration_elem):
|
|
|
274
336
|
|
|
275
337
|
def string_to_bool(s: str) -> bool:
|
|
276
338
|
return s.lower() == "true"
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@overload
|
|
342
|
+
def string_to_int(s: None) -> None: ...
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@overload
|
|
346
|
+
def string_to_int(s: str) -> int: ...
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def string_to_int(s):
|
|
350
|
+
return int(s) if s is not None else None
|
|
@@ -2,11 +2,14 @@ import copy
|
|
|
2
2
|
import datetime
|
|
3
3
|
import uuid
|
|
4
4
|
import xml.etree.ElementTree as ET
|
|
5
|
-
from typing import Callable, Optional
|
|
5
|
+
from typing import Callable, Optional, overload
|
|
6
6
|
|
|
7
7
|
from defusedxml.ElementTree import fromstring
|
|
8
8
|
|
|
9
9
|
from tableauserverclient.datetime_helpers import parse_datetime
|
|
10
|
+
from tableauserverclient.models.location_item import LocationItem
|
|
11
|
+
from tableauserverclient.models.project_item import ProjectItem
|
|
12
|
+
from tableauserverclient.models.user_item import UserItem
|
|
10
13
|
from .connection_item import ConnectionItem
|
|
11
14
|
from .exceptions import UnpopulatedPropertyError
|
|
12
15
|
from .permissions_item import PermissionsRule
|
|
@@ -51,13 +54,31 @@ class WorkbookItem:
|
|
|
51
54
|
created_at : Optional[datetime.datetime]
|
|
52
55
|
The date and time the workbook was created.
|
|
53
56
|
|
|
57
|
+
default_view_id : Optional[str]
|
|
58
|
+
The identifier for the default view of the workbook.
|
|
59
|
+
|
|
54
60
|
description : Optional[str]
|
|
55
61
|
User-defined description of the workbook.
|
|
56
62
|
|
|
63
|
+
encrypt_extracts : Optional[bool]
|
|
64
|
+
Indicates whether extracts are encrypted.
|
|
65
|
+
|
|
66
|
+
has_extracts : Optional[bool]
|
|
67
|
+
Indicates whether the workbook has extracts.
|
|
68
|
+
|
|
57
69
|
id : Optional[str]
|
|
58
70
|
The identifier for the workbook. You need this value to query a specific
|
|
59
71
|
workbook or to delete a workbook with the get_by_id and delete methods.
|
|
60
72
|
|
|
73
|
+
last_published_at : Optional[datetime.datetime]
|
|
74
|
+
The date and time the workbook was last published.
|
|
75
|
+
|
|
76
|
+
location : Optional[LocationItem]
|
|
77
|
+
The location of the workbook, such as a personal space or project.
|
|
78
|
+
|
|
79
|
+
owner : Optional[UserItem]
|
|
80
|
+
The owner of the workbook.
|
|
81
|
+
|
|
61
82
|
owner_id : Optional[str]
|
|
62
83
|
The identifier for the owner (UserItem) of the workbook.
|
|
63
84
|
|
|
@@ -65,6 +86,9 @@ class WorkbookItem:
|
|
|
65
86
|
The thumbnail image for the view. You must first call the
|
|
66
87
|
workbooks.populate_preview_image method to access this data.
|
|
67
88
|
|
|
89
|
+
project: Optional[ProjectItem]
|
|
90
|
+
The project that contains the workbook.
|
|
91
|
+
|
|
68
92
|
project_name : Optional[str]
|
|
69
93
|
The name of the project that contains the workbook.
|
|
70
94
|
|
|
@@ -139,6 +163,15 @@ class WorkbookItem:
|
|
|
139
163
|
self._permissions = None
|
|
140
164
|
self.thumbnails_user_id = thumbnails_user_id
|
|
141
165
|
self.thumbnails_group_id = thumbnails_group_id
|
|
166
|
+
self._sheet_count: Optional[int] = None
|
|
167
|
+
self._has_extracts: Optional[bool] = None
|
|
168
|
+
self._project: Optional[ProjectItem] = None
|
|
169
|
+
self._owner: Optional[UserItem] = None
|
|
170
|
+
self._location: Optional[LocationItem] = None
|
|
171
|
+
self._encrypt_extracts: Optional[bool] = None
|
|
172
|
+
self._default_view_id: Optional[str] = None
|
|
173
|
+
self._share_description: Optional[str] = None
|
|
174
|
+
self._last_published_at: Optional[datetime.datetime] = None
|
|
142
175
|
|
|
143
176
|
return None
|
|
144
177
|
|
|
@@ -234,6 +267,14 @@ class WorkbookItem:
|
|
|
234
267
|
def size(self):
|
|
235
268
|
return self._size
|
|
236
269
|
|
|
270
|
+
@property
|
|
271
|
+
def sheet_count(self) -> Optional[int]:
|
|
272
|
+
return self._sheet_count
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def has_extracts(self) -> Optional[bool]:
|
|
276
|
+
return self._has_extracts
|
|
277
|
+
|
|
237
278
|
@property
|
|
238
279
|
def updated_at(self) -> Optional[datetime.datetime]:
|
|
239
280
|
return self._updated_at
|
|
@@ -300,6 +341,34 @@ class WorkbookItem:
|
|
|
300
341
|
def thumbnails_group_id(self, value: str):
|
|
301
342
|
self._thumbnails_group_id = value
|
|
302
343
|
|
|
344
|
+
@property
|
|
345
|
+
def project(self) -> Optional[ProjectItem]:
|
|
346
|
+
return self._project
|
|
347
|
+
|
|
348
|
+
@property
|
|
349
|
+
def owner(self) -> Optional[UserItem]:
|
|
350
|
+
return self._owner
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
def location(self) -> Optional[LocationItem]:
|
|
354
|
+
return self._location
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def encrypt_extracts(self) -> Optional[bool]:
|
|
358
|
+
return self._encrypt_extracts
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
def default_view_id(self) -> Optional[str]:
|
|
362
|
+
return self._default_view_id
|
|
363
|
+
|
|
364
|
+
@property
|
|
365
|
+
def share_description(self) -> Optional[str]:
|
|
366
|
+
return self._share_description
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def last_published_at(self) -> Optional[datetime.datetime]:
|
|
370
|
+
return self._last_published_at
|
|
371
|
+
|
|
303
372
|
def _set_connections(self, connections):
|
|
304
373
|
self._connections = connections
|
|
305
374
|
|
|
@@ -342,6 +411,15 @@ class WorkbookItem:
|
|
|
342
411
|
views,
|
|
343
412
|
data_acceleration_config,
|
|
344
413
|
data_freshness_policy,
|
|
414
|
+
sheet_count,
|
|
415
|
+
has_extracts,
|
|
416
|
+
project,
|
|
417
|
+
owner,
|
|
418
|
+
location,
|
|
419
|
+
encrypt_extracts,
|
|
420
|
+
default_view_id,
|
|
421
|
+
share_description,
|
|
422
|
+
last_published_at,
|
|
345
423
|
) = self._parse_element(workbook_xml, ns)
|
|
346
424
|
|
|
347
425
|
self._set_values(
|
|
@@ -361,6 +439,15 @@ class WorkbookItem:
|
|
|
361
439
|
views,
|
|
362
440
|
data_acceleration_config,
|
|
363
441
|
data_freshness_policy,
|
|
442
|
+
sheet_count,
|
|
443
|
+
has_extracts,
|
|
444
|
+
project,
|
|
445
|
+
owner,
|
|
446
|
+
location,
|
|
447
|
+
encrypt_extracts,
|
|
448
|
+
default_view_id,
|
|
449
|
+
share_description,
|
|
450
|
+
last_published_at,
|
|
364
451
|
)
|
|
365
452
|
|
|
366
453
|
return self
|
|
@@ -383,6 +470,15 @@ class WorkbookItem:
|
|
|
383
470
|
views,
|
|
384
471
|
data_acceleration_config,
|
|
385
472
|
data_freshness_policy,
|
|
473
|
+
sheet_count,
|
|
474
|
+
has_extracts,
|
|
475
|
+
project,
|
|
476
|
+
owner,
|
|
477
|
+
location,
|
|
478
|
+
encrypt_extracts,
|
|
479
|
+
default_view_id,
|
|
480
|
+
share_description,
|
|
481
|
+
last_published_at,
|
|
386
482
|
):
|
|
387
483
|
if id is not None:
|
|
388
484
|
self._id = id
|
|
@@ -417,6 +513,24 @@ class WorkbookItem:
|
|
|
417
513
|
self.data_acceleration_config = data_acceleration_config
|
|
418
514
|
if data_freshness_policy is not None:
|
|
419
515
|
self.data_freshness_policy = data_freshness_policy
|
|
516
|
+
if sheet_count is not None:
|
|
517
|
+
self._sheet_count = sheet_count
|
|
518
|
+
if has_extracts is not None:
|
|
519
|
+
self._has_extracts = has_extracts
|
|
520
|
+
if project:
|
|
521
|
+
self._project = project
|
|
522
|
+
if owner:
|
|
523
|
+
self._owner = owner
|
|
524
|
+
if location:
|
|
525
|
+
self._location = location
|
|
526
|
+
if encrypt_extracts is not None:
|
|
527
|
+
self._encrypt_extracts = encrypt_extracts
|
|
528
|
+
if default_view_id is not None:
|
|
529
|
+
self._default_view_id = default_view_id
|
|
530
|
+
if share_description is not None:
|
|
531
|
+
self._share_description = share_description
|
|
532
|
+
if last_published_at is not None:
|
|
533
|
+
self._last_published_at = last_published_at
|
|
420
534
|
|
|
421
535
|
@classmethod
|
|
422
536
|
def from_response(cls, resp: str, ns: dict[str, str]) -> list["WorkbookItem"]:
|
|
@@ -443,6 +557,12 @@ class WorkbookItem:
|
|
|
443
557
|
created_at = parse_datetime(workbook_xml.get("createdAt", None))
|
|
444
558
|
description = workbook_xml.get("description", None)
|
|
445
559
|
updated_at = parse_datetime(workbook_xml.get("updatedAt", None))
|
|
560
|
+
sheet_count = string_to_int(workbook_xml.get("sheetCount", None))
|
|
561
|
+
has_extracts = string_to_bool(workbook_xml.get("hasExtracts", ""))
|
|
562
|
+
encrypt_extracts = string_to_bool(e) if (e := workbook_xml.get("encryptExtracts", None)) is not None else None
|
|
563
|
+
default_view_id = workbook_xml.get("defaultViewId", None)
|
|
564
|
+
share_description = workbook_xml.get("shareDescription", None)
|
|
565
|
+
last_published_at = parse_datetime(workbook_xml.get("lastPublishedAt", None))
|
|
446
566
|
|
|
447
567
|
size = workbook_xml.get("size", None)
|
|
448
568
|
if size:
|
|
@@ -452,14 +572,18 @@ class WorkbookItem:
|
|
|
452
572
|
|
|
453
573
|
project_id = None
|
|
454
574
|
project_name = None
|
|
575
|
+
project = None
|
|
455
576
|
project_tag = workbook_xml.find(".//t:project", namespaces=ns)
|
|
456
577
|
if project_tag is not None:
|
|
578
|
+
project = ProjectItem.from_xml(project_tag, ns)
|
|
457
579
|
project_id = project_tag.get("id", None)
|
|
458
580
|
project_name = project_tag.get("name", None)
|
|
459
581
|
|
|
460
582
|
owner_id = None
|
|
583
|
+
owner = None
|
|
461
584
|
owner_tag = workbook_xml.find(".//t:owner", namespaces=ns)
|
|
462
585
|
if owner_tag is not None:
|
|
586
|
+
owner = UserItem.from_xml(owner_tag, ns)
|
|
463
587
|
owner_id = owner_tag.get("id", None)
|
|
464
588
|
|
|
465
589
|
tags = None
|
|
@@ -473,6 +597,11 @@ class WorkbookItem:
|
|
|
473
597
|
if views_elem is not None:
|
|
474
598
|
views = ViewItem.from_xml_element(views_elem, ns)
|
|
475
599
|
|
|
600
|
+
location = None
|
|
601
|
+
location_elem = workbook_xml.find(".//t:location", namespaces=ns)
|
|
602
|
+
if location_elem is not None:
|
|
603
|
+
location = LocationItem.from_xml(location_elem, ns)
|
|
604
|
+
|
|
476
605
|
data_acceleration_config = {
|
|
477
606
|
"acceleration_enabled": None,
|
|
478
607
|
"accelerate_now": None,
|
|
@@ -505,6 +634,15 @@ class WorkbookItem:
|
|
|
505
634
|
views,
|
|
506
635
|
data_acceleration_config,
|
|
507
636
|
data_freshness_policy,
|
|
637
|
+
sheet_count,
|
|
638
|
+
has_extracts,
|
|
639
|
+
project,
|
|
640
|
+
owner,
|
|
641
|
+
location,
|
|
642
|
+
encrypt_extracts,
|
|
643
|
+
default_view_id,
|
|
644
|
+
share_description,
|
|
645
|
+
last_published_at,
|
|
508
646
|
)
|
|
509
647
|
|
|
510
648
|
|
|
@@ -535,3 +673,15 @@ def parse_data_acceleration_config(data_acceleration_elem):
|
|
|
535
673
|
# Used to convert string represented boolean to a boolean type
|
|
536
674
|
def string_to_bool(s: str) -> bool:
|
|
537
675
|
return s.lower() == "true"
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
@overload
|
|
679
|
+
def string_to_int(s: None) -> None: ...
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
@overload
|
|
683
|
+
def string_to_int(s: str) -> int: ...
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
def string_to_int(s):
|
|
687
|
+
return int(s) if s is not None else None
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Union
|
|
2
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
3
3
|
from collections.abc import Iterable
|
|
4
4
|
|
|
5
|
+
from tableauserverclient.models.permissions_item import PermissionsRule
|
|
5
6
|
from tableauserverclient.server.endpoint.default_permissions_endpoint import _DefaultPermissionsEndpoint
|
|
6
7
|
from tableauserverclient.server.endpoint.dqw_endpoint import _DataQualityWarningEndpoint
|
|
7
8
|
from tableauserverclient.server.endpoint.endpoint import api, Endpoint
|
|
@@ -13,6 +14,10 @@ from tableauserverclient.models import DatabaseItem, TableItem, PaginationItem,
|
|
|
13
14
|
|
|
14
15
|
from tableauserverclient.helpers.logging import logger
|
|
15
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from tableauserverclient.models.dqw_item import DQWItem
|
|
19
|
+
from tableauserverclient.server.request_options import RequestOptions
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
class Databases(Endpoint, TaggingMixin):
|
|
18
23
|
def __init__(self, parent_srv):
|
|
@@ -23,11 +28,29 @@ class Databases(Endpoint, TaggingMixin):
|
|
|
23
28
|
self._data_quality_warnings = _DataQualityWarningEndpoint(parent_srv, Resource.Database)
|
|
24
29
|
|
|
25
30
|
@property
|
|
26
|
-
def baseurl(self):
|
|
31
|
+
def baseurl(self) -> str:
|
|
27
32
|
return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/databases"
|
|
28
33
|
|
|
29
34
|
@api(version="3.5")
|
|
30
|
-
def get(self, req_options=None):
|
|
35
|
+
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[DatabaseItem], PaginationItem]:
|
|
36
|
+
"""
|
|
37
|
+
Get information about all databases on the site. Endpoint is paginated,
|
|
38
|
+
and will return a default of 100 items per page. Use the `req_options`
|
|
39
|
+
parameter to customize the request.
|
|
40
|
+
|
|
41
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_databases
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
req_options : RequestOptions, optional
|
|
46
|
+
Options to customize the request. If not provided, defaults to None.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
tuple[list[DatabaseItem], PaginationItem]
|
|
51
|
+
A tuple containing a list of DatabaseItem objects and a
|
|
52
|
+
PaginationItem object.
|
|
53
|
+
"""
|
|
31
54
|
logger.info("Querying all databases on site")
|
|
32
55
|
url = self.baseurl
|
|
33
56
|
server_response = self.get_request(url, req_options)
|
|
@@ -37,7 +60,27 @@ class Databases(Endpoint, TaggingMixin):
|
|
|
37
60
|
|
|
38
61
|
# Get 1 database
|
|
39
62
|
@api(version="3.5")
|
|
40
|
-
def get_by_id(self, database_id):
|
|
63
|
+
def get_by_id(self, database_id: str) -> DatabaseItem:
|
|
64
|
+
"""
|
|
65
|
+
Get information about a single database asset on the site.
|
|
66
|
+
|
|
67
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_database
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
database_id : str
|
|
72
|
+
The ID of the database to retrieve.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
DatabaseItem
|
|
77
|
+
A DatabaseItem object representing the database.
|
|
78
|
+
|
|
79
|
+
Raises
|
|
80
|
+
------
|
|
81
|
+
ValueError
|
|
82
|
+
If the database ID is undefined.
|
|
83
|
+
"""
|
|
41
84
|
if not database_id:
|
|
42
85
|
error = "database ID undefined."
|
|
43
86
|
raise ValueError(error)
|
|
@@ -47,7 +90,24 @@ class Databases(Endpoint, TaggingMixin):
|
|
|
47
90
|
return DatabaseItem.from_response(server_response.content, self.parent_srv.namespace)[0]
|
|
48
91
|
|
|
49
92
|
@api(version="3.5")
|
|
50
|
-
def delete(self, database_id):
|
|
93
|
+
def delete(self, database_id: str) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Deletes a single database asset from the server.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
database_id : str
|
|
100
|
+
The ID of the database to delete.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
None
|
|
105
|
+
|
|
106
|
+
Raises
|
|
107
|
+
------
|
|
108
|
+
ValueError
|
|
109
|
+
If the database ID is undefined.
|
|
110
|
+
"""
|
|
51
111
|
if not database_id:
|
|
52
112
|
error = "Database ID undefined."
|
|
53
113
|
raise ValueError(error)
|
|
@@ -56,7 +116,28 @@ class Databases(Endpoint, TaggingMixin):
|
|
|
56
116
|
logger.info(f"Deleted single database (ID: {database_id})")
|
|
57
117
|
|
|
58
118
|
@api(version="3.5")
|
|
59
|
-
def update(self, database_item):
|
|
119
|
+
def update(self, database_item: DatabaseItem) -> DatabaseItem:
|
|
120
|
+
"""
|
|
121
|
+
Update the database description, certify the database, set permissions,
|
|
122
|
+
or assign a User as the database contact.
|
|
123
|
+
|
|
124
|
+
REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#update_database
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
database_item : DatabaseItem
|
|
129
|
+
The DatabaseItem object to update.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
DatabaseItem
|
|
134
|
+
The updated DatabaseItem object.
|
|
135
|
+
|
|
136
|
+
Raises
|
|
137
|
+
------
|
|
138
|
+
MissingRequiredFieldError
|
|
139
|
+
If the database item is missing an ID.
|
|
140
|
+
"""
|
|
60
141
|
if not database_item.id:
|
|
61
142
|
error = "Database item missing ID."
|
|
62
143
|
raise MissingRequiredFieldError(error)
|
|
@@ -88,43 +169,45 @@ class Databases(Endpoint, TaggingMixin):
|
|
|
88
169
|
return tables
|
|
89
170
|
|
|
90
171
|
@api(version="3.5")
|
|
91
|
-
def populate_permissions(self, item):
|
|
172
|
+
def populate_permissions(self, item: DatabaseItem) -> None:
|
|
92
173
|
self._permissions.populate(item)
|
|
93
174
|
|
|
94
175
|
@api(version="3.5")
|
|
95
|
-
def update_permissions(self, item, rules):
|
|
176
|
+
def update_permissions(self, item: DatabaseItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
|
|
96
177
|
return self._permissions.update(item, rules)
|
|
97
178
|
|
|
98
179
|
@api(version="3.5")
|
|
99
|
-
def delete_permission(self, item, rules):
|
|
180
|
+
def delete_permission(self, item: DatabaseItem, rules: list[PermissionsRule]) -> None:
|
|
100
181
|
self._permissions.delete(item, rules)
|
|
101
182
|
|
|
102
183
|
@api(version="3.5")
|
|
103
|
-
def populate_table_default_permissions(self, item):
|
|
184
|
+
def populate_table_default_permissions(self, item: DatabaseItem):
|
|
104
185
|
self._default_permissions.populate_default_permissions(item, Resource.Table)
|
|
105
186
|
|
|
106
187
|
@api(version="3.5")
|
|
107
|
-
def update_table_default_permissions(
|
|
108
|
-
|
|
188
|
+
def update_table_default_permissions(
|
|
189
|
+
self, item: DatabaseItem, rules: list[PermissionsRule]
|
|
190
|
+
) -> list[PermissionsRule]:
|
|
191
|
+
return self._default_permissions.update_default_permissions(item, rules, Resource.Table)
|
|
109
192
|
|
|
110
193
|
@api(version="3.5")
|
|
111
|
-
def delete_table_default_permissions(self, item):
|
|
112
|
-
self._default_permissions.delete_default_permission(item, Resource.Table)
|
|
194
|
+
def delete_table_default_permissions(self, rule: PermissionsRule, item: DatabaseItem) -> None:
|
|
195
|
+
self._default_permissions.delete_default_permission(item, rule, Resource.Table)
|
|
113
196
|
|
|
114
197
|
@api(version="3.5")
|
|
115
|
-
def populate_dqw(self, item):
|
|
198
|
+
def populate_dqw(self, item: DatabaseItem) -> None:
|
|
116
199
|
self._data_quality_warnings.populate(item)
|
|
117
200
|
|
|
118
201
|
@api(version="3.5")
|
|
119
|
-
def update_dqw(self, item, warning):
|
|
202
|
+
def update_dqw(self, item: DatabaseItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
120
203
|
return self._data_quality_warnings.update(item, warning)
|
|
121
204
|
|
|
122
205
|
@api(version="3.5")
|
|
123
|
-
def add_dqw(self, item, warning):
|
|
206
|
+
def add_dqw(self, item: DatabaseItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
124
207
|
return self._data_quality_warnings.add(item, warning)
|
|
125
208
|
|
|
126
209
|
@api(version="3.5")
|
|
127
|
-
def delete_dqw(self, item):
|
|
210
|
+
def delete_dqw(self, item: DatabaseItem) -> None:
|
|
128
211
|
self._data_quality_warnings.clear(item)
|
|
129
212
|
|
|
130
213
|
@api(version="3.9")
|
|
@@ -733,7 +733,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
733
733
|
self._data_quality_warnings.populate(item)
|
|
734
734
|
|
|
735
735
|
@api(version="3.5")
|
|
736
|
-
def update_dqw(self, item, warning):
|
|
736
|
+
def update_dqw(self, item: DatasourceItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
737
737
|
"""
|
|
738
738
|
Update the warning type, status, and message of a data quality warning.
|
|
739
739
|
|
|
@@ -755,7 +755,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
755
755
|
return self._data_quality_warnings.update(item, warning)
|
|
756
756
|
|
|
757
757
|
@api(version="3.5")
|
|
758
|
-
def add_dqw(self, item, warning):
|
|
758
|
+
def add_dqw(self, item: DatasourceItem, warning: "DQWItem") -> list["DQWItem"]:
|
|
759
759
|
"""
|
|
760
760
|
Add a data quality warning to a datasource.
|
|
761
761
|
|
|
@@ -786,7 +786,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
|
|
|
786
786
|
return self._data_quality_warnings.add(item, warning)
|
|
787
787
|
|
|
788
788
|
@api(version="3.5")
|
|
789
|
-
def delete_dqw(self, item):
|
|
789
|
+
def delete_dqw(self, item: DatasourceItem) -> None:
|
|
790
790
|
"""
|
|
791
791
|
Delete a data quality warnings from an asset.
|
|
792
792
|
|