tableauserverclient 0.33__py3-none-any.whl → 0.35__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 (94) hide show
  1. tableauserverclient/__init__.py +33 -23
  2. tableauserverclient/{_version.py → bin/_version.py} +3 -3
  3. tableauserverclient/config.py +5 -3
  4. tableauserverclient/models/column_item.py +1 -1
  5. tableauserverclient/models/connection_credentials.py +18 -2
  6. tableauserverclient/models/connection_item.py +44 -6
  7. tableauserverclient/models/custom_view_item.py +78 -11
  8. tableauserverclient/models/data_acceleration_report_item.py +2 -2
  9. tableauserverclient/models/data_alert_item.py +5 -5
  10. tableauserverclient/models/data_freshness_policy_item.py +6 -6
  11. tableauserverclient/models/database_item.py +3 -3
  12. tableauserverclient/models/datasource_item.py +10 -10
  13. tableauserverclient/models/dqw_item.py +1 -1
  14. tableauserverclient/models/favorites_item.py +5 -6
  15. tableauserverclient/models/fileupload_item.py +1 -1
  16. tableauserverclient/models/flow_item.py +54 -9
  17. tableauserverclient/models/flow_run_item.py +3 -3
  18. tableauserverclient/models/group_item.py +44 -4
  19. tableauserverclient/models/groupset_item.py +4 -4
  20. tableauserverclient/models/interval_item.py +9 -9
  21. tableauserverclient/models/job_item.py +73 -8
  22. tableauserverclient/models/linked_tasks_item.py +5 -5
  23. tableauserverclient/models/metric_item.py +5 -5
  24. tableauserverclient/models/pagination_item.py +1 -1
  25. tableauserverclient/models/permissions_item.py +12 -10
  26. tableauserverclient/models/project_item.py +73 -19
  27. tableauserverclient/models/property_decorators.py +12 -11
  28. tableauserverclient/models/reference_item.py +2 -2
  29. tableauserverclient/models/revision_item.py +3 -3
  30. tableauserverclient/models/schedule_item.py +2 -2
  31. tableauserverclient/models/server_info_item.py +26 -6
  32. tableauserverclient/models/site_item.py +69 -3
  33. tableauserverclient/models/subscription_item.py +3 -3
  34. tableauserverclient/models/table_item.py +1 -1
  35. tableauserverclient/models/tableau_auth.py +115 -5
  36. tableauserverclient/models/tableau_types.py +2 -2
  37. tableauserverclient/models/tag_item.py +3 -4
  38. tableauserverclient/models/task_item.py +34 -4
  39. tableauserverclient/models/user_item.py +47 -17
  40. tableauserverclient/models/view_item.py +66 -13
  41. tableauserverclient/models/virtual_connection_item.py +6 -5
  42. tableauserverclient/models/webhook_item.py +39 -6
  43. tableauserverclient/models/workbook_item.py +116 -13
  44. tableauserverclient/namespace.py +1 -1
  45. tableauserverclient/server/__init__.py +2 -1
  46. tableauserverclient/server/endpoint/auth_endpoint.py +69 -10
  47. tableauserverclient/server/endpoint/custom_views_endpoint.py +258 -29
  48. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
  49. tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
  50. tableauserverclient/server/endpoint/databases_endpoint.py +13 -12
  51. tableauserverclient/server/endpoint/datasources_endpoint.py +61 -62
  52. tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
  53. tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
  54. tableauserverclient/server/endpoint/endpoint.py +19 -21
  55. tableauserverclient/server/endpoint/exceptions.py +23 -7
  56. tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
  57. tableauserverclient/server/endpoint/fileuploads_endpoint.py +9 -11
  58. tableauserverclient/server/endpoint/flow_runs_endpoint.py +15 -13
  59. tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
  60. tableauserverclient/server/endpoint/flows_endpoint.py +344 -29
  61. tableauserverclient/server/endpoint/groups_endpoint.py +342 -27
  62. tableauserverclient/server/endpoint/groupsets_endpoint.py +2 -2
  63. tableauserverclient/server/endpoint/jobs_endpoint.py +116 -7
  64. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +2 -2
  65. tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
  66. tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
  67. tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
  68. tableauserverclient/server/endpoint/projects_endpoint.py +681 -30
  69. tableauserverclient/server/endpoint/resource_tagger.py +14 -13
  70. tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
  71. tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
  72. tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
  73. tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
  74. tableauserverclient/server/endpoint/tables_endpoint.py +15 -14
  75. tableauserverclient/server/endpoint/tasks_endpoint.py +86 -8
  76. tableauserverclient/server/endpoint/users_endpoint.py +366 -19
  77. tableauserverclient/server/endpoint/views_endpoint.py +262 -20
  78. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +6 -5
  79. tableauserverclient/server/endpoint/webhooks_endpoint.py +88 -11
  80. tableauserverclient/server/endpoint/workbooks_endpoint.py +653 -65
  81. tableauserverclient/server/filter.py +2 -2
  82. tableauserverclient/server/pager.py +29 -6
  83. tableauserverclient/server/query.py +68 -19
  84. tableauserverclient/server/request_factory.py +57 -37
  85. tableauserverclient/server/request_options.py +243 -141
  86. tableauserverclient/server/server.py +76 -10
  87. tableauserverclient/server/sort.py +16 -2
  88. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/METADATA +7 -7
  89. tableauserverclient-0.35.dist-info/RECORD +106 -0
  90. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/WHEEL +1 -1
  91. tableauserverclient-0.33.dist-info/RECORD +0 -106
  92. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE +0 -0
  93. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/LICENSE.versioneer +0 -0
  94. {tableauserverclient-0.33.dist-info → tableauserverclient-0.35.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from tableauserverclient._version import get_versions
1
+ from tableauserverclient.bin._version import get_versions
2
2
  from tableauserverclient.namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE
3
3
  from tableauserverclient.models import (
4
4
  BackgroundJobItem,
@@ -32,11 +32,13 @@ from tableauserverclient.models import (
32
32
  PermissionsRule,
33
33
  PersonalAccessTokenAuth,
34
34
  ProjectItem,
35
+ Resource,
35
36
  RevisionItem,
36
37
  ScheduleItem,
37
38
  SiteItem,
38
39
  ServerInfoItem,
39
40
  SubscriptionItem,
41
+ TableauItem,
40
42
  TableItem,
41
43
  TableauAuth,
42
44
  Target,
@@ -56,6 +58,7 @@ from tableauserverclient.server import (
56
58
  PDFRequestOptions,
57
59
  RequestOptions,
58
60
  MissingRequiredFieldError,
61
+ FailedSignInError,
59
62
  NotSignedInError,
60
63
  ServerResponseError,
61
64
  Filter,
@@ -65,65 +68,72 @@ from tableauserverclient.server import (
65
68
  )
66
69
 
67
70
  __all__ = [
68
- "get_versions",
69
- "DEFAULT_NAMESPACE",
70
71
  "BackgroundJobItem",
71
72
  "BackgroundJobItem",
72
73
  "ColumnItem",
73
74
  "ConnectionCredentials",
74
75
  "ConnectionItem",
76
+ "CSVRequestOptions",
75
77
  "CustomViewItem",
76
- "DQWItem",
77
78
  "DailyInterval",
78
79
  "DataAlertItem",
79
80
  "DatabaseItem",
80
81
  "DataFreshnessPolicyItem",
81
82
  "DatasourceItem",
83
+ "DEFAULT_NAMESPACE",
84
+ "DQWItem",
85
+ "ExcelRequestOptions",
86
+ "FailedSignInError",
82
87
  "FavoriteItem",
88
+ "FileuploadItem",
89
+ "Filter",
83
90
  "FlowItem",
84
91
  "FlowRunItem",
85
- "FileuploadItem",
92
+ "get_versions",
86
93
  "GroupItem",
87
94
  "GroupSetItem",
88
95
  "HourlyInterval",
96
+ "ImageRequestOptions",
89
97
  "IntervalItem",
90
98
  "JobItem",
91
99
  "JWTAuth",
100
+ "LinkedTaskFlowRunItem",
101
+ "LinkedTaskItem",
102
+ "LinkedTaskStepItem",
92
103
  "MetricItem",
104
+ "MissingRequiredFieldError",
93
105
  "MonthlyInterval",
106
+ "NotSignedInError",
107
+ "Pager",
94
108
  "PaginationItem",
109
+ "PDFRequestOptions",
95
110
  "Permission",
96
111
  "PermissionsRule",
97
112
  "PersonalAccessTokenAuth",
98
113
  "ProjectItem",
114
+ "RequestOptions",
115
+ "Resource",
99
116
  "RevisionItem",
100
117
  "ScheduleItem",
101
- "SiteItem",
118
+ "Server",
102
119
  "ServerInfoItem",
120
+ "ServerResponseError",
121
+ "SiteItem",
122
+ "Sort",
103
123
  "SubscriptionItem",
104
- "TableItem",
105
124
  "TableauAuth",
125
+ "TableauItem",
126
+ "TableItem",
106
127
  "Target",
107
128
  "TaskItem",
108
129
  "UserItem",
109
130
  "ViewItem",
131
+ "VirtualConnectionItem",
110
132
  "WebhookItem",
111
133
  "WeeklyInterval",
112
134
  "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
135
  ]
136
+
137
+ from .bin import _version
138
+
139
+ __version__ = _version.get_versions()["version"]
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-09-17T16:51:07-0700",
11
+ "date": "2025-01-03T19:22:57-0800",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "4259316ef2e2656531b0c65c71d043708b37b4a9",
15
- "version": "0.33"
14
+ "full-revisionid": "c5e016fe5320267f795de4252b0dc92fa84495b5",
15
+ "version": "0.35"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -6,11 +6,13 @@ BYTES_PER_MB = 1024 * 1024
6
6
 
7
7
  DELAY_SLEEP_SECONDS = 0.1
8
8
 
9
- # The maximum size of a file that can be published in a single request is 64MB
10
- FILESIZE_LIMIT_MB = 64
11
-
12
9
 
13
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
+
14
16
  # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
15
17
  @property
16
18
  def CHUNK_SIZE_MB(self):
@@ -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,12 +1,28 @@
1
1
  from .property_decorators import property_is_boolean
2
2
 
3
3
 
4
- class ConnectionCredentials(object):
5
- """Connection Credentials for Workbooks and Datasources publish request.
4
+ class ConnectionCredentials:
5
+ """
6
+ Connection Credentials for Workbooks and Datasources publish request.
6
7
 
7
8
  Consider removing this object and other variables holding secrets
8
9
  as soon as possible after use to avoid them hanging around in memory.
9
10
 
11
+ Parameters
12
+ ----------
13
+ name: str
14
+ The username for the connection.
15
+
16
+ password: str
17
+ The password used for the connection.
18
+
19
+ embed: bool, default True
20
+ Determines whether to embed the password (True) for the workbook or data source connection or not (False).
21
+
22
+ oauth: bool, default False
23
+ Determines whether to use OAuth for the connection (True) or not (False).
24
+ For more information see: https://help.tableau.com/current/server/en-us/protected_auth.htm
25
+
10
26
  """
11
27
 
12
28
  def __init__(self, name, password, embed=True, oauth=False):
@@ -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,45 @@ 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
+ """
13
+ Corresponds to workbook and data source connections.
14
+
15
+ Attributes
16
+ ----------
17
+ datasource_id: str
18
+ The identifier of the data source.
19
+
20
+ datasource_name: str
21
+ The name of the data source.
22
+
23
+ id: str
24
+ The identifier of the connection.
25
+
26
+ connection_type: str
27
+ The type of connection.
28
+
29
+ username: str
30
+ The username for the connection. (see ConnectionCredentials)
31
+
32
+ password: str
33
+ The password used for the connection. (see ConnectionCredentials)
34
+
35
+ embed_password: bool
36
+ Determines whether to embed the password (True) for the workbook or data source connection or not (False). (see ConnectionCredentials)
37
+
38
+ server_address: str
39
+ The server address for the connection.
40
+
41
+ server_port: str
42
+ The port used for the connection.
43
+
44
+ connection_credentials: ConnectionCredentials
45
+ The Connection Credentials object containing authentication details for
46
+ the connection. Replaces username/password/embed_password when
47
+ publishing a flow, document or workbook file in the request body.
48
+ """
49
+
12
50
  def __init__(self):
13
51
  self._datasource_id: Optional[str] = None
14
52
  self._datasource_name: Optional[str] = None
@@ -48,7 +86,7 @@ class ConnectionItem(object):
48
86
  # if connection type = hyper, Snowflake, or Teradata, we can't change this value: it is always true
49
87
  if self._connection_type in ["hyper", "snowflake", "teradata"]:
50
88
  logger.debug(
51
- "Cannot update value: Query tagging is always enabled for {} connections".format(self._connection_type)
89
+ f"Cannot update value: Query tagging is always enabled for {self._connection_type} connections"
52
90
  )
53
91
  return
54
92
  self._query_tagging = value
@@ -59,7 +97,7 @@ class ConnectionItem(object):
59
97
  )
60
98
 
61
99
  @classmethod
62
- def from_response(cls, resp, ns) -> List["ConnectionItem"]:
100
+ def from_response(cls, resp, ns) -> list["ConnectionItem"]:
63
101
  all_connection_items = list()
64
102
  parsed_response = fromstring(resp)
65
103
  all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns)
@@ -82,7 +120,7 @@ class ConnectionItem(object):
82
120
  return all_connection_items
83
121
 
84
122
  @classmethod
85
- def from_xml_element(cls, parsed_response, ns) -> List["ConnectionItem"]:
123
+ def from_xml_element(cls, parsed_response, ns) -> list["ConnectionItem"]:
86
124
  """
87
125
  <connections>
88
126
  <connection serverAddress="mysql.test.com">
@@ -93,7 +131,7 @@ class ConnectionItem(object):
93
131
  </connection>
94
132
  </connections>
95
133
  """
96
- all_connection_items: List["ConnectionItem"] = list()
134
+ all_connection_items: list["ConnectionItem"] = list()
97
135
  all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns)
98
136
 
99
137
  for connection_xml in all_connection_xml:
@@ -2,21 +2,68 @@ 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
- from .exceptions import UnpopulatedPropertyError
8
- from .user_item import UserItem
9
- from .view_item import ViewItem
10
- from .workbook_item import WorkbookItem
11
- from ..datetime_helpers import parse_datetime
8
+ from tableauserverclient.models.exceptions import UnpopulatedPropertyError
9
+ from tableauserverclient.models.user_item import UserItem
10
+ from tableauserverclient.models.view_item import ViewItem
11
+ from tableauserverclient.models.workbook_item import WorkbookItem
12
+ from tableauserverclient.datetime_helpers import parse_datetime
12
13
 
13
14
 
14
- class CustomViewItem(object):
15
+ class CustomViewItem:
16
+ """
17
+ Represents a Custom View item on Tableau Server.
18
+
19
+ Parameters
20
+ ----------
21
+ id : Optional[str]
22
+ The ID of the Custom View item.
23
+
24
+ name : Optional[str]
25
+ The name of the Custom View item.
26
+
27
+ Attributes
28
+ ----------
29
+ content_url : Optional[str]
30
+ The content URL of the Custom View item.
31
+
32
+ created_at : Optional[datetime]
33
+ The date and time the Custom View item was created.
34
+
35
+ image: bytes
36
+ The image of the Custom View item. Must be populated first.
37
+
38
+ pdf: bytes
39
+ The PDF of the Custom View item. Must be populated first.
40
+
41
+ csv: Iterator[bytes]
42
+ The CSV of the Custom View item. Must be populated first.
43
+
44
+ shared : Optional[bool]
45
+ Whether the Custom View item is shared.
46
+
47
+ updated_at : Optional[datetime]
48
+ The date and time the Custom View item was last updated.
49
+
50
+ owner : Optional[UserItem]
51
+ The id of the owner of the Custom View item.
52
+
53
+ workbook : Optional[WorkbookItem]
54
+ The id of the workbook the Custom View item belongs to.
55
+
56
+ view : Optional[ViewItem]
57
+ The id of the view the Custom View item belongs to.
58
+ """
59
+
15
60
  def __init__(self, id: Optional[str] = None, name: Optional[str] = None) -> None:
16
61
  self._content_url: Optional[str] = None # ?
17
62
  self._created_at: Optional["datetime"] = None
18
63
  self._id: Optional[str] = id
19
64
  self._image: Optional[Callable[[], bytes]] = None
65
+ self._pdf: Optional[Callable[[], bytes]] = None
66
+ self._csv: Optional[Callable[[], Iterator[bytes]]] = None
20
67
  self._name: Optional[str] = name
21
68
  self._shared: Optional[bool] = False
22
69
  self._updated_at: Optional["datetime"] = None
@@ -35,11 +82,17 @@ class CustomViewItem(object):
35
82
  owner_info = ""
36
83
  if self._owner:
37
84
  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)
85
+ return f"<CustomViewItem id={self.id} name=`{self.name}`{view_info}{wb_info}{owner_info}>"
39
86
 
40
87
  def _set_image(self, image):
41
88
  self._image = image
42
89
 
90
+ def _set_pdf(self, pdf):
91
+ self._pdf = pdf
92
+
93
+ def _set_csv(self, csv):
94
+ self._csv = csv
95
+
43
96
  @property
44
97
  def content_url(self) -> Optional[str]:
45
98
  return self._content_url
@@ -55,10 +108,24 @@ class CustomViewItem(object):
55
108
  @property
56
109
  def image(self) -> bytes:
57
110
  if self._image is None:
58
- error = "View item must be populated with its png image first."
111
+ error = "Custom View item must be populated with its png image first."
59
112
  raise UnpopulatedPropertyError(error)
60
113
  return self._image()
61
114
 
115
+ @property
116
+ def pdf(self) -> bytes:
117
+ if self._pdf is None:
118
+ error = "Custom View item must be populated with its pdf first."
119
+ raise UnpopulatedPropertyError(error)
120
+ return self._pdf()
121
+
122
+ @property
123
+ def csv(self) -> Iterator[bytes]:
124
+ if self._csv is None:
125
+ error = "Custom View item must be populated with its csv first."
126
+ raise UnpopulatedPropertyError(error)
127
+ return self._csv()
128
+
62
129
  @property
63
130
  def name(self) -> Optional[str]:
64
131
  return self._name
@@ -104,7 +171,7 @@ class CustomViewItem(object):
104
171
  return item[0]
105
172
 
106
173
  @classmethod
107
- def list_from_response(cls, resp, ns, workbook_id="") -> List["CustomViewItem"]:
174
+ def list_from_response(cls, resp, ns, workbook_id="") -> list["CustomViewItem"]:
108
175
  return cls.from_xml_element(fromstring(resp), ns, workbook_id)
109
176
 
110
177
  """
@@ -121,7 +188,7 @@ class CustomViewItem(object):
121
188
  """
122
189
 
123
190
  @classmethod
124
- def from_xml_element(cls, parsed_response, ns, workbook_id="") -> List["CustomViewItem"]:
191
+ def from_xml_element(cls, parsed_response, ns, workbook_id="") -> list["CustomViewItem"]:
125
192
  all_view_items = list()
126
193
  all_view_xml = parsed_response.findall(".//t:customView", namespaces=ns)
127
194
  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"
@@ -45,7 +45,7 @@ class DatabaseItem(object):
45
45
  self._tables = None # Not implemented yet
46
46
 
47
47
  def __str__(self):
48
- return "<Database {0} '{1}'>".format(self._id, self.name)
48
+ return f"<Database {self._id} '{self.name}'>"
49
49
 
50
50
  def __repr__(self):
51
51
  return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"
@@ -250,7 +250,7 @@ class DatabaseItem(object):
250
250
  self._tables = tables
251
251
 
252
252
  def _set_default_permissions(self, permissions, content_type):
253
- attr = "_default_{content}_permissions".format(content=content_type)
253
+ attr = f"_default_{content_type}_permissions"
254
254
  setattr(
255
255
  self,
256
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": [],