tableauserverclient 0.32__py3-none-any.whl → 0.34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. tableauserverclient/__init__.py +34 -18
  2. tableauserverclient/_version.py +3 -3
  3. tableauserverclient/config.py +20 -6
  4. tableauserverclient/models/__init__.py +12 -0
  5. tableauserverclient/models/column_item.py +1 -1
  6. tableauserverclient/models/connection_credentials.py +1 -1
  7. tableauserverclient/models/connection_item.py +10 -8
  8. tableauserverclient/models/custom_view_item.py +29 -6
  9. tableauserverclient/models/data_acceleration_report_item.py +2 -2
  10. tableauserverclient/models/data_alert_item.py +5 -5
  11. tableauserverclient/models/data_freshness_policy_item.py +6 -6
  12. tableauserverclient/models/database_item.py +8 -2
  13. tableauserverclient/models/datasource_item.py +10 -10
  14. tableauserverclient/models/dqw_item.py +1 -1
  15. tableauserverclient/models/favorites_item.py +5 -6
  16. tableauserverclient/models/fileupload_item.py +1 -1
  17. tableauserverclient/models/flow_item.py +12 -12
  18. tableauserverclient/models/flow_run_item.py +3 -3
  19. tableauserverclient/models/group_item.py +4 -4
  20. tableauserverclient/models/groupset_item.py +53 -0
  21. tableauserverclient/models/interval_item.py +36 -23
  22. tableauserverclient/models/job_item.py +26 -10
  23. tableauserverclient/models/linked_tasks_item.py +102 -0
  24. tableauserverclient/models/metric_item.py +5 -5
  25. tableauserverclient/models/pagination_item.py +1 -1
  26. tableauserverclient/models/permissions_item.py +19 -14
  27. tableauserverclient/models/project_item.py +35 -19
  28. tableauserverclient/models/property_decorators.py +12 -11
  29. tableauserverclient/models/reference_item.py +2 -2
  30. tableauserverclient/models/revision_item.py +3 -3
  31. tableauserverclient/models/schedule_item.py +2 -2
  32. tableauserverclient/models/server_info_item.py +26 -6
  33. tableauserverclient/models/site_item.py +69 -3
  34. tableauserverclient/models/subscription_item.py +3 -3
  35. tableauserverclient/models/table_item.py +1 -1
  36. tableauserverclient/models/tableau_auth.py +115 -5
  37. tableauserverclient/models/tableau_types.py +11 -9
  38. tableauserverclient/models/tag_item.py +3 -4
  39. tableauserverclient/models/task_item.py +4 -4
  40. tableauserverclient/models/user_item.py +47 -17
  41. tableauserverclient/models/view_item.py +11 -10
  42. tableauserverclient/models/virtual_connection_item.py +78 -0
  43. tableauserverclient/models/webhook_item.py +6 -6
  44. tableauserverclient/models/workbook_item.py +90 -12
  45. tableauserverclient/namespace.py +1 -1
  46. tableauserverclient/server/__init__.py +2 -1
  47. tableauserverclient/server/endpoint/__init__.py +8 -0
  48. tableauserverclient/server/endpoint/auth_endpoint.py +68 -11
  49. tableauserverclient/server/endpoint/custom_views_endpoint.py +124 -19
  50. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
  51. tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
  52. tableauserverclient/server/endpoint/databases_endpoint.py +32 -17
  53. tableauserverclient/server/endpoint/datasources_endpoint.py +150 -59
  54. tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
  55. tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
  56. tableauserverclient/server/endpoint/endpoint.py +47 -31
  57. tableauserverclient/server/endpoint/exceptions.py +23 -7
  58. tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
  59. tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -13
  60. tableauserverclient/server/endpoint/flow_runs_endpoint.py +59 -17
  61. tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
  62. tableauserverclient/server/endpoint/flows_endpoint.py +73 -35
  63. tableauserverclient/server/endpoint/groups_endpoint.py +96 -27
  64. tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
  65. tableauserverclient/server/endpoint/jobs_endpoint.py +79 -12
  66. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
  67. tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
  68. tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
  69. tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
  70. tableauserverclient/server/endpoint/projects_endpoint.py +124 -30
  71. tableauserverclient/server/endpoint/resource_tagger.py +139 -6
  72. tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
  73. tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
  74. tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
  75. tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
  76. tableauserverclient/server/endpoint/tables_endpoint.py +33 -19
  77. tableauserverclient/server/endpoint/tasks_endpoint.py +8 -8
  78. tableauserverclient/server/endpoint/users_endpoint.py +405 -19
  79. tableauserverclient/server/endpoint/views_endpoint.py +111 -25
  80. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +174 -0
  81. tableauserverclient/server/endpoint/webhooks_endpoint.py +11 -11
  82. tableauserverclient/server/endpoint/workbooks_endpoint.py +735 -68
  83. tableauserverclient/server/filter.py +2 -2
  84. tableauserverclient/server/pager.py +8 -10
  85. tableauserverclient/server/query.py +70 -20
  86. tableauserverclient/server/request_factory.py +213 -41
  87. tableauserverclient/server/request_options.py +125 -145
  88. tableauserverclient/server/server.py +73 -9
  89. tableauserverclient/server/sort.py +2 -2
  90. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/METADATA +17 -17
  91. tableauserverclient-0.34.dist-info/RECORD +106 -0
  92. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/WHEEL +1 -1
  93. tableauserverclient-0.32.dist-info/RECORD +0 -100
  94. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE +0 -0
  95. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE.versioneer +0 -0
  96. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/top_level.txt +0 -0
@@ -17,10 +17,14 @@ from tableauserverclient.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,
@@ -28,17 +32,20 @@ from tableauserverclient.models import (
28
32
  PermissionsRule,
29
33
  PersonalAccessTokenAuth,
30
34
  ProjectItem,
35
+ Resource,
31
36
  RevisionItem,
32
37
  ScheduleItem,
33
38
  SiteItem,
34
39
  ServerInfoItem,
35
40
  SubscriptionItem,
41
+ TableauItem,
36
42
  TableItem,
37
43
  TableauAuth,
38
44
  Target,
39
45
  TaskItem,
40
46
  UserItem,
41
47
  ViewItem,
48
+ VirtualConnectionItem,
42
49
  WebhookItem,
43
50
  WeeklyInterval,
44
51
  WorkbookItem,
@@ -51,6 +58,7 @@ from tableauserverclient.server import (
51
58
  PDFRequestOptions,
52
59
  RequestOptions,
53
60
  MissingRequiredFieldError,
61
+ FailedSignInError,
54
62
  NotSignedInError,
55
63
  ServerResponseError,
56
64
  Filter,
@@ -60,60 +68,68 @@ from tableauserverclient.server import (
60
68
  )
61
69
 
62
70
  __all__ = [
63
- "get_versions",
64
- "DEFAULT_NAMESPACE",
65
71
  "BackgroundJobItem",
66
72
  "BackgroundJobItem",
67
73
  "ColumnItem",
68
74
  "ConnectionCredentials",
69
75
  "ConnectionItem",
76
+ "CSVRequestOptions",
70
77
  "CustomViewItem",
71
- "DQWItem",
72
78
  "DailyInterval",
73
79
  "DataAlertItem",
74
80
  "DatabaseItem",
75
81
  "DataFreshnessPolicyItem",
76
82
  "DatasourceItem",
83
+ "DEFAULT_NAMESPACE",
84
+ "DQWItem",
85
+ "ExcelRequestOptions",
86
+ "FailedSignInError",
77
87
  "FavoriteItem",
88
+ "FileuploadItem",
89
+ "Filter",
78
90
  "FlowItem",
79
91
  "FlowRunItem",
80
- "FileuploadItem",
92
+ "get_versions",
81
93
  "GroupItem",
94
+ "GroupSetItem",
82
95
  "HourlyInterval",
96
+ "ImageRequestOptions",
83
97
  "IntervalItem",
84
98
  "JobItem",
85
99
  "JWTAuth",
100
+ "LinkedTaskFlowRunItem",
101
+ "LinkedTaskItem",
102
+ "LinkedTaskStepItem",
86
103
  "MetricItem",
104
+ "MissingRequiredFieldError",
87
105
  "MonthlyInterval",
106
+ "NotSignedInError",
107
+ "Pager",
88
108
  "PaginationItem",
109
+ "PDFRequestOptions",
89
110
  "Permission",
90
111
  "PermissionsRule",
91
112
  "PersonalAccessTokenAuth",
92
113
  "ProjectItem",
114
+ "RequestOptions",
115
+ "Resource",
93
116
  "RevisionItem",
94
117
  "ScheduleItem",
95
- "SiteItem",
118
+ "Server",
96
119
  "ServerInfoItem",
120
+ "ServerResponseError",
121
+ "SiteItem",
122
+ "Sort",
97
123
  "SubscriptionItem",
98
- "TableItem",
99
124
  "TableauAuth",
125
+ "TableauItem",
126
+ "TableItem",
100
127
  "Target",
101
128
  "TaskItem",
102
129
  "UserItem",
103
130
  "ViewItem",
131
+ "VirtualConnectionItem",
104
132
  "WebhookItem",
105
133
  "WeeklyInterval",
106
134
  "WorkbookItem",
107
- "CSVRequestOptions",
108
- "ExcelRequestOptions",
109
- "ImageRequestOptions",
110
- "PDFRequestOptions",
111
- "RequestOptions",
112
- "MissingRequiredFieldError",
113
- "NotSignedInError",
114
- "ServerResponseError",
115
- "Filter",
116
- "Pager",
117
- "Server",
118
- "Sort",
119
135
  ]
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-07-27T15:44:04-0700",
11
+ "date": "2024-10-25T16:34:58-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "257cf616f35cc36b24a73e9e102886a52ead1853",
15
- "version": "0.32"
14
+ "full-revisionid": "1d98fdad189ebed130fb904e8fa5dca2207f9011",
15
+ "version": "0.34"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -1,13 +1,27 @@
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
- # The maximum size of a file that can be published in a single request is 64MB
13
- FILESIZE_LIMIT_MB = 64
9
+
10
+ class Config:
11
+ # The maximum size of a file that can be published in a single request is 64MB
12
+ @property
13
+ def FILESIZE_LIMIT_MB(self):
14
+ return min(int(os.getenv("TSC_FILESIZE_LIMIT_MB", 64)), 64)
15
+
16
+ # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
17
+ @property
18
+ def CHUNK_SIZE_MB(self):
19
+ return int(os.getenv("TSC_CHUNK_SIZE_MB", 5 * 10)) # 5MB felt too slow, upped it to 50
20
+
21
+ # Default page size
22
+ @property
23
+ def PAGE_SIZE(self):
24
+ return int(os.getenv("TSC_PAGE_SIZE", 100))
25
+
26
+
27
+ config = Config()
@@ -14,6 +14,7 @@ from tableauserverclient.models.fileupload_item import FileuploadItem
14
14
  from tableauserverclient.models.flow_item import FlowItem
15
15
  from tableauserverclient.models.flow_run_item import FlowRunItem
16
16
  from tableauserverclient.models.group_item import GroupItem
17
+ from tableauserverclient.models.groupset_item import GroupSetItem
17
18
  from tableauserverclient.models.interval_item import (
18
19
  IntervalItem,
19
20
  DailyInterval,
@@ -22,6 +23,11 @@ from tableauserverclient.models.interval_item import (
22
23
  HourlyInterval,
23
24
  )
24
25
  from tableauserverclient.models.job_item import JobItem, BackgroundJobItem
26
+ from tableauserverclient.models.linked_tasks_item import (
27
+ LinkedTaskItem,
28
+ LinkedTaskStepItem,
29
+ LinkedTaskFlowRunItem,
30
+ )
25
31
  from tableauserverclient.models.metric_item import MetricItem
26
32
  from tableauserverclient.models.pagination_item import PaginationItem
27
33
  from tableauserverclient.models.permissions_item import PermissionsRule, Permission
@@ -39,6 +45,7 @@ from tableauserverclient.models.target import Target
39
45
  from tableauserverclient.models.task_item import TaskItem
40
46
  from tableauserverclient.models.user_item import UserItem
41
47
  from tableauserverclient.models.view_item import ViewItem
48
+ from tableauserverclient.models.virtual_connection_item import VirtualConnectionItem
42
49
  from tableauserverclient.models.webhook_item import WebhookItem
43
50
  from tableauserverclient.models.workbook_item import WorkbookItem
44
51
 
@@ -60,6 +67,7 @@ __all__ = [
60
67
  "FlowItem",
61
68
  "FlowRunItem",
62
69
  "GroupItem",
70
+ "GroupSetItem",
63
71
  "IntervalItem",
64
72
  "JobItem",
65
73
  "DailyInterval",
@@ -89,6 +97,10 @@ __all__ = [
89
97
  "TaskItem",
90
98
  "UserItem",
91
99
  "ViewItem",
100
+ "VirtualConnectionItem",
92
101
  "WebhookItem",
93
102
  "WorkbookItem",
103
+ "LinkedTaskItem",
104
+ "LinkedTaskStepItem",
105
+ "LinkedTaskFlowRunItem",
94
106
  ]
@@ -3,7 +3,7 @@ from defusedxml.ElementTree import fromstring
3
3
  from .property_decorators import property_not_empty
4
4
 
5
5
 
6
- class ColumnItem(object):
6
+ class ColumnItem:
7
7
  def __init__(self, name, description=None):
8
8
  self._id = None
9
9
  self.description = description
@@ -1,7 +1,7 @@
1
1
  from .property_decorators import property_is_boolean
2
2
 
3
3
 
4
- class ConnectionCredentials(object):
4
+ class ConnectionCredentials:
5
5
  """Connection Credentials for Workbooks and Datasources publish request.
6
6
 
7
7
  Consider removing this object and other variables holding secrets
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import List, Optional
2
+ from typing import Optional
3
3
 
4
4
  from defusedxml.ElementTree import fromstring
5
5
 
@@ -8,7 +8,7 @@ from .property_decorators import property_is_boolean
8
8
  from tableauserverclient.helpers.logging import logger
9
9
 
10
10
 
11
- class ConnectionItem(object):
11
+ class ConnectionItem:
12
12
  def __init__(self):
13
13
  self._datasource_id: Optional[str] = None
14
14
  self._datasource_name: Optional[str] = None
@@ -48,7 +48,7 @@ class ConnectionItem(object):
48
48
  # if connection type = hyper, Snowflake, or Teradata, we can't change this value: it is always true
49
49
  if self._connection_type in ["hyper", "snowflake", "teradata"]:
50
50
  logger.debug(
51
- "Cannot update value: Query tagging is always enabled for {} connections".format(self._connection_type)
51
+ f"Cannot update value: Query tagging is always enabled for {self._connection_type} connections"
52
52
  )
53
53
  return
54
54
  self._query_tagging = value
@@ -59,19 +59,21 @@ class ConnectionItem(object):
59
59
  )
60
60
 
61
61
  @classmethod
62
- def from_response(cls, resp, ns) -> List["ConnectionItem"]:
62
+ def from_response(cls, resp, ns) -> list["ConnectionItem"]:
63
63
  all_connection_items = list()
64
64
  parsed_response = fromstring(resp)
65
65
  all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns)
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)
@@ -80,7 +82,7 @@ class ConnectionItem(object):
80
82
  return all_connection_items
81
83
 
82
84
  @classmethod
83
- def from_xml_element(cls, parsed_response, ns) -> List["ConnectionItem"]:
85
+ def from_xml_element(cls, parsed_response, ns) -> list["ConnectionItem"]:
84
86
  """
85
87
  <connections>
86
88
  <connection serverAddress="mysql.test.com">
@@ -91,7 +93,7 @@ class ConnectionItem(object):
91
93
  </connection>
92
94
  </connections>
93
95
  """
94
- all_connection_items: List["ConnectionItem"] = list()
96
+ all_connection_items: list["ConnectionItem"] = list()
95
97
  all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns)
96
98
 
97
99
  for connection_xml in all_connection_xml:
@@ -2,7 +2,8 @@ from datetime import datetime
2
2
 
3
3
  from defusedxml import ElementTree
4
4
  from defusedxml.ElementTree import fromstring, tostring
5
- from typing import Callable, List, Optional
5
+ from typing import Callable, Optional
6
+ from collections.abc import Iterator
6
7
 
7
8
  from .exceptions import UnpopulatedPropertyError
8
9
  from .user_item import UserItem
@@ -11,12 +12,14 @@ from .workbook_item import WorkbookItem
11
12
  from ..datetime_helpers import parse_datetime
12
13
 
13
14
 
14
- class CustomViewItem(object):
15
+ class CustomViewItem:
15
16
  def __init__(self, id: Optional[str] = None, name: Optional[str] = None) -> None:
16
17
  self._content_url: Optional[str] = None # ?
17
18
  self._created_at: Optional["datetime"] = None
18
19
  self._id: Optional[str] = id
19
20
  self._image: Optional[Callable[[], bytes]] = None
21
+ self._pdf: Optional[Callable[[], bytes]] = None
22
+ self._csv: Optional[Callable[[], Iterator[bytes]]] = None
20
23
  self._name: Optional[str] = name
21
24
  self._shared: Optional[bool] = False
22
25
  self._updated_at: Optional["datetime"] = None
@@ -35,11 +38,17 @@ class CustomViewItem(object):
35
38
  owner_info = ""
36
39
  if self._owner:
37
40
  owner_info = " owner='{}'".format(self._owner.name or self._owner.id or "unknown")
38
- return "<CustomViewItem id={} name=`{}`{}{}{}>".format(self.id, self.name, view_info, wb_info, owner_info)
41
+ return f"<CustomViewItem id={self.id} name=`{self.name}`{view_info}{wb_info}{owner_info}>"
39
42
 
40
43
  def _set_image(self, image):
41
44
  self._image = image
42
45
 
46
+ def _set_pdf(self, pdf):
47
+ self._pdf = pdf
48
+
49
+ def _set_csv(self, csv):
50
+ self._csv = csv
51
+
43
52
  @property
44
53
  def content_url(self) -> Optional[str]:
45
54
  return self._content_url
@@ -55,10 +64,24 @@ class CustomViewItem(object):
55
64
  @property
56
65
  def image(self) -> bytes:
57
66
  if self._image is None:
58
- error = "View item must be populated with its png image first."
67
+ error = "Custom View item must be populated with its png image first."
59
68
  raise UnpopulatedPropertyError(error)
60
69
  return self._image()
61
70
 
71
+ @property
72
+ def pdf(self) -> bytes:
73
+ if self._pdf is None:
74
+ error = "Custom View item must be populated with its pdf first."
75
+ raise UnpopulatedPropertyError(error)
76
+ return self._pdf()
77
+
78
+ @property
79
+ def csv(self) -> Iterator[bytes]:
80
+ if self._csv is None:
81
+ error = "Custom View item must be populated with its csv first."
82
+ raise UnpopulatedPropertyError(error)
83
+ return self._csv()
84
+
62
85
  @property
63
86
  def name(self) -> Optional[str]:
64
87
  return self._name
@@ -104,7 +127,7 @@ class CustomViewItem(object):
104
127
  return item[0]
105
128
 
106
129
  @classmethod
107
- def list_from_response(cls, resp, ns, workbook_id="") -> List["CustomViewItem"]:
130
+ def list_from_response(cls, resp, ns, workbook_id="") -> list["CustomViewItem"]:
108
131
  return cls.from_xml_element(fromstring(resp), ns, workbook_id)
109
132
 
110
133
  """
@@ -121,7 +144,7 @@ class CustomViewItem(object):
121
144
  """
122
145
 
123
146
  @classmethod
124
- def from_xml_element(cls, parsed_response, ns, workbook_id="") -> List["CustomViewItem"]:
147
+ def from_xml_element(cls, parsed_response, ns, workbook_id="") -> list["CustomViewItem"]:
125
148
  all_view_items = list()
126
149
  all_view_xml = parsed_response.findall(".//t:customView", namespaces=ns)
127
150
  for custom_view_xml in all_view_xml:
@@ -1,8 +1,8 @@
1
1
  from defusedxml.ElementTree import fromstring
2
2
 
3
3
 
4
- class DataAccelerationReportItem(object):
5
- class ComparisonRecord(object):
4
+ class DataAccelerationReportItem:
5
+ class ComparisonRecord:
6
6
  def __init__(
7
7
  self,
8
8
  site,
@@ -1,5 +1,5 @@
1
1
  from datetime import datetime
2
- from typing import List, Optional
2
+ from typing import Optional
3
3
 
4
4
  from defusedxml.ElementTree import fromstring
5
5
 
@@ -10,7 +10,7 @@ from .property_decorators import (
10
10
  )
11
11
 
12
12
 
13
- class DataAlertItem(object):
13
+ class DataAlertItem:
14
14
  class Frequency:
15
15
  Once = "Once"
16
16
  Frequently = "Frequently"
@@ -34,7 +34,7 @@ class DataAlertItem(object):
34
34
  self._workbook_name: Optional[str] = None
35
35
  self._project_id: Optional[str] = None
36
36
  self._project_name: Optional[str] = None
37
- self._recipients: Optional[List[str]] = None
37
+ self._recipients: Optional[list[str]] = None
38
38
 
39
39
  def __repr__(self) -> str:
40
40
  return "<Data Alert {_id} subject={_subject} frequency={_frequency} \
@@ -78,7 +78,7 @@ class DataAlertItem(object):
78
78
  return self._creatorId
79
79
 
80
80
  @property
81
- def recipients(self) -> List[str]:
81
+ def recipients(self) -> list[str]:
82
82
  return self._recipients or list()
83
83
 
84
84
  @property
@@ -174,7 +174,7 @@ class DataAlertItem(object):
174
174
  self._recipients = recipients
175
175
 
176
176
  @classmethod
177
- def from_response(cls, resp, ns) -> List["DataAlertItem"]:
177
+ def from_response(cls, resp, ns) -> list["DataAlertItem"]:
178
178
  all_alert_items = list()
179
179
  parsed_response = fromstring(resp)
180
180
  all_alert_xml = parsed_response.findall(".//t:dataAlert", namespaces=ns)
@@ -1,6 +1,6 @@
1
1
  import xml.etree.ElementTree as ET
2
2
 
3
- from typing import Optional, Union, List
3
+ from typing import Optional
4
4
  from tableauserverclient.models.property_decorators import property_is_enum, property_not_nullable
5
5
  from .interval_item import IntervalItem
6
6
 
@@ -50,11 +50,11 @@ class DataFreshnessPolicyItem:
50
50
  Week = "Week"
51
51
  Month = "Month"
52
52
 
53
- def __init__(self, frequency: str, time: str, timezone, interval_item: Optional[List[str]] = None):
53
+ def __init__(self, frequency: str, time: str, timezone, interval_item: Optional[list[str]] = None):
54
54
  self.frequency = frequency
55
55
  self.time = time
56
56
  self.timezone = timezone
57
- self.interval_item: Optional[List[str]] = interval_item
57
+ self.interval_item: Optional[list[str]] = interval_item
58
58
 
59
59
  def __repr__(self):
60
60
  return (
@@ -62,11 +62,11 @@ class DataFreshnessPolicyItem:
62
62
  ).format(**vars(self))
63
63
 
64
64
  @property
65
- def interval_item(self) -> Optional[List[str]]:
65
+ def interval_item(self) -> Optional[list[str]]:
66
66
  return self._interval_item
67
67
 
68
68
  @interval_item.setter
69
- def interval_item(self, value: List[str]):
69
+ def interval_item(self, value: list[str]):
70
70
  self._interval_item = value
71
71
 
72
72
  @property
@@ -186,7 +186,7 @@ def parse_week_intervals(interval_values):
186
186
 
187
187
 
188
188
  def parse_month_intervals(interval_values):
189
- error = "Invalid interval value for a monthly frequency: {}.".format(interval_values)
189
+ error = f"Invalid interval value for a monthly frequency: {interval_values}."
190
190
 
191
191
  # Month interval can have value either only ['LastDay'] or list of dates e.g. ["1", 20", "30"]
192
192
  # First check if the list only have LastDay value. When using LastDay, there shouldn't be
@@ -10,7 +10,7 @@ from .property_decorators import (
10
10
  )
11
11
 
12
12
 
13
- class DatabaseItem(object):
13
+ class DatabaseItem:
14
14
  class ContentPermissions:
15
15
  LockedToProject = "LockedToDatabase"
16
16
  ManagedByOwner = "ManagedByOwner"
@@ -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 f"<Database {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:
@@ -244,7 +250,7 @@ class DatabaseItem(object):
244
250
  self._tables = tables
245
251
 
246
252
  def _set_default_permissions(self, permissions, content_type):
247
- attr = "_default_{content}_permissions".format(content=content_type)
253
+ attr = f"_default_{content_type}_permissions"
248
254
  setattr(
249
255
  self,
250
256
  attr,
@@ -1,7 +1,7 @@
1
1
  import copy
2
2
  import datetime
3
3
  import xml.etree.ElementTree as ET
4
- from typing import Dict, List, Optional, Set, Tuple
4
+ from typing import Optional
5
5
 
6
6
  from defusedxml.ElementTree import fromstring
7
7
 
@@ -18,14 +18,14 @@ from tableauserverclient.models.revision_item import RevisionItem
18
18
  from tableauserverclient.models.tag_item import TagItem
19
19
 
20
20
 
21
- class DatasourceItem(object):
21
+ class DatasourceItem:
22
22
  class AskDataEnablement:
23
23
  Enabled = "Enabled"
24
24
  Disabled = "Disabled"
25
25
  SiteDefault = "SiteDefault"
26
26
 
27
27
  def __repr__(self):
28
- return "<Datasource {0} '{1}' ({2} parent={3} >".format(
28
+ return "<Datasource {} '{}' ({} parent={} >".format(
29
29
  self._id,
30
30
  self.name,
31
31
  self.description or "No Description",
@@ -44,7 +44,7 @@ class DatasourceItem(object):
44
44
  self._encrypt_extracts = None
45
45
  self._has_extracts = None
46
46
  self._id: Optional[str] = None
47
- self._initial_tags: Set = set()
47
+ self._initial_tags: set = set()
48
48
  self._project_name: Optional[str] = None
49
49
  self._revisions = None
50
50
  self._size: Optional[int] = None
@@ -55,7 +55,7 @@ class DatasourceItem(object):
55
55
  self.name = name
56
56
  self.owner_id: Optional[str] = None
57
57
  self.project_id = project_id
58
- self.tags: Set[str] = set()
58
+ self.tags: set[str] = set()
59
59
 
60
60
  self._permissions = None
61
61
  self._data_quality_warnings = None
@@ -72,14 +72,14 @@ class DatasourceItem(object):
72
72
  self._ask_data_enablement = value
73
73
 
74
74
  @property
75
- def connections(self) -> Optional[List[ConnectionItem]]:
75
+ def connections(self) -> Optional[list[ConnectionItem]]:
76
76
  if self._connections is None:
77
77
  error = "Datasource item must be populated with connections first."
78
78
  raise UnpopulatedPropertyError(error)
79
79
  return self._connections()
80
80
 
81
81
  @property
82
- def permissions(self) -> Optional[List[PermissionsRule]]:
82
+ def permissions(self) -> Optional[list[PermissionsRule]]:
83
83
  if self._permissions is None:
84
84
  error = "Project item must be populated with permissions first."
85
85
  raise UnpopulatedPropertyError(error)
@@ -177,7 +177,7 @@ class DatasourceItem(object):
177
177
  return self._webpage_url
178
178
 
179
179
  @property
180
- def revisions(self) -> List[RevisionItem]:
180
+ def revisions(self) -> list[RevisionItem]:
181
181
  if self._revisions is None:
182
182
  error = "Datasource item must be populated with revisions first."
183
183
  raise UnpopulatedPropertyError(error)
@@ -309,7 +309,7 @@ class DatasourceItem(object):
309
309
  self._size = int(size)
310
310
 
311
311
  @classmethod
312
- def from_response(cls, resp: str, ns: Dict) -> List["DatasourceItem"]:
312
+ def from_response(cls, resp: str, ns: dict) -> list["DatasourceItem"]:
313
313
  all_datasource_items = list()
314
314
  parsed_response = fromstring(resp)
315
315
  all_datasource_xml = parsed_response.findall(".//t:datasource", namespaces=ns)
@@ -326,7 +326,7 @@ class DatasourceItem(object):
326
326
  return datasource_item
327
327
 
328
328
  @staticmethod
329
- def _parse_element(datasource_xml: ET.Element, ns: Dict) -> Tuple:
329
+ def _parse_element(datasource_xml: ET.Element, ns: dict) -> tuple:
330
330
  id_ = datasource_xml.get("id", None)
331
331
  name = datasource_xml.get("name", None)
332
332
  datasource_type = datasource_xml.get("type", None)
@@ -3,7 +3,7 @@ from defusedxml.ElementTree import fromstring
3
3
  from tableauserverclient.datetime_helpers import parse_datetime
4
4
 
5
5
 
6
- class DQWItem(object):
6
+ class DQWItem:
7
7
  class WarningType:
8
8
  WARNING = "WARNING"
9
9
  DEPRECATED = "DEPRECATED"
@@ -1,28 +1,27 @@
1
1
  import logging
2
2
 
3
+ from typing import Union
3
4
  from defusedxml.ElementTree import fromstring
4
- from tableauserverclient.models.tableau_types import TableauItem
5
5
 
6
+ from tableauserverclient.models.tableau_types import TableauItem
6
7
  from tableauserverclient.models.datasource_item import DatasourceItem
7
8
  from tableauserverclient.models.flow_item import FlowItem
8
9
  from tableauserverclient.models.project_item import ProjectItem
9
10
  from tableauserverclient.models.metric_item import MetricItem
10
11
  from tableauserverclient.models.view_item import ViewItem
11
12
  from tableauserverclient.models.workbook_item import WorkbookItem
12
- from typing import Dict, List
13
13
 
14
14
  from tableauserverclient.helpers.logging import logger
15
- from typing import Dict, List, Union
16
15
 
17
- FavoriteType = Dict[
16
+ FavoriteType = dict[
18
17
  str,
19
- List[TableauItem],
18
+ list[TableauItem],
20
19
  ]
21
20
 
22
21
 
23
22
  class FavoriteItem:
24
23
  @classmethod
25
- def from_response(cls, xml: str, namespace: Dict) -> FavoriteType:
24
+ def from_response(cls, xml: Union[str, bytes], namespace: dict) -> FavoriteType:
26
25
  favorites: FavoriteType = {
27
26
  "datasources": [],
28
27
  "flows": [],
@@ -1,7 +1,7 @@
1
1
  from defusedxml.ElementTree import fromstring
2
2
 
3
3
 
4
- class FileuploadItem(object):
4
+ class FileuploadItem:
5
5
  def __init__(self):
6
6
  self._file_size = None
7
7
  self._upload_session_id = None