tableauserverclient 0.31__py3-none-any.whl → 0.33__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 (54) hide show
  1. tableauserverclient/__init__.py +74 -4
  2. tableauserverclient/_version.py +3 -3
  3. tableauserverclient/config.py +16 -4
  4. tableauserverclient/models/__init__.py +100 -37
  5. tableauserverclient/models/connection_item.py +4 -2
  6. tableauserverclient/models/database_item.py +6 -0
  7. tableauserverclient/models/datasource_item.py +18 -6
  8. tableauserverclient/models/favorites_item.py +7 -7
  9. tableauserverclient/models/flow_item.py +6 -6
  10. tableauserverclient/models/groupset_item.py +53 -0
  11. tableauserverclient/models/interval_item.py +27 -14
  12. tableauserverclient/models/job_item.py +18 -2
  13. tableauserverclient/models/linked_tasks_item.py +102 -0
  14. tableauserverclient/models/permissions_item.py +53 -5
  15. tableauserverclient/models/project_item.py +4 -3
  16. tableauserverclient/models/reference_item.py +5 -0
  17. tableauserverclient/models/tableau_auth.py +22 -23
  18. tableauserverclient/models/tableau_types.py +9 -7
  19. tableauserverclient/models/virtual_connection_item.py +77 -0
  20. tableauserverclient/server/__init__.py +83 -8
  21. tableauserverclient/server/endpoint/__init__.py +69 -28
  22. tableauserverclient/server/endpoint/auth_endpoint.py +3 -3
  23. tableauserverclient/server/endpoint/custom_views_endpoint.py +66 -5
  24. tableauserverclient/server/endpoint/databases_endpoint.py +21 -18
  25. tableauserverclient/server/endpoint/datasources_endpoint.py +115 -35
  26. tableauserverclient/server/endpoint/endpoint.py +53 -20
  27. tableauserverclient/server/endpoint/favorites_endpoint.py +1 -1
  28. tableauserverclient/server/endpoint/fileuploads_endpoint.py +2 -2
  29. tableauserverclient/server/endpoint/flow_runs_endpoint.py +45 -5
  30. tableauserverclient/server/endpoint/flows_endpoint.py +43 -16
  31. tableauserverclient/server/endpoint/groups_endpoint.py +85 -31
  32. tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
  33. tableauserverclient/server/endpoint/jobs_endpoint.py +74 -7
  34. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
  35. tableauserverclient/server/endpoint/metadata_endpoint.py +3 -3
  36. tableauserverclient/server/endpoint/metrics_endpoint.py +1 -1
  37. tableauserverclient/server/endpoint/projects_endpoint.py +50 -18
  38. tableauserverclient/server/endpoint/resource_tagger.py +135 -3
  39. tableauserverclient/server/endpoint/tables_endpoint.py +19 -16
  40. tableauserverclient/server/endpoint/users_endpoint.py +40 -1
  41. tableauserverclient/server/endpoint/views_endpoint.py +97 -10
  42. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +173 -0
  43. tableauserverclient/server/endpoint/workbooks_endpoint.py +97 -45
  44. tableauserverclient/server/pager.py +46 -46
  45. tableauserverclient/server/query.py +62 -33
  46. tableauserverclient/server/request_factory.py +192 -49
  47. tableauserverclient/server/request_options.py +4 -2
  48. tableauserverclient/server/server.py +13 -6
  49. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/METADATA +15 -16
  50. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/RECORD +54 -48
  51. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/WHEEL +1 -1
  52. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/LICENSE +0 -0
  53. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/LICENSE.versioneer +0 -0
  54. {tableauserverclient-0.31.dist-info → tableauserverclient-0.33.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- from ._version import get_versions
2
- from .namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE
3
- from .models import (
1
+ from tableauserverclient._version import get_versions
2
+ from tableauserverclient.namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE
3
+ from tableauserverclient.models import (
4
4
  BackgroundJobItem,
5
5
  ColumnItem,
6
6
  ConnectionCredentials,
@@ -17,10 +17,14 @@ from .models import (
17
17
  FlowRunItem,
18
18
  FileuploadItem,
19
19
  GroupItem,
20
+ GroupSetItem,
20
21
  HourlyInterval,
21
22
  IntervalItem,
22
23
  JobItem,
23
24
  JWTAuth,
25
+ LinkedTaskItem,
26
+ LinkedTaskStepItem,
27
+ LinkedTaskFlowRunItem,
24
28
  MetricItem,
25
29
  MonthlyInterval,
26
30
  PaginationItem,
@@ -39,11 +43,13 @@ from .models import (
39
43
  TaskItem,
40
44
  UserItem,
41
45
  ViewItem,
46
+ VirtualConnectionItem,
42
47
  WebhookItem,
43
48
  WeeklyInterval,
44
49
  WorkbookItem,
45
50
  )
46
- from .server import (
51
+
52
+ from tableauserverclient.server import (
47
53
  CSVRequestOptions,
48
54
  ExcelRequestOptions,
49
55
  ImageRequestOptions,
@@ -57,3 +63,67 @@ from .server import (
57
63
  Server,
58
64
  Sort,
59
65
  )
66
+
67
+ __all__ = [
68
+ "get_versions",
69
+ "DEFAULT_NAMESPACE",
70
+ "BackgroundJobItem",
71
+ "BackgroundJobItem",
72
+ "ColumnItem",
73
+ "ConnectionCredentials",
74
+ "ConnectionItem",
75
+ "CustomViewItem",
76
+ "DQWItem",
77
+ "DailyInterval",
78
+ "DataAlertItem",
79
+ "DatabaseItem",
80
+ "DataFreshnessPolicyItem",
81
+ "DatasourceItem",
82
+ "FavoriteItem",
83
+ "FlowItem",
84
+ "FlowRunItem",
85
+ "FileuploadItem",
86
+ "GroupItem",
87
+ "GroupSetItem",
88
+ "HourlyInterval",
89
+ "IntervalItem",
90
+ "JobItem",
91
+ "JWTAuth",
92
+ "MetricItem",
93
+ "MonthlyInterval",
94
+ "PaginationItem",
95
+ "Permission",
96
+ "PermissionsRule",
97
+ "PersonalAccessTokenAuth",
98
+ "ProjectItem",
99
+ "RevisionItem",
100
+ "ScheduleItem",
101
+ "SiteItem",
102
+ "ServerInfoItem",
103
+ "SubscriptionItem",
104
+ "TableItem",
105
+ "TableauAuth",
106
+ "Target",
107
+ "TaskItem",
108
+ "UserItem",
109
+ "ViewItem",
110
+ "WebhookItem",
111
+ "WeeklyInterval",
112
+ "WorkbookItem",
113
+ "CSVRequestOptions",
114
+ "ExcelRequestOptions",
115
+ "ImageRequestOptions",
116
+ "PDFRequestOptions",
117
+ "RequestOptions",
118
+ "MissingRequiredFieldError",
119
+ "NotSignedInError",
120
+ "ServerResponseError",
121
+ "Filter",
122
+ "Pager",
123
+ "Server",
124
+ "Sort",
125
+ "LinkedTaskItem",
126
+ "LinkedTaskStepItem",
127
+ "LinkedTaskFlowRunItem",
128
+ "VirtualConnectionItem",
129
+ ]
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-06-03T12:52:39-0700",
11
+ "date": "2024-09-17T16:51:07-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "4018a0ffc01bfa7c5b0024c6f112ced158d420b9",
15
- "version": "0.31"
14
+ "full-revisionid": "4259316ef2e2656531b0c65c71d043708b37b4a9",
15
+ "version": "0.33"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -1,13 +1,25 @@
1
- # TODO: check for env variables, else set default values
1
+ import os
2
2
 
3
3
  ALLOWED_FILE_EXTENSIONS = ["tds", "tdsx", "tde", "hyper", "parquet"]
4
4
 
5
5
  BYTES_PER_MB = 1024 * 1024
6
6
 
7
- # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
8
- CHUNK_SIZE_MB = 5 * 10 # 5MB felt too slow, upped it to 50
9
-
10
7
  DELAY_SLEEP_SECONDS = 0.1
11
8
 
12
9
  # The maximum size of a file that can be published in a single request is 64MB
13
10
  FILESIZE_LIMIT_MB = 64
11
+
12
+
13
+ class Config:
14
+ # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
15
+ @property
16
+ def CHUNK_SIZE_MB(self):
17
+ return int(os.getenv("TSC_CHUNK_SIZE_MB", 5 * 10)) # 5MB felt too slow, upped it to 50
18
+
19
+ # Default page size
20
+ @property
21
+ def PAGE_SIZE(self):
22
+ return int(os.getenv("TSC_PAGE_SIZE", 100))
23
+
24
+
25
+ config = Config()
@@ -1,43 +1,106 @@
1
- from .column_item import ColumnItem
2
- from .connection_credentials import ConnectionCredentials
3
- from .connection_item import ConnectionItem
4
- from .custom_view_item import CustomViewItem
5
- from .data_acceleration_report_item import DataAccelerationReportItem
6
- from .data_alert_item import DataAlertItem
7
- from .database_item import DatabaseItem
8
- from .data_freshness_policy_item import DataFreshnessPolicyItem
9
- from .datasource_item import DatasourceItem
10
- from .dqw_item import DQWItem
11
- from .exceptions import UnpopulatedPropertyError
12
- from .favorites_item import FavoriteItem
13
- from .fileupload_item import FileuploadItem
14
- from .flow_item import FlowItem
15
- from .flow_run_item import FlowRunItem
16
- from .group_item import GroupItem
17
- from .interval_item import (
1
+ from tableauserverclient.models.column_item import ColumnItem
2
+ from tableauserverclient.models.connection_credentials import ConnectionCredentials
3
+ from tableauserverclient.models.connection_item import ConnectionItem
4
+ from tableauserverclient.models.custom_view_item import CustomViewItem
5
+ from tableauserverclient.models.data_acceleration_report_item import DataAccelerationReportItem
6
+ from tableauserverclient.models.data_alert_item import DataAlertItem
7
+ from tableauserverclient.models.database_item import DatabaseItem
8
+ from tableauserverclient.models.data_freshness_policy_item import DataFreshnessPolicyItem
9
+ from tableauserverclient.models.datasource_item import DatasourceItem
10
+ from tableauserverclient.models.dqw_item import DQWItem
11
+ from tableauserverclient.models.exceptions import UnpopulatedPropertyError
12
+ from tableauserverclient.models.favorites_item import FavoriteItem
13
+ from tableauserverclient.models.fileupload_item import FileuploadItem
14
+ from tableauserverclient.models.flow_item import FlowItem
15
+ from tableauserverclient.models.flow_run_item import FlowRunItem
16
+ from tableauserverclient.models.group_item import GroupItem
17
+ from tableauserverclient.models.groupset_item import GroupSetItem
18
+ from tableauserverclient.models.interval_item import (
18
19
  IntervalItem,
19
20
  DailyInterval,
20
21
  WeeklyInterval,
21
22
  MonthlyInterval,
22
23
  HourlyInterval,
23
24
  )
24
- from .job_item import JobItem, BackgroundJobItem
25
- from .metric_item import MetricItem
26
- from .pagination_item import PaginationItem
27
- from .permissions_item import PermissionsRule, Permission
28
- from .project_item import ProjectItem
29
- from .revision_item import RevisionItem
30
- from .schedule_item import ScheduleItem
31
- from .server_info_item import ServerInfoItem
32
- from .site_item import SiteItem
33
- from .subscription_item import SubscriptionItem
34
- from .table_item import TableItem
35
- from .tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth, JWTAuth
36
- from .tableau_types import Resource, TableauItem, plural_type
37
- from .tag_item import TagItem
38
- from .target import Target
39
- from .task_item import TaskItem
40
- from .user_item import UserItem
41
- from .view_item import ViewItem
42
- from .webhook_item import WebhookItem
43
- from .workbook_item import WorkbookItem
25
+ from tableauserverclient.models.job_item import JobItem, BackgroundJobItem
26
+ from tableauserverclient.models.linked_tasks_item import (
27
+ LinkedTaskItem,
28
+ LinkedTaskStepItem,
29
+ LinkedTaskFlowRunItem,
30
+ )
31
+ from tableauserverclient.models.metric_item import MetricItem
32
+ from tableauserverclient.models.pagination_item import PaginationItem
33
+ from tableauserverclient.models.permissions_item import PermissionsRule, Permission
34
+ from tableauserverclient.models.project_item import ProjectItem
35
+ from tableauserverclient.models.revision_item import RevisionItem
36
+ from tableauserverclient.models.schedule_item import ScheduleItem
37
+ from tableauserverclient.models.server_info_item import ServerInfoItem
38
+ from tableauserverclient.models.site_item import SiteItem
39
+ from tableauserverclient.models.subscription_item import SubscriptionItem
40
+ from tableauserverclient.models.table_item import TableItem
41
+ from tableauserverclient.models.tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth, JWTAuth
42
+ from tableauserverclient.models.tableau_types import Resource, TableauItem, plural_type
43
+ from tableauserverclient.models.tag_item import TagItem
44
+ from tableauserverclient.models.target import Target
45
+ from tableauserverclient.models.task_item import TaskItem
46
+ from tableauserverclient.models.user_item import UserItem
47
+ from tableauserverclient.models.view_item import ViewItem
48
+ from tableauserverclient.models.virtual_connection_item import VirtualConnectionItem
49
+ from tableauserverclient.models.webhook_item import WebhookItem
50
+ from tableauserverclient.models.workbook_item import WorkbookItem
51
+
52
+ __all__ = [
53
+ "ColumnItem",
54
+ "ConnectionCredentials",
55
+ "ConnectionItem",
56
+ "Credentials",
57
+ "CustomViewItem",
58
+ "DataAccelerationReportItem",
59
+ "DataAlertItem",
60
+ "DatabaseItem",
61
+ "DataFreshnessPolicyItem",
62
+ "DatasourceItem",
63
+ "DQWItem",
64
+ "UnpopulatedPropertyError",
65
+ "FavoriteItem",
66
+ "FileuploadItem",
67
+ "FlowItem",
68
+ "FlowRunItem",
69
+ "GroupItem",
70
+ "GroupSetItem",
71
+ "IntervalItem",
72
+ "JobItem",
73
+ "DailyInterval",
74
+ "WeeklyInterval",
75
+ "MonthlyInterval",
76
+ "HourlyInterval",
77
+ "BackgroundJobItem",
78
+ "MetricItem",
79
+ "PaginationItem",
80
+ "Permission",
81
+ "PermissionsRule",
82
+ "ProjectItem",
83
+ "RevisionItem",
84
+ "ScheduleItem",
85
+ "ServerInfoItem",
86
+ "SiteItem",
87
+ "SubscriptionItem",
88
+ "TableItem",
89
+ "TableauAuth",
90
+ "PersonalAccessTokenAuth",
91
+ "JWTAuth",
92
+ "Resource",
93
+ "TableauItem",
94
+ "plural_type",
95
+ "TagItem",
96
+ "Target",
97
+ "TaskItem",
98
+ "UserItem",
99
+ "ViewItem",
100
+ "VirtualConnectionItem",
101
+ "WebhookItem",
102
+ "WorkbookItem",
103
+ "LinkedTaskItem",
104
+ "LinkedTaskStepItem",
105
+ "LinkedTaskFlowRunItem",
106
+ ]
@@ -66,12 +66,14 @@ class ConnectionItem(object):
66
66
  for connection_xml in all_connection_xml:
67
67
  connection_item = cls()
68
68
  connection_item._id = connection_xml.get("id", None)
69
- connection_item._connection_type = connection_xml.get("type", None)
69
+ connection_item._connection_type = connection_xml.get("type", connection_xml.get("dbClass", None))
70
70
  connection_item.embed_password = string_to_bool(connection_xml.get("embedPassword", ""))
71
71
  connection_item.server_address = connection_xml.get("serverAddress", None)
72
72
  connection_item.server_port = connection_xml.get("serverPort", None)
73
73
  connection_item.username = connection_xml.get("userName", None)
74
- connection_item._query_tagging = string_to_bool(connection_xml.get("queryTaggingEnabled", None))
74
+ connection_item._query_tagging = (
75
+ string_to_bool(s) if (s := connection_xml.get("queryTagging", None)) else None
76
+ )
75
77
  datasource_elem = connection_xml.find(".//t:datasource", namespaces=ns)
76
78
  if datasource_elem is not None:
77
79
  connection_item._datasource_id = datasource_elem.get("id", None)
@@ -44,6 +44,12 @@ class DatabaseItem(object):
44
44
 
45
45
  self._tables = None # Not implemented yet
46
46
 
47
+ def __str__(self):
48
+ return "<Database {0} '{1}'>".format(self._id, self.name)
49
+
50
+ def __repr__(self):
51
+ return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"
52
+
47
53
  @property
48
54
  def dqws(self):
49
55
  if self._data_quality_warnings is None:
@@ -6,16 +6,16 @@ from typing import Dict, List, Optional, Set, Tuple
6
6
  from defusedxml.ElementTree import fromstring
7
7
 
8
8
  from tableauserverclient.datetime_helpers import parse_datetime
9
- from .connection_item import ConnectionItem
10
- from .exceptions import UnpopulatedPropertyError
11
- from .permissions_item import PermissionsRule
12
- from .property_decorators import (
9
+ from tableauserverclient.models.connection_item import ConnectionItem
10
+ from tableauserverclient.models.exceptions import UnpopulatedPropertyError
11
+ from tableauserverclient.models.permissions_item import PermissionsRule
12
+ from tableauserverclient.models.property_decorators import (
13
13
  property_not_nullable,
14
14
  property_is_boolean,
15
15
  property_is_enum,
16
16
  )
17
- from .revision_item import RevisionItem
18
- from .tag_item import TagItem
17
+ from tableauserverclient.models.revision_item import RevisionItem
18
+ from tableauserverclient.models.tag_item import TagItem
19
19
 
20
20
 
21
21
  class DatasourceItem(object):
@@ -47,6 +47,7 @@ class DatasourceItem(object):
47
47
  self._initial_tags: Set = set()
48
48
  self._project_name: Optional[str] = None
49
49
  self._revisions = None
50
+ self._size: Optional[int] = None
50
51
  self._updated_at = None
51
52
  self._use_remote_query_agent = None
52
53
  self._webpage_url = None
@@ -182,6 +183,10 @@ class DatasourceItem(object):
182
183
  raise UnpopulatedPropertyError(error)
183
184
  return self._revisions()
184
185
 
186
+ @property
187
+ def size(self) -> Optional[int]:
188
+ return self._size
189
+
185
190
  def _set_connections(self, connections):
186
191
  self._connections = connections
187
192
 
@@ -217,6 +222,7 @@ class DatasourceItem(object):
217
222
  updated_at,
218
223
  use_remote_query_agent,
219
224
  webpage_url,
225
+ size,
220
226
  ) = self._parse_element(datasource_xml, ns)
221
227
  self._set_values(
222
228
  ask_data_enablement,
@@ -237,6 +243,7 @@ class DatasourceItem(object):
237
243
  updated_at,
238
244
  use_remote_query_agent,
239
245
  webpage_url,
246
+ size,
240
247
  )
241
248
  return self
242
249
 
@@ -260,6 +267,7 @@ class DatasourceItem(object):
260
267
  updated_at,
261
268
  use_remote_query_agent,
262
269
  webpage_url,
270
+ size,
263
271
  ):
264
272
  if ask_data_enablement is not None:
265
273
  self._ask_data_enablement = ask_data_enablement
@@ -297,6 +305,8 @@ class DatasourceItem(object):
297
305
  self._use_remote_query_agent = str(use_remote_query_agent).lower() == "true"
298
306
  if webpage_url:
299
307
  self._webpage_url = webpage_url
308
+ if size is not None:
309
+ self._size = int(size)
300
310
 
301
311
  @classmethod
302
312
  def from_response(cls, resp: str, ns: Dict) -> List["DatasourceItem"]:
@@ -330,6 +340,7 @@ class DatasourceItem(object):
330
340
  has_extracts = datasource_xml.get("hasExtracts", None)
331
341
  use_remote_query_agent = datasource_xml.get("useRemoteQueryAgent", None)
332
342
  webpage_url = datasource_xml.get("webpageUrl", None)
343
+ size = datasource_xml.get("size", None)
333
344
 
334
345
  tags = None
335
346
  tags_elem = datasource_xml.find(".//t:tags", namespaces=ns)
@@ -372,4 +383,5 @@ class DatasourceItem(object):
372
383
  updated_at,
373
384
  use_remote_query_agent,
374
385
  webpage_url,
386
+ size,
375
387
  )
@@ -1,14 +1,14 @@
1
1
  import logging
2
2
 
3
3
  from defusedxml.ElementTree import fromstring
4
- from .tableau_types import TableauItem
4
+ from tableauserverclient.models.tableau_types import TableauItem
5
5
 
6
- from .datasource_item import DatasourceItem
7
- from .flow_item import FlowItem
8
- from .project_item import ProjectItem
9
- from .metric_item import MetricItem
10
- from .view_item import ViewItem
11
- from .workbook_item import WorkbookItem
6
+ from tableauserverclient.models.datasource_item import DatasourceItem
7
+ from tableauserverclient.models.flow_item import FlowItem
8
+ from tableauserverclient.models.project_item import ProjectItem
9
+ from tableauserverclient.models.metric_item import MetricItem
10
+ from tableauserverclient.models.view_item import ViewItem
11
+ from tableauserverclient.models.workbook_item import WorkbookItem
12
12
  from typing import Dict, List
13
13
 
14
14
  from tableauserverclient.helpers.logging import logger
@@ -6,12 +6,12 @@ from typing import List, Optional, Set
6
6
  from defusedxml.ElementTree import fromstring
7
7
 
8
8
  from tableauserverclient.datetime_helpers import parse_datetime
9
- from .connection_item import ConnectionItem
10
- from .dqw_item import DQWItem
11
- from .exceptions import UnpopulatedPropertyError
12
- from .permissions_item import Permission
13
- from .property_decorators import property_not_nullable
14
- from .tag_item import TagItem
9
+ from tableauserverclient.models.connection_item import ConnectionItem
10
+ from tableauserverclient.models.dqw_item import DQWItem
11
+ from tableauserverclient.models.exceptions import UnpopulatedPropertyError
12
+ from tableauserverclient.models.permissions_item import Permission
13
+ from tableauserverclient.models.property_decorators import property_not_nullable
14
+ from tableauserverclient.models.tag_item import TagItem
15
15
 
16
16
 
17
17
  class FlowItem(object):
@@ -0,0 +1,53 @@
1
+ from typing import Dict, List, Optional
2
+ import xml.etree.ElementTree as ET
3
+
4
+ from defusedxml.ElementTree import fromstring
5
+
6
+ from tableauserverclient.models.group_item import GroupItem
7
+ from tableauserverclient.models.reference_item import ResourceReference
8
+
9
+
10
+ class GroupSetItem:
11
+ tag_name: str = "groupSet"
12
+
13
+ def __init__(self, name: Optional[str] = None) -> None:
14
+ self.name = name
15
+ self.id: Optional[str] = None
16
+ self.groups: List["GroupItem"] = []
17
+ self.group_count: int = 0
18
+
19
+ def __str__(self) -> str:
20
+ name = self.name
21
+ id = self.id
22
+ return f"<{self.__class__.__qualname__}({name=}, {id=})>"
23
+
24
+ def __repr__(self) -> str:
25
+ return self.__str__()
26
+
27
+ @classmethod
28
+ def from_response(cls, response: bytes, ns: Dict[str, str]) -> List["GroupSetItem"]:
29
+ parsed_response = fromstring(response)
30
+ all_groupset_xml = parsed_response.findall(".//t:groupSet", namespaces=ns)
31
+ return [cls.from_xml(xml, ns) for xml in all_groupset_xml]
32
+
33
+ @classmethod
34
+ def from_xml(cls, groupset_xml: ET.Element, ns: Dict[str, str]) -> "GroupSetItem":
35
+ def get_group(group_xml: ET.Element) -> GroupItem:
36
+ group_item = GroupItem()
37
+ group_item._id = group_xml.get("id")
38
+ group_item.name = group_xml.get("name")
39
+ return group_item
40
+
41
+ group_set_item = cls()
42
+ group_set_item.name = groupset_xml.get("name")
43
+ group_set_item.id = groupset_xml.get("id")
44
+ group_set_item.group_count = int(count) if (count := groupset_xml.get("groupCount")) else 0
45
+ group_set_item.groups = [
46
+ get_group(group_xml) for group_xml in groupset_xml.findall(".//t:group", namespaces=ns)
47
+ ]
48
+
49
+ return group_set_item
50
+
51
+ @staticmethod
52
+ def as_reference(id_: str) -> ResourceReference:
53
+ return ResourceReference(id_, GroupSetItem.tag_name)
@@ -246,21 +246,34 @@ class MonthlyInterval(object):
246
246
 
247
247
  @interval.setter
248
248
  def interval(self, interval_values):
249
- # This is weird because the value could be a str or an int
250
- # The only valid str is 'LastDay' so we check that first. If that's not it
251
- # try to convert it to an int, if that fails because it's an incorrect string
252
- # like 'badstring' we catch and re-raise. Otherwise we convert to int and check
253
- # that it's in range 1-31
249
+ # Valid monthly intervals strings can contain any of the following
250
+ # day numbers (1-31) (integer or string)
251
+ # relative day within the month (First, Second, ... Last)
252
+ # week days (Sunday, Monday, ... LastDay)
253
+ VALID_INTERVALS = [
254
+ "Sunday",
255
+ "Monday",
256
+ "Tuesday",
257
+ "Wednesday",
258
+ "Thursday",
259
+ "Friday",
260
+ "Saturday",
261
+ "LastDay",
262
+ "First",
263
+ "Second",
264
+ "Third",
265
+ "Fourth",
266
+ "Fifth",
267
+ "Last",
268
+ ]
269
+ for value in range(1, 32):
270
+ VALID_INTERVALS.append(str(value))
271
+ VALID_INTERVALS.append(value)
272
+
254
273
  for interval_value in interval_values:
255
- error = "Invalid interval value for a monthly frequency: {}.".format(interval_value)
256
-
257
- if interval_value != "LastDay":
258
- try:
259
- if not (1 <= int(interval_value) <= 31):
260
- raise ValueError(error)
261
- except ValueError:
262
- if interval_value != "LastDay":
263
- raise ValueError(error)
274
+ if interval_value not in VALID_INTERVALS:
275
+ error = f"Invalid monthly interval: {interval_value}"
276
+ raise ValueError(error)
264
277
 
265
278
  self._interval = interval_values
266
279
 
@@ -4,7 +4,7 @@ from typing import List, Optional
4
4
  from defusedxml.ElementTree import fromstring
5
5
 
6
6
  from tableauserverclient.datetime_helpers import parse_datetime
7
- from .flow_run_item import FlowRunItem
7
+ from tableauserverclient.models.flow_run_item import FlowRunItem
8
8
 
9
9
 
10
10
  class JobItem(object):
@@ -33,6 +33,8 @@ class JobItem(object):
33
33
  datasource_id: Optional[str] = None,
34
34
  flow_run: Optional[FlowRunItem] = None,
35
35
  updated_at: Optional[datetime.datetime] = None,
36
+ workbook_name: Optional[str] = None,
37
+ datasource_name: Optional[str] = None,
36
38
  ):
37
39
  self._id = id_
38
40
  self._type = job_type
@@ -47,6 +49,8 @@ class JobItem(object):
47
49
  self._datasource_id = datasource_id
48
50
  self._flow_run = flow_run
49
51
  self._updated_at = updated_at
52
+ self._workbook_name = workbook_name
53
+ self._datasource_name = datasource_name
50
54
 
51
55
  @property
52
56
  def id(self) -> str:
@@ -117,6 +121,14 @@ class JobItem(object):
117
121
  def updated_at(self) -> Optional[datetime.datetime]:
118
122
  return self._updated_at
119
123
 
124
+ @property
125
+ def workbook_name(self) -> Optional[str]:
126
+ return self._workbook_name
127
+
128
+ @property
129
+ def datasource_name(self) -> Optional[str]:
130
+ return self._datasource_name
131
+
120
132
  def __str__(self):
121
133
  return (
122
134
  "<Job#{_id} {_type} created_at({_created_at}) started_at({_started_at}) updated_at({_updated_at}) completed_at({_completed_at})"
@@ -148,8 +160,10 @@ class JobItem(object):
148
160
  mode = element.get("mode", None)
149
161
  workbook = element.find(".//t:workbook[@id]", namespaces=ns)
150
162
  workbook_id = workbook.get("id") if workbook is not None else None
163
+ workbook_name = workbook.get("name") if workbook is not None else None
151
164
  datasource = element.find(".//t:datasource[@id]", namespaces=ns)
152
165
  datasource_id = datasource.get("id") if datasource is not None else None
166
+ datasource_name = datasource.get("name") if datasource is not None else None
153
167
  flow_run = None
154
168
  updated_at = parse_datetime(element.get("updatedAt", None))
155
169
  for flow_job in element.findall(".//t:runFlowJobType", namespaces=ns):
@@ -172,6 +186,8 @@ class JobItem(object):
172
186
  datasource_id,
173
187
  flow_run,
174
188
  updated_at,
189
+ workbook_name,
190
+ datasource_name,
175
191
  )
176
192
 
177
193
 
@@ -206,7 +222,7 @@ class BackgroundJobItem(object):
206
222
  self._subtitle = subtitle
207
223
 
208
224
  def __str__(self):
209
- return f"<{self.__class__.name} {self._id} {self._type}>"
225
+ return f"<{self.__class__.__qualname__} {self._id} {self._type}>"
210
226
 
211
227
  def __repr__(self):
212
228
  return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"