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.
Files changed (45) hide show
  1. tableauserverclient/__init__.py +6 -0
  2. tableauserverclient/bin/_version.py +3 -3
  3. tableauserverclient/helpers/strings.py +25 -1
  4. tableauserverclient/models/__init__.py +6 -1
  5. tableauserverclient/models/connection_item.py +3 -3
  6. tableauserverclient/models/datasource_item.py +218 -23
  7. tableauserverclient/models/extract_item.py +82 -0
  8. tableauserverclient/models/flow_item.py +2 -2
  9. tableauserverclient/models/group_item.py +11 -0
  10. tableauserverclient/models/interval_item.py +40 -0
  11. tableauserverclient/models/job_item.py +1 -0
  12. tableauserverclient/models/location_item.py +53 -0
  13. tableauserverclient/models/project_item.py +138 -27
  14. tableauserverclient/models/schedule_item.py +57 -0
  15. tableauserverclient/models/site_item.py +28 -0
  16. tableauserverclient/models/table_item.py +7 -3
  17. tableauserverclient/models/tableau_types.py +13 -1
  18. tableauserverclient/models/user_item.py +101 -1
  19. tableauserverclient/models/view_item.py +79 -5
  20. tableauserverclient/models/workbook_item.py +151 -1
  21. tableauserverclient/server/__init__.py +2 -0
  22. tableauserverclient/server/endpoint/databases_endpoint.py +101 -18
  23. tableauserverclient/server/endpoint/datasources_endpoint.py +562 -7
  24. tableauserverclient/server/endpoint/dqw_endpoint.py +16 -6
  25. tableauserverclient/server/endpoint/endpoint.py +39 -0
  26. tableauserverclient/server/endpoint/exceptions.py +4 -0
  27. tableauserverclient/server/endpoint/fileuploads_endpoint.py +1 -1
  28. tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
  29. tableauserverclient/server/endpoint/jobs_endpoint.py +1 -1
  30. tableauserverclient/server/endpoint/schedules_endpoint.py +132 -2
  31. tableauserverclient/server/endpoint/sites_endpoint.py +18 -1
  32. tableauserverclient/server/endpoint/tables_endpoint.py +140 -17
  33. tableauserverclient/server/endpoint/users_endpoint.py +22 -5
  34. tableauserverclient/server/endpoint/views_endpoint.py +5 -1
  35. tableauserverclient/server/endpoint/workbooks_endpoint.py +24 -10
  36. tableauserverclient/server/query.py +36 -0
  37. tableauserverclient/server/request_factory.py +16 -5
  38. tableauserverclient/server/request_options.py +162 -2
  39. tableauserverclient/server/server.py +42 -0
  40. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/METADATA +3 -2
  41. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/RECORD +45 -43
  42. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/WHEEL +1 -1
  43. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE +0 -0
  44. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info/licenses}/LICENSE.versioneer +0 -0
  45. {tableauserverclient-0.36.dist-info → tableauserverclient-0.38.dist-info}/top_level.txt +0 -0
@@ -7,6 +7,7 @@ from typing import Optional, TYPE_CHECKING
7
7
  from defusedxml.ElementTree import fromstring
8
8
 
9
9
  from tableauserverclient.datetime_helpers import parse_datetime
10
+ from tableauserverclient.models.site_item import SiteAuthConfiguration
10
11
  from .exceptions import UnpopulatedPropertyError
11
12
  from .property_decorators import (
12
13
  property_is_enum,
@@ -37,6 +38,49 @@ class UserItem:
37
38
  auth_setting: str
38
39
  Required attribute for Tableau Cloud. How the user autenticates to the
39
40
  server.
41
+
42
+ Attributes
43
+ ----------
44
+ domain_name: Optional[str]
45
+ The name of the Active Directory domain ("local" if local authentication
46
+ is used).
47
+
48
+ email: Optional[str]
49
+ The email address of the user.
50
+
51
+ external_auth_user_id: Optional[str]
52
+ The unique identifier for the user in the external authentication system.
53
+
54
+ id: Optional[str]
55
+ The unique identifier for the user.
56
+
57
+ favorites: dict[str, list]
58
+ The favorites of the user. Must be populated with a call to
59
+ `populate_favorites()`.
60
+
61
+ fullname: Optional[str]
62
+ The full name of the user.
63
+
64
+ groups: Pager
65
+ The groups the user belongs to. Must be populated with a call to
66
+ `populate_groups()`.
67
+
68
+ last_login: Optional[datetime]
69
+ The last time the user logged in.
70
+
71
+ locale: Optional[str]
72
+ The locale of the user.
73
+
74
+ language: Optional[str]
75
+ Language setting for the user.
76
+
77
+ idp_configuration_id: Optional[str]
78
+ The ID of the identity provider configuration.
79
+
80
+ workbooks: Pager
81
+ The workbooks owned by the user. Must be populated with a call to
82
+ `populate_workbooks()`.
83
+
40
84
  """
41
85
 
42
86
  tag_name: str = "user"
@@ -94,6 +138,9 @@ class UserItem:
94
138
  self.name: Optional[str] = name
95
139
  self.site_role: Optional[str] = site_role
96
140
  self.auth_setting: Optional[str] = auth_setting
141
+ self._locale: Optional[str] = None
142
+ self._language: Optional[str] = None
143
+ self._idp_configuration_id: Optional[str] = None
97
144
 
98
145
  return None
99
146
 
@@ -184,6 +231,26 @@ class UserItem:
184
231
  raise UnpopulatedPropertyError(error)
185
232
  return self._groups()
186
233
 
234
+ @property
235
+ def locale(self) -> Optional[str]:
236
+ return self._locale
237
+
238
+ @property
239
+ def language(self) -> Optional[str]:
240
+ return self._language
241
+
242
+ @property
243
+ def idp_configuration_id(self) -> Optional[str]:
244
+ """
245
+ IDP configuration id for the user. This is only available on Tableau
246
+ Cloud, 3.24 or later
247
+ """
248
+ return self._idp_configuration_id
249
+
250
+ @idp_configuration_id.setter
251
+ def idp_configuration_id(self, value: str) -> None:
252
+ self._idp_configuration_id = value
253
+
187
254
  def _set_workbooks(self, workbooks) -> None:
188
255
  self._workbooks = workbooks
189
256
 
@@ -204,8 +271,11 @@ class UserItem:
204
271
  email,
205
272
  auth_setting,
206
273
  _,
274
+ _,
275
+ _,
276
+ _,
207
277
  ) = self._parse_element(user_xml, ns)
208
- self._set_values(None, None, site_role, None, None, fullname, email, auth_setting, None)
278
+ self._set_values(None, None, site_role, None, None, fullname, email, auth_setting, None, None, None, None)
209
279
  return self
210
280
 
211
281
  def _set_values(
@@ -219,6 +289,9 @@ class UserItem:
219
289
  email,
220
290
  auth_setting,
221
291
  domain_name,
292
+ locale,
293
+ language,
294
+ idp_configuration_id,
222
295
  ):
223
296
  if id is not None:
224
297
  self._id = id
@@ -238,6 +311,12 @@ class UserItem:
238
311
  self._auth_setting = auth_setting
239
312
  if domain_name:
240
313
  self._domain_name = domain_name
314
+ if locale:
315
+ self._locale = locale
316
+ if language:
317
+ self._language = language
318
+ if idp_configuration_id:
319
+ self._idp_configuration_id = idp_configuration_id
241
320
 
242
321
  @classmethod
243
322
  def from_response(cls, resp, ns) -> list["UserItem"]:
@@ -249,6 +328,12 @@ class UserItem:
249
328
  element_name = ".//t:owner"
250
329
  return cls._parse_xml(element_name, resp, ns)
251
330
 
331
+ @classmethod
332
+ def from_xml(cls, xml: ET.Element, ns: Optional[dict] = None) -> "UserItem":
333
+ item = cls()
334
+ item._set_values(*cls._parse_element(xml, ns))
335
+ return item
336
+
252
337
  @classmethod
253
338
  def _parse_xml(cls, element_name, resp, ns):
254
339
  all_user_items = []
@@ -265,6 +350,9 @@ class UserItem:
265
350
  email,
266
351
  auth_setting,
267
352
  domain_name,
353
+ locale,
354
+ language,
355
+ idp_configuration_id,
268
356
  ) = cls._parse_element(user_xml, ns)
269
357
  user_item = cls(name, site_role)
270
358
  user_item._set_values(
@@ -277,6 +365,9 @@ class UserItem:
277
365
  email,
278
366
  auth_setting,
279
367
  domain_name,
368
+ locale,
369
+ language,
370
+ idp_configuration_id,
280
371
  )
281
372
  all_user_items.append(user_item)
282
373
  return all_user_items
@@ -295,6 +386,9 @@ class UserItem:
295
386
  fullname = user_xml.get("fullName", None)
296
387
  email = user_xml.get("email", None)
297
388
  auth_setting = user_xml.get("authSetting", None)
389
+ locale = user_xml.get("locale", None)
390
+ language = user_xml.get("language", None)
391
+ idp_configuration_id = user_xml.get("idpConfigurationId", None)
298
392
 
299
393
  domain_name = None
300
394
  domain_elem = user_xml.find(".//t:domain", namespaces=ns)
@@ -311,6 +405,9 @@ class UserItem:
311
405
  email,
312
406
  auth_setting,
313
407
  domain_name,
408
+ locale,
409
+ language,
410
+ idp_configuration_id,
314
411
  )
315
412
 
316
413
  class CSVImport:
@@ -361,6 +458,9 @@ class UserItem:
361
458
  values[UserItem.CSVImport.ColumnType.EMAIL],
362
459
  values[UserItem.CSVImport.ColumnType.AUTH],
363
460
  None,
461
+ None,
462
+ None,
463
+ None,
364
464
  )
365
465
  return user
366
466
 
@@ -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(".//t:tags", namespaces=ns)
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
- view_item._project_id = project_elem.get("id", None)
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
- view_item._workbook_id = workbook_elem.get("id", None)
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
@@ -5,6 +5,7 @@ from tableauserverclient.server.request_options import (
5
5
  ExcelRequestOptions,
6
6
  ImageRequestOptions,
7
7
  PDFRequestOptions,
8
+ PPTXRequestOptions,
8
9
  RequestOptions,
9
10
  )
10
11
  from tableauserverclient.server.filter import Filter
@@ -52,6 +53,7 @@ __all__ = [
52
53
  "ExcelRequestOptions",
53
54
  "ImageRequestOptions",
54
55
  "PDFRequestOptions",
56
+ "PPTXRequestOptions",
55
57
  "RequestOptions",
56
58
  "Filter",
57
59
  "Sort",