tableauserverclient 0.37__py3-none-any.whl → 0.39__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 (118) hide show
  1. tableauserverclient/bin/_version.py → _version.py +3 -3
  2. bin/__init__.py +3 -0
  3. bin/_version.py +21 -0
  4. {tableauserverclient/helpers → helpers}/strings.py +25 -1
  5. {tableauserverclient/models → models}/__init__.py +15 -1
  6. models/collection_item.py +52 -0
  7. {tableauserverclient/models → models}/connection_item.py +16 -2
  8. {tableauserverclient/models → models}/custom_view_item.py +8 -0
  9. {tableauserverclient/models → models}/data_freshness_policy_item.py +3 -3
  10. {tableauserverclient/models → models}/datasource_item.py +113 -3
  11. models/extensions_item.py +186 -0
  12. models/extract_item.py +82 -0
  13. {tableauserverclient/models → models}/favorites_item.py +21 -8
  14. {tableauserverclient/models → models}/flow_item.py +3 -3
  15. {tableauserverclient/models → models}/group_item.py +18 -1
  16. {tableauserverclient/models → models}/groupset_item.py +14 -0
  17. {tableauserverclient/models → models}/interval_item.py +42 -1
  18. models/location_item.py +53 -0
  19. models/oidc_item.py +82 -0
  20. {tableauserverclient/models → models}/permissions_item.py +2 -0
  21. {tableauserverclient/models → models}/project_item.py +141 -29
  22. {tableauserverclient/models → models}/property_decorators.py +2 -2
  23. {tableauserverclient/models → models}/reference_item.py +12 -6
  24. {tableauserverclient/models → models}/schedule_item.py +67 -1
  25. {tableauserverclient/models → models}/site_item.py +54 -0
  26. {tableauserverclient/models → models}/table_item.py +7 -3
  27. {tableauserverclient/models → models}/tableau_auth.py +13 -6
  28. {tableauserverclient/models → models}/tableau_types.py +13 -1
  29. {tableauserverclient/models → models}/user_item.py +111 -4
  30. {tableauserverclient/models → models}/view_item.py +79 -5
  31. {tableauserverclient/models → models}/workbook_item.py +153 -3
  32. {tableauserverclient/server → server}/endpoint/__init__.py +4 -0
  33. {tableauserverclient/server → server}/endpoint/databases_endpoint.py +101 -18
  34. {tableauserverclient/server → server}/endpoint/datasources_endpoint.py +155 -25
  35. {tableauserverclient/server → server}/endpoint/dqw_endpoint.py +16 -6
  36. {tableauserverclient/server → server}/endpoint/endpoint.py +39 -0
  37. server/endpoint/extensions_endpoint.py +79 -0
  38. {tableauserverclient/server → server}/endpoint/flow_task_endpoint.py +1 -1
  39. {tableauserverclient/server → server}/endpoint/flows_endpoint.py +5 -4
  40. server/endpoint/oidc_endpoint.py +157 -0
  41. {tableauserverclient/server → server}/endpoint/projects_endpoint.py +12 -0
  42. server/endpoint/schedules_endpoint.py +328 -0
  43. {tableauserverclient/server → server}/endpoint/sites_endpoint.py +18 -1
  44. {tableauserverclient/server → server}/endpoint/tables_endpoint.py +140 -17
  45. {tableauserverclient/server → server}/endpoint/users_endpoint.py +296 -10
  46. {tableauserverclient/server → server}/endpoint/views_endpoint.py +23 -0
  47. {tableauserverclient/server → server}/endpoint/workbooks_endpoint.py +124 -9
  48. {tableauserverclient/server → server}/query.py +36 -0
  49. {tableauserverclient/server → server}/request_factory.py +286 -2
  50. {tableauserverclient/server → server}/request_options.py +139 -3
  51. {tableauserverclient/server → server}/server.py +46 -0
  52. {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/METADATA +5 -26
  53. tableauserverclient-0.39.dist-info/RECORD +107 -0
  54. {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/WHEEL +1 -1
  55. tableauserverclient-0.39.dist-info/top_level.txt +4 -0
  56. tableauserverclient/__init__.py +0 -141
  57. tableauserverclient/config.py +0 -27
  58. tableauserverclient/datetime_helpers.py +0 -45
  59. tableauserverclient/exponential_backoff.py +0 -30
  60. tableauserverclient/filesys_helpers.py +0 -63
  61. tableauserverclient/namespace.py +0 -37
  62. tableauserverclient/py.typed +0 -0
  63. tableauserverclient/server/endpoint/schedules_endpoint.py +0 -151
  64. tableauserverclient-0.37.dist-info/RECORD +0 -106
  65. tableauserverclient-0.37.dist-info/licenses/LICENSE.versioneer +0 -7
  66. tableauserverclient-0.37.dist-info/top_level.txt +0 -1
  67. {tableauserverclient/helpers → helpers}/__init__.py +0 -0
  68. {tableauserverclient/helpers → helpers}/headers.py +0 -0
  69. {tableauserverclient/helpers → helpers}/logging.py +0 -0
  70. {tableauserverclient/models → models}/column_item.py +0 -0
  71. {tableauserverclient/models → models}/connection_credentials.py +0 -0
  72. {tableauserverclient/models → models}/data_acceleration_report_item.py +0 -0
  73. {tableauserverclient/models → models}/data_alert_item.py +0 -0
  74. {tableauserverclient/models → models}/database_item.py +0 -0
  75. {tableauserverclient/models → models}/dqw_item.py +0 -0
  76. {tableauserverclient/models → models}/exceptions.py +0 -0
  77. {tableauserverclient/models → models}/fileupload_item.py +0 -0
  78. {tableauserverclient/models → models}/flow_run_item.py +0 -0
  79. {tableauserverclient/models → models}/job_item.py +0 -0
  80. {tableauserverclient/models → models}/linked_tasks_item.py +0 -0
  81. {tableauserverclient/models → models}/metric_item.py +0 -0
  82. {tableauserverclient/models → models}/pagination_item.py +0 -0
  83. {tableauserverclient/models → models}/revision_item.py +0 -0
  84. {tableauserverclient/models → models}/server_info_item.py +0 -0
  85. {tableauserverclient/models → models}/subscription_item.py +0 -0
  86. {tableauserverclient/models → models}/tag_item.py +0 -0
  87. {tableauserverclient/models → models}/target.py +0 -0
  88. {tableauserverclient/models → models}/task_item.py +0 -0
  89. {tableauserverclient/models → models}/virtual_connection_item.py +0 -0
  90. {tableauserverclient/models → models}/webhook_item.py +0 -0
  91. {tableauserverclient/server → server}/__init__.py +0 -0
  92. {tableauserverclient/server → server}/endpoint/auth_endpoint.py +0 -0
  93. {tableauserverclient/server → server}/endpoint/custom_views_endpoint.py +0 -0
  94. {tableauserverclient/server → server}/endpoint/data_acceleration_report_endpoint.py +0 -0
  95. {tableauserverclient/server → server}/endpoint/data_alert_endpoint.py +0 -0
  96. {tableauserverclient/server → server}/endpoint/default_permissions_endpoint.py +0 -0
  97. {tableauserverclient/server → server}/endpoint/exceptions.py +0 -0
  98. {tableauserverclient/server → server}/endpoint/favorites_endpoint.py +0 -0
  99. {tableauserverclient/server → server}/endpoint/fileuploads_endpoint.py +0 -0
  100. {tableauserverclient/server → server}/endpoint/flow_runs_endpoint.py +0 -0
  101. {tableauserverclient/server → server}/endpoint/groups_endpoint.py +0 -0
  102. {tableauserverclient/server → server}/endpoint/groupsets_endpoint.py +0 -0
  103. {tableauserverclient/server → server}/endpoint/jobs_endpoint.py +0 -0
  104. {tableauserverclient/server → server}/endpoint/linked_tasks_endpoint.py +0 -0
  105. {tableauserverclient/server → server}/endpoint/metadata_endpoint.py +0 -0
  106. {tableauserverclient/server → server}/endpoint/metrics_endpoint.py +0 -0
  107. {tableauserverclient/server → server}/endpoint/permissions_endpoint.py +0 -0
  108. {tableauserverclient/server → server}/endpoint/resource_tagger.py +0 -0
  109. {tableauserverclient/server → server}/endpoint/server_info_endpoint.py +0 -0
  110. {tableauserverclient/server → server}/endpoint/subscriptions_endpoint.py +0 -0
  111. {tableauserverclient/server → server}/endpoint/tasks_endpoint.py +0 -0
  112. {tableauserverclient/server → server}/endpoint/virtual_connections_endpoint.py +0 -0
  113. {tableauserverclient/server → server}/endpoint/webhooks_endpoint.py +0 -0
  114. {tableauserverclient/server → server}/exceptions.py +0 -0
  115. {tableauserverclient/server → server}/filter.py +0 -0
  116. {tableauserverclient/server → server}/pager.py +0 -0
  117. {tableauserverclient/server → server}/sort.py +0 -0
  118. {tableauserverclient-0.37.dist-info → tableauserverclient-0.39.dist-info}/licenses/LICENSE +0 -0
@@ -6,6 +6,7 @@ from tableauserverclient.server.endpoint.databases_endpoint import Databases
6
6
  from tableauserverclient.server.endpoint.datasources_endpoint import Datasources
7
7
  from tableauserverclient.server.endpoint.endpoint import Endpoint, QuerysetEndpoint
8
8
  from tableauserverclient.server.endpoint.exceptions import ServerResponseError, MissingRequiredFieldError
9
+ from tableauserverclient.server.endpoint.extensions_endpoint import Extensions
9
10
  from tableauserverclient.server.endpoint.favorites_endpoint import Favorites
10
11
  from tableauserverclient.server.endpoint.fileuploads_endpoint import Fileuploads
11
12
  from tableauserverclient.server.endpoint.flow_runs_endpoint import FlowRuns
@@ -17,6 +18,7 @@ from tableauserverclient.server.endpoint.jobs_endpoint import Jobs
17
18
  from tableauserverclient.server.endpoint.linked_tasks_endpoint import LinkedTasks
18
19
  from tableauserverclient.server.endpoint.metadata_endpoint import Metadata
19
20
  from tableauserverclient.server.endpoint.metrics_endpoint import Metrics
21
+ from tableauserverclient.server.endpoint.oidc_endpoint import OIDC
20
22
  from tableauserverclient.server.endpoint.projects_endpoint import Projects
21
23
  from tableauserverclient.server.endpoint.schedules_endpoint import Schedules
22
24
  from tableauserverclient.server.endpoint.server_info_endpoint import ServerInfo
@@ -41,6 +43,7 @@ __all__ = [
41
43
  "QuerysetEndpoint",
42
44
  "MissingRequiredFieldError",
43
45
  "Endpoint",
46
+ "Extensions",
44
47
  "Favorites",
45
48
  "Fileuploads",
46
49
  "FlowRuns",
@@ -52,6 +55,7 @@ __all__ = [
52
55
  "LinkedTasks",
53
56
  "Metadata",
54
57
  "Metrics",
58
+ "OIDC",
55
59
  "Projects",
56
60
  "Schedules",
57
61
  "ServerInfo",
@@ -1,7 +1,8 @@
1
1
  import logging
2
- from typing import Union
2
+ from typing import TYPE_CHECKING, Optional, Union
3
3
  from collections.abc import Iterable
4
4
 
5
+ from tableauserverclient.models.permissions_item import PermissionsRule
5
6
  from tableauserverclient.server.endpoint.default_permissions_endpoint import _DefaultPermissionsEndpoint
6
7
  from tableauserverclient.server.endpoint.dqw_endpoint import _DataQualityWarningEndpoint
7
8
  from tableauserverclient.server.endpoint.endpoint import api, Endpoint
@@ -13,6 +14,10 @@ from tableauserverclient.models import DatabaseItem, TableItem, PaginationItem,
13
14
 
14
15
  from tableauserverclient.helpers.logging import logger
15
16
 
17
+ if TYPE_CHECKING:
18
+ from tableauserverclient.models.dqw_item import DQWItem
19
+ from tableauserverclient.server.request_options import RequestOptions
20
+
16
21
 
17
22
  class Databases(Endpoint, TaggingMixin):
18
23
  def __init__(self, parent_srv):
@@ -23,11 +28,29 @@ class Databases(Endpoint, TaggingMixin):
23
28
  self._data_quality_warnings = _DataQualityWarningEndpoint(parent_srv, Resource.Database)
24
29
 
25
30
  @property
26
- def baseurl(self):
31
+ def baseurl(self) -> str:
27
32
  return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/databases"
28
33
 
29
34
  @api(version="3.5")
30
- def get(self, req_options=None):
35
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[DatabaseItem], PaginationItem]:
36
+ """
37
+ Get information about all databases on the site. Endpoint is paginated,
38
+ and will return a default of 100 items per page. Use the `req_options`
39
+ parameter to customize the request.
40
+
41
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_databases
42
+
43
+ Parameters
44
+ ----------
45
+ req_options : RequestOptions, optional
46
+ Options to customize the request. If not provided, defaults to None.
47
+
48
+ Returns
49
+ -------
50
+ tuple[list[DatabaseItem], PaginationItem]
51
+ A tuple containing a list of DatabaseItem objects and a
52
+ PaginationItem object.
53
+ """
31
54
  logger.info("Querying all databases on site")
32
55
  url = self.baseurl
33
56
  server_response = self.get_request(url, req_options)
@@ -37,7 +60,27 @@ class Databases(Endpoint, TaggingMixin):
37
60
 
38
61
  # Get 1 database
39
62
  @api(version="3.5")
40
- def get_by_id(self, database_id):
63
+ def get_by_id(self, database_id: str) -> DatabaseItem:
64
+ """
65
+ Get information about a single database asset on the site.
66
+
67
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#query_database
68
+
69
+ Parameters
70
+ ----------
71
+ database_id : str
72
+ The ID of the database to retrieve.
73
+
74
+ Returns
75
+ -------
76
+ DatabaseItem
77
+ A DatabaseItem object representing the database.
78
+
79
+ Raises
80
+ ------
81
+ ValueError
82
+ If the database ID is undefined.
83
+ """
41
84
  if not database_id:
42
85
  error = "database ID undefined."
43
86
  raise ValueError(error)
@@ -47,7 +90,24 @@ class Databases(Endpoint, TaggingMixin):
47
90
  return DatabaseItem.from_response(server_response.content, self.parent_srv.namespace)[0]
48
91
 
49
92
  @api(version="3.5")
50
- def delete(self, database_id):
93
+ def delete(self, database_id: str) -> None:
94
+ """
95
+ Deletes a single database asset from the server.
96
+
97
+ Parameters
98
+ ----------
99
+ database_id : str
100
+ The ID of the database to delete.
101
+
102
+ Returns
103
+ -------
104
+ None
105
+
106
+ Raises
107
+ ------
108
+ ValueError
109
+ If the database ID is undefined.
110
+ """
51
111
  if not database_id:
52
112
  error = "Database ID undefined."
53
113
  raise ValueError(error)
@@ -56,7 +116,28 @@ class Databases(Endpoint, TaggingMixin):
56
116
  logger.info(f"Deleted single database (ID: {database_id})")
57
117
 
58
118
  @api(version="3.5")
59
- def update(self, database_item):
119
+ def update(self, database_item: DatabaseItem) -> DatabaseItem:
120
+ """
121
+ Update the database description, certify the database, set permissions,
122
+ or assign a User as the database contact.
123
+
124
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_metadata.htm#update_database
125
+
126
+ Parameters
127
+ ----------
128
+ database_item : DatabaseItem
129
+ The DatabaseItem object to update.
130
+
131
+ Returns
132
+ -------
133
+ DatabaseItem
134
+ The updated DatabaseItem object.
135
+
136
+ Raises
137
+ ------
138
+ MissingRequiredFieldError
139
+ If the database item is missing an ID.
140
+ """
60
141
  if not database_item.id:
61
142
  error = "Database item missing ID."
62
143
  raise MissingRequiredFieldError(error)
@@ -88,43 +169,45 @@ class Databases(Endpoint, TaggingMixin):
88
169
  return tables
89
170
 
90
171
  @api(version="3.5")
91
- def populate_permissions(self, item):
172
+ def populate_permissions(self, item: DatabaseItem) -> None:
92
173
  self._permissions.populate(item)
93
174
 
94
175
  @api(version="3.5")
95
- def update_permissions(self, item, rules):
176
+ def update_permissions(self, item: DatabaseItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
96
177
  return self._permissions.update(item, rules)
97
178
 
98
179
  @api(version="3.5")
99
- def delete_permission(self, item, rules):
180
+ def delete_permission(self, item: DatabaseItem, rules: list[PermissionsRule]) -> None:
100
181
  self._permissions.delete(item, rules)
101
182
 
102
183
  @api(version="3.5")
103
- def populate_table_default_permissions(self, item):
184
+ def populate_table_default_permissions(self, item: DatabaseItem):
104
185
  self._default_permissions.populate_default_permissions(item, Resource.Table)
105
186
 
106
187
  @api(version="3.5")
107
- def update_table_default_permissions(self, item):
108
- return self._default_permissions.update_default_permissions(item, Resource.Table)
188
+ def update_table_default_permissions(
189
+ self, item: DatabaseItem, rules: list[PermissionsRule]
190
+ ) -> list[PermissionsRule]:
191
+ return self._default_permissions.update_default_permissions(item, rules, Resource.Table)
109
192
 
110
193
  @api(version="3.5")
111
- def delete_table_default_permissions(self, item):
112
- self._default_permissions.delete_default_permission(item, Resource.Table)
194
+ def delete_table_default_permissions(self, rule: PermissionsRule, item: DatabaseItem) -> None:
195
+ self._default_permissions.delete_default_permission(item, rule, Resource.Table)
113
196
 
114
197
  @api(version="3.5")
115
- def populate_dqw(self, item):
198
+ def populate_dqw(self, item: DatabaseItem) -> None:
116
199
  self._data_quality_warnings.populate(item)
117
200
 
118
201
  @api(version="3.5")
119
- def update_dqw(self, item, warning):
202
+ def update_dqw(self, item: DatabaseItem, warning: "DQWItem") -> list["DQWItem"]:
120
203
  return self._data_quality_warnings.update(item, warning)
121
204
 
122
205
  @api(version="3.5")
123
- def add_dqw(self, item, warning):
206
+ def add_dqw(self, item: DatabaseItem, warning: "DQWItem") -> list["DQWItem"]:
124
207
  return self._data_quality_warnings.add(item, warning)
125
208
 
126
209
  @api(version="3.5")
127
- def delete_dqw(self, item):
210
+ def delete_dqw(self, item: DatabaseItem) -> None:
128
211
  self._data_quality_warnings.clear(item)
129
212
 
130
213
  @api(version="3.9")
@@ -6,8 +6,8 @@ import os
6
6
 
7
7
  from contextlib import closing
8
8
  from pathlib import Path
9
- from typing import Literal, Optional, TYPE_CHECKING, Union, overload
10
- from collections.abc import Iterable, Mapping, Sequence
9
+ from typing import Literal, Optional, TYPE_CHECKING, TypedDict, TypeVar, Union, overload
10
+ from collections.abc import Iterable, Sequence
11
11
 
12
12
  from tableauserverclient.helpers.headers import fix_filename
13
13
  from tableauserverclient.models.dqw_item import DQWItem
@@ -50,13 +50,50 @@ FilePath = Union[str, os.PathLike]
50
50
  FileObject = Union[io.BufferedReader, io.BytesIO]
51
51
  PathOrFile = Union[FilePath, FileObject]
52
52
 
53
- FilePath = Union[str, os.PathLike]
54
53
  FileObjectR = Union[io.BufferedReader, io.BytesIO]
55
54
  FileObjectW = Union[io.BufferedWriter, io.BytesIO]
56
55
  PathOrFileR = Union[FilePath, FileObjectR]
57
56
  PathOrFileW = Union[FilePath, FileObjectW]
58
57
 
59
58
 
59
+ HyperActionCondition = TypedDict(
60
+ "HyperActionCondition",
61
+ {
62
+ "op": str,
63
+ "target-col": str,
64
+ "source-col": str,
65
+ },
66
+ )
67
+
68
+ HyperActionRow = TypedDict(
69
+ "HyperActionRow",
70
+ {
71
+ "action": Literal[
72
+ "update",
73
+ "upsert",
74
+ "delete",
75
+ ],
76
+ "source-table": str,
77
+ "target-table": str,
78
+ "condition": HyperActionCondition,
79
+ },
80
+ )
81
+
82
+ HyperActionTable = TypedDict(
83
+ "HyperActionTable",
84
+ {
85
+ "action": Literal[
86
+ "insert",
87
+ "replace",
88
+ ],
89
+ "source-table": str,
90
+ "target-table": str,
91
+ },
92
+ )
93
+
94
+ HyperAction = Union[HyperActionTable, HyperActionRow]
95
+
96
+
60
97
  class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]):
61
98
  def __init__(self, parent_srv: "Server") -> None:
62
99
  super().__init__(parent_srv)
@@ -191,16 +228,34 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
191
228
  self.delete_request(url)
192
229
  logger.info(f"Deleted single datasource (ID: {datasource_id})")
193
230
 
231
+ T = TypeVar("T", bound=FileObjectW)
232
+
233
+ @overload
234
+ def download(
235
+ self,
236
+ datasource_id: str,
237
+ filepath: T,
238
+ include_extract: bool = True,
239
+ ) -> T: ...
240
+
241
+ @overload
242
+ def download(
243
+ self,
244
+ datasource_id: str,
245
+ filepath: Optional[FilePath] = None,
246
+ include_extract: bool = True,
247
+ ) -> str: ...
248
+
194
249
  # Download 1 datasource by id
195
250
  @api(version="2.0")
196
251
  @parameter_added_in(no_extract="2.5")
197
252
  @parameter_added_in(include_extract="2.5")
198
253
  def download(
199
254
  self,
200
- datasource_id: str,
201
- filepath: Optional[PathOrFileW] = None,
202
- include_extract: bool = True,
203
- ) -> PathOrFileW:
255
+ datasource_id,
256
+ filepath=None,
257
+ include_extract=True,
258
+ ):
204
259
  """
205
260
  Downloads the specified data source from a site. The data source is
206
261
  downloaded as a .tdsx file.
@@ -319,8 +374,63 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
319
374
  logger.info(f"Updated datasource item (ID: {datasource_item.id} & connection item {connection_item.id}")
320
375
  return connection
321
376
 
377
+ @api(version="3.26")
378
+ def update_connections(
379
+ self,
380
+ datasource_item: DatasourceItem,
381
+ connection_luids: Iterable[str],
382
+ authentication_type: str,
383
+ username: Optional[str] = None,
384
+ password: Optional[str] = None,
385
+ embed_password: Optional[bool] = None,
386
+ ) -> list[ConnectionItem]:
387
+ """
388
+ Bulk updates one or more datasource connections by LUID.
389
+
390
+ Parameters
391
+ ----------
392
+ datasource_item : DatasourceItem
393
+ The datasource item containing the connections.
394
+
395
+ connection_luids : Iterable of str
396
+ The connection LUIDs to update.
397
+
398
+ authentication_type : str
399
+ The authentication type to use (e.g., 'auth-keypair').
400
+
401
+ username : str, optional
402
+ The username to set.
403
+
404
+ password : str, optional
405
+ The password or secret to set.
406
+
407
+ embed_password : bool, optional
408
+ Whether to embed the password.
409
+
410
+ Returns
411
+ -------
412
+ Iterable of str
413
+ The connection LUIDs that were updated.
414
+ """
415
+
416
+ url = f"{self.baseurl}/{datasource_item.id}/connections"
417
+
418
+ request_body = RequestFactory.Datasource.update_connections_req(
419
+ connection_luids=connection_luids,
420
+ authentication_type=authentication_type,
421
+ username=username,
422
+ password=password,
423
+ embed_password=embed_password,
424
+ )
425
+ server_response = self.put_request(url, request_body)
426
+ connection_items = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)
427
+ updated_ids: list[str] = [conn.id for conn in connection_items]
428
+
429
+ logger.info(f"Updated connections for datasource {datasource_item.id}: {', '.join(updated_ids)}")
430
+ return connection_items
431
+
322
432
  @api(version="2.8")
323
- def refresh(self, datasource_item: DatasourceItem, incremental: bool = False) -> JobItem:
433
+ def refresh(self, datasource_item: Union[DatasourceItem, str], incremental: bool = False) -> JobItem:
324
434
  """
325
435
  Refreshes the extract of an existing workbook.
326
436
 
@@ -328,8 +438,8 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
328
438
 
329
439
  Parameters
330
440
  ----------
331
- workbook_item : WorkbookItem | str
332
- The workbook item or workbook ID.
441
+ workbook_item : DatasourceItem | str
442
+ The datasource item or datasource ID.
333
443
  incremental: bool
334
444
  Whether to do a full refresh or incremental refresh of the extract data
335
445
 
@@ -424,13 +534,13 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
424
534
  @parameter_added_in(as_job="3.0")
425
535
  def publish(
426
536
  self,
427
- datasource_item: DatasourceItem,
428
- file: PathOrFileR,
429
- mode: str,
430
- connection_credentials: Optional[ConnectionCredentials] = None,
431
- connections: Optional[Sequence[ConnectionItem]] = None,
432
- as_job: bool = False,
433
- ) -> Union[DatasourceItem, JobItem]:
537
+ datasource_item,
538
+ file,
539
+ mode,
540
+ connection_credentials=None,
541
+ connections=None,
542
+ as_job=False,
543
+ ):
434
544
  """
435
545
  Publishes a data source to a server, or appends data to an existing
436
546
  data source.
@@ -576,7 +686,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
576
686
  datasource_or_connection_item: Union[DatasourceItem, ConnectionItem, str],
577
687
  *,
578
688
  request_id: str,
579
- actions: Sequence[Mapping],
689
+ actions: Sequence[HyperAction],
580
690
  payload: Optional[FilePath] = None,
581
691
  ) -> JobItem:
582
692
  """
@@ -733,7 +843,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
733
843
  self._data_quality_warnings.populate(item)
734
844
 
735
845
  @api(version="3.5")
736
- def update_dqw(self, item, warning):
846
+ def update_dqw(self, item: DatasourceItem, warning: "DQWItem") -> list["DQWItem"]:
737
847
  """
738
848
  Update the warning type, status, and message of a data quality warning.
739
849
 
@@ -755,7 +865,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
755
865
  return self._data_quality_warnings.update(item, warning)
756
866
 
757
867
  @api(version="3.5")
758
- def add_dqw(self, item, warning):
868
+ def add_dqw(self, item: DatasourceItem, warning: "DQWItem") -> list["DQWItem"]:
759
869
  """
760
870
  Add a data quality warning to a datasource.
761
871
 
@@ -786,7 +896,7 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
786
896
  return self._data_quality_warnings.add(item, warning)
787
897
 
788
898
  @api(version="3.5")
789
- def delete_dqw(self, item):
899
+ def delete_dqw(self, item: DatasourceItem) -> None:
790
900
  """
791
901
  Delete a data quality warnings from an asset.
792
902
 
@@ -843,15 +953,35 @@ class Datasources(QuerysetEndpoint[DatasourceItem], TaggingMixin[DatasourceItem]
843
953
  revisions = RevisionItem.from_response(server_response.content, self.parent_srv.namespace, datasource_item)
844
954
  return revisions
845
955
 
846
- # Download 1 datasource revision by revision number
847
- @api(version="2.3")
956
+ T = TypeVar("T", bound=FileObjectW)
957
+
958
+ @overload
848
959
  def download_revision(
849
960
  self,
850
961
  datasource_id: str,
851
962
  revision_number: Optional[str],
852
- filepath: Optional[PathOrFileW] = None,
963
+ filepath: T,
853
964
  include_extract: bool = True,
854
- ) -> PathOrFileW:
965
+ ) -> T: ...
966
+
967
+ @overload
968
+ def download_revision(
969
+ self,
970
+ datasource_id: str,
971
+ revision_number: Optional[str],
972
+ filepath: Optional[FilePath] = None,
973
+ include_extract: bool = True,
974
+ ) -> str: ...
975
+
976
+ # Download 1 datasource revision by revision number
977
+ @api(version="2.3")
978
+ def download_revision(
979
+ self,
980
+ datasource_id,
981
+ revision_number,
982
+ filepath=None,
983
+ include_extract=True,
984
+ ):
855
985
  """
856
986
  Downloads a specific version of a data source prior to the current one
857
987
  in .tdsx format. To download the current version of a data source set
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from typing import Callable, Optional, Protocol, TYPE_CHECKING
2
3
 
3
4
  from .endpoint import Endpoint
4
5
  from .exceptions import MissingRequiredFieldError
@@ -7,6 +8,15 @@ from tableauserverclient.models import DQWItem
7
8
 
8
9
  from tableauserverclient.helpers.logging import logger
9
10
 
11
+ if TYPE_CHECKING:
12
+ from tableauserverclient.server.request_options import RequestOptions
13
+
14
+
15
+ class HasId(Protocol):
16
+ @property
17
+ def id(self) -> Optional[str]: ...
18
+ def _set_data_quality_warnings(self, dqw: Callable[[], list[DQWItem]]): ...
19
+
10
20
 
11
21
  class _DataQualityWarningEndpoint(Endpoint):
12
22
  def __init__(self, parent_srv, resource_type):
@@ -14,12 +24,12 @@ class _DataQualityWarningEndpoint(Endpoint):
14
24
  self.resource_type = resource_type
15
25
 
16
26
  @property
17
- def baseurl(self):
27
+ def baseurl(self) -> str:
18
28
  return "{}/sites/{}/dataQualityWarnings/{}".format(
19
29
  self.parent_srv.baseurl, self.parent_srv.site_id, self.resource_type
20
30
  )
21
31
 
22
- def add(self, resource, warning):
32
+ def add(self, resource: HasId, warning: DQWItem) -> list[DQWItem]:
23
33
  url = f"{self.baseurl}/{resource.id}"
24
34
  add_req = RequestFactory.DQW.add_req(warning)
25
35
  response = self.post_request(url, add_req)
@@ -28,7 +38,7 @@ class _DataQualityWarningEndpoint(Endpoint):
28
38
 
29
39
  return warnings
30
40
 
31
- def update(self, resource, warning):
41
+ def update(self, resource: HasId, warning: DQWItem) -> list[DQWItem]:
32
42
  url = f"{self.baseurl}/{resource.id}"
33
43
  add_req = RequestFactory.DQW.update_req(warning)
34
44
  response = self.put_request(url, add_req)
@@ -37,11 +47,11 @@ class _DataQualityWarningEndpoint(Endpoint):
37
47
 
38
48
  return warnings
39
49
 
40
- def clear(self, resource):
50
+ def clear(self, resource: HasId) -> None:
41
51
  url = f"{self.baseurl}/{resource.id}"
42
52
  return self.delete_request(url)
43
53
 
44
- def populate(self, item):
54
+ def populate(self, item: HasId) -> None:
45
55
  if not item.id:
46
56
  error = "Server item is missing ID. Item must be retrieved from server first."
47
57
  raise MissingRequiredFieldError(error)
@@ -52,7 +62,7 @@ class _DataQualityWarningEndpoint(Endpoint):
52
62
  item._set_data_quality_warnings(dqw_fetcher)
53
63
  logger.info(f"Populated permissions for item (ID: {item.id})")
54
64
 
55
- def _get_data_quality_warnings(self, item, req_options=None):
65
+ def _get_data_quality_warnings(self, item: HasId, req_options: Optional["RequestOptions"] = None) -> list[DQWItem]:
56
66
  url = f"{self.baseurl}/{item.id}"
57
67
  server_response = self.get_request(url, req_options)
58
68
  dqws = DQWItem.from_response(server_response.content, self.parent_srv.namespace)
@@ -14,6 +14,7 @@ from typing import (
14
14
  TypeVar,
15
15
  Union,
16
16
  )
17
+ from typing_extensions import Self
17
18
 
18
19
  from tableauserverclient.models.pagination_item import PaginationItem
19
20
  from tableauserverclient.server.request_options import RequestOptions
@@ -353,3 +354,41 @@ class QuerysetEndpoint(Endpoint, Generic[T]):
353
354
  @abc.abstractmethod
354
355
  def get(self, request_options: Optional[RequestOptions] = None) -> tuple[list[T], PaginationItem]:
355
356
  raise NotImplementedError(f".get has not been implemented for {self.__class__.__qualname__}")
357
+
358
+ def fields(self: Self, *fields: str) -> QuerySet:
359
+ """
360
+ Add fields to the request options. If no fields are provided, the
361
+ default fields will be used. If fields are provided, the default fields
362
+ will be used in addition to the provided fields.
363
+
364
+ Parameters
365
+ ----------
366
+ fields : str
367
+ The fields to include in the request options.
368
+
369
+ Returns
370
+ -------
371
+ QuerySet
372
+ """
373
+ queryset = QuerySet(self)
374
+ queryset.request_options.fields |= set(fields) | set(("_default_",))
375
+ return queryset
376
+
377
+ def only_fields(self: Self, *fields: str) -> QuerySet:
378
+ """
379
+ Add fields to the request options. If no fields are provided, the
380
+ default fields will be used. If fields are provided, the default fields
381
+ will be replaced by the provided fields.
382
+
383
+ Parameters
384
+ ----------
385
+ fields : str
386
+ The fields to include in the request options.
387
+
388
+ Returns
389
+ -------
390
+ QuerySet
391
+ """
392
+ queryset = QuerySet(self)
393
+ queryset.request_options.fields |= set(fields)
394
+ return queryset