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
@@ -2,7 +2,7 @@ import copy
2
2
  import datetime
3
3
  import uuid
4
4
  import xml.etree.ElementTree as ET
5
- from typing import Callable, Dict, List, Optional, Set
5
+ from typing import Callable, Optional
6
6
 
7
7
  from defusedxml.ElementTree import fromstring
8
8
 
@@ -20,8 +20,93 @@ from .view_item import ViewItem
20
20
  from .data_freshness_policy_item import DataFreshnessPolicyItem
21
21
 
22
22
 
23
- class WorkbookItem(object):
24
- def __init__(self, project_id: Optional[str] = None, name: Optional[str] = None, show_tabs: bool = False) -> None:
23
+ class WorkbookItem:
24
+ """
25
+ The workbook resources for Tableau are defined in the WorkbookItem class.
26
+ The class corresponds to the workbook resources you can access using the
27
+ Tableau REST API. Some workbook methods take an instance of the WorkbookItem
28
+ class as arguments. The workbook item specifies the project.
29
+
30
+ Parameters
31
+ ----------
32
+ project_id : Optional[str], optional
33
+ The project ID for the workbook, by default None.
34
+
35
+ name : Optional[str], optional
36
+ The name of the workbook, by default None.
37
+
38
+ show_tabs : bool, optional
39
+ Determines whether the workbook shows tabs for the view.
40
+
41
+ Attributes
42
+ ----------
43
+ connections : list[ConnectionItem]
44
+ The list of data connections (ConnectionItem) for the data sources used
45
+ by the workbook. You must first call the workbooks.populate_connections
46
+ method to access this data. See the ConnectionItem class.
47
+
48
+ content_url : Optional[str]
49
+ The name of the workbook as it appears in the URL.
50
+
51
+ created_at : Optional[datetime.datetime]
52
+ The date and time the workbook was created.
53
+
54
+ description : Optional[str]
55
+ User-defined description of the workbook.
56
+
57
+ id : Optional[str]
58
+ The identifier for the workbook. You need this value to query a specific
59
+ workbook or to delete a workbook with the get_by_id and delete methods.
60
+
61
+ owner_id : Optional[str]
62
+ The identifier for the owner (UserItem) of the workbook.
63
+
64
+ preview_image : bytes
65
+ The thumbnail image for the view. You must first call the
66
+ workbooks.populate_preview_image method to access this data.
67
+
68
+ project_name : Optional[str]
69
+ The name of the project that contains the workbook.
70
+
71
+ size: int
72
+ The size of the workbook in megabytes.
73
+
74
+ hidden_views: Optional[list[str]]
75
+ List of string names of views that need to be hidden when the workbook
76
+ is published.
77
+
78
+ tags: set[str]
79
+ The set of tags associated with the workbook.
80
+
81
+ updated_at : Optional[datetime.datetime]
82
+ The date and time the workbook was last updated.
83
+
84
+ views : list[ViewItem]
85
+ The list of views (ViewItem) for the workbook. You must first call the
86
+ workbooks.populate_views method to access this data. See the ViewItem
87
+ class.
88
+
89
+ web_page_url : Optional[str]
90
+ The full URL for the workbook.
91
+
92
+ Examples
93
+ --------
94
+ # creating a new instance of a WorkbookItem
95
+ >>> import tableauserverclient as TSC
96
+
97
+ >>> # Create new workbook_item with project id '3a8b6148-493c-11e6-a621-6f3499394a39'
98
+
99
+ >>> new_workbook = TSC.WorkbookItem('3a8b6148-493c-11e6-a621-6f3499394a39')
100
+ """
101
+
102
+ def __init__(
103
+ self,
104
+ project_id: Optional[str] = None,
105
+ name: Optional[str] = None,
106
+ show_tabs: bool = False,
107
+ thumbnails_user_id: Optional[str] = None,
108
+ thumbnails_group_id: Optional[str] = None,
109
+ ) -> None:
25
110
  self._connections = None
26
111
  self._content_url = None
27
112
  self._webpage_url = None
@@ -35,15 +120,15 @@ class WorkbookItem(object):
35
120
  self._revisions = None
36
121
  self._size = None
37
122
  self._updated_at = None
38
- self._views: Optional[Callable[[], List[ViewItem]]] = None
123
+ self._views: Optional[Callable[[], list[ViewItem]]] = None
39
124
  self.name = name
40
125
  self._description = None
41
126
  self.owner_id: Optional[str] = None
42
127
  # workaround for Personal Space workbooks without a project
43
128
  self.project_id: Optional[str] = project_id or uuid.uuid4().__str__()
44
129
  self.show_tabs = show_tabs
45
- self.hidden_views: Optional[List[str]] = None
46
- self.tags: Set[str] = set()
130
+ self.hidden_views: Optional[list[str]] = None
131
+ self.tags: set[str] = set()
47
132
  self.data_acceleration_config = {
48
133
  "acceleration_enabled": None,
49
134
  "accelerate_now": None,
@@ -52,11 +137,13 @@ class WorkbookItem(object):
52
137
  }
53
138
  self.data_freshness_policy = None
54
139
  self._permissions = None
140
+ self.thumbnails_user_id = thumbnails_user_id
141
+ self.thumbnails_group_id = thumbnails_group_id
55
142
 
56
143
  return None
57
144
 
58
145
  def __str__(self):
59
- return "<WorkbookItem {0} '{1}' contentUrl='{2}' project={3}>".format(
146
+ return "<WorkbookItem {} '{}' contentUrl='{}' project={}>".format(
60
147
  self._id, self.name, self.content_url, self.project_id
61
148
  )
62
149
 
@@ -64,14 +151,14 @@ class WorkbookItem(object):
64
151
  return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"
65
152
 
66
153
  @property
67
- def connections(self) -> List[ConnectionItem]:
154
+ def connections(self) -> list[ConnectionItem]:
68
155
  if self._connections is None:
69
156
  error = "Workbook item must be populated with connections first."
70
157
  raise UnpopulatedPropertyError(error)
71
158
  return self._connections()
72
159
 
73
160
  @property
74
- def permissions(self) -> List[PermissionsRule]:
161
+ def permissions(self) -> list[PermissionsRule]:
75
162
  if self._permissions is None:
76
163
  error = "Workbook item must be populated with permissions first."
77
164
  raise UnpopulatedPropertyError(error)
@@ -152,7 +239,7 @@ class WorkbookItem(object):
152
239
  return self._updated_at
153
240
 
154
241
  @property
155
- def views(self) -> List[ViewItem]:
242
+ def views(self) -> list[ViewItem]:
156
243
  # Views can be set in an initial workbook response OR by a call
157
244
  # to Server. Without getting too fancy, I think we can rely on
158
245
  # returning a list from the response, until they call
@@ -191,19 +278,35 @@ class WorkbookItem(object):
191
278
  self._data_freshness_policy = value
192
279
 
193
280
  @property
194
- def revisions(self) -> List[RevisionItem]:
281
+ def revisions(self) -> list[RevisionItem]:
195
282
  if self._revisions is None:
196
283
  error = "Workbook item must be populated with revisions first."
197
284
  raise UnpopulatedPropertyError(error)
198
285
  return self._revisions()
199
286
 
287
+ @property
288
+ def thumbnails_user_id(self) -> Optional[str]:
289
+ return self._thumbnails_user_id
290
+
291
+ @thumbnails_user_id.setter
292
+ def thumbnails_user_id(self, value: str):
293
+ self._thumbnails_user_id = value
294
+
295
+ @property
296
+ def thumbnails_group_id(self) -> Optional[str]:
297
+ return self._thumbnails_group_id
298
+
299
+ @thumbnails_group_id.setter
300
+ def thumbnails_group_id(self, value: str):
301
+ self._thumbnails_group_id = value
302
+
200
303
  def _set_connections(self, connections):
201
304
  self._connections = connections
202
305
 
203
306
  def _set_permissions(self, permissions):
204
307
  self._permissions = permissions
205
308
 
206
- def _set_views(self, views: Callable[[], List[ViewItem]]) -> None:
309
+ def _set_views(self, views: Callable[[], list[ViewItem]]) -> None:
207
310
  self._views = views
208
311
 
209
312
  def _set_pdf(self, pdf: Callable[[], bytes]) -> None:
@@ -316,7 +419,7 @@ class WorkbookItem(object):
316
419
  self.data_freshness_policy = data_freshness_policy
317
420
 
318
421
  @classmethod
319
- def from_response(cls, resp: str, ns: Dict[str, str]) -> List["WorkbookItem"]:
422
+ def from_response(cls, resp: str, ns: dict[str, str]) -> list["WorkbookItem"]:
320
423
  all_workbook_items = list()
321
424
  parsed_response = fromstring(resp)
322
425
  all_workbook_xml = parsed_response.findall(".//t:workbook", namespaces=ns)
@@ -11,7 +11,7 @@ class UnknownNamespaceError(Exception):
11
11
  pass
12
12
 
13
13
 
14
- class Namespace(object):
14
+ class Namespace:
15
15
  def __init__(self):
16
16
  self._namespace = {"t": NEW_NAMESPACE}
17
17
  self._detected = False
@@ -11,7 +11,7 @@ from tableauserverclient.server.filter import Filter
11
11
  from tableauserverclient.server.sort import Sort
12
12
  from tableauserverclient.server.server import Server
13
13
  from tableauserverclient.server.pager import Pager
14
- from tableauserverclient.server.endpoint.exceptions import NotSignedInError
14
+ from tableauserverclient.server.endpoint.exceptions import FailedSignInError, NotSignedInError
15
15
 
16
16
  from tableauserverclient.server.endpoint import (
17
17
  Auth,
@@ -57,6 +57,7 @@ __all__ = [
57
57
  "Sort",
58
58
  "Server",
59
59
  "Pager",
60
+ "FailedSignInError",
60
61
  "NotSignedInError",
61
62
  "Auth",
62
63
  "CustomViews",
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
16
16
 
17
17
 
18
18
  class Auth(Endpoint):
19
- class contextmgr(object):
19
+ class contextmgr:
20
20
  def __init__(self, callback):
21
21
  self._callback = callback
22
22
 
@@ -28,7 +28,7 @@ class Auth(Endpoint):
28
28
 
29
29
  @property
30
30
  def baseurl(self) -> str:
31
- return "{0}/auth".format(self.parent_srv.baseurl)
31
+ return f"{self.parent_srv.baseurl}/auth"
32
32
 
33
33
  @api(version="2.0")
34
34
  def sign_in(self, auth_req: "Credentials") -> contextmgr:
@@ -41,8 +41,32 @@ class Auth(Endpoint):
41
41
  optionally a user_id to impersonate.
42
42
 
43
43
  Creates a context manager that will sign out of the server upon exit.
44
+
45
+ Parameters
46
+ ----------
47
+ auth_req : Credentials
48
+ The credentials object to use for signing in. Can be a TableauAuth,
49
+ PersonalAccessTokenAuth, or JWTAuth object.
50
+
51
+ Returns
52
+ -------
53
+ contextmgr
54
+ A context manager that will sign out of the server upon exit.
55
+
56
+ Examples
57
+ --------
58
+ >>> import tableauserverclient as TSC
59
+
60
+ >>> # create an auth object
61
+ >>> tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD')
62
+
63
+ >>> # create an instance for your server
64
+ >>> server = TSC.Server('https://SERVER_URL')
65
+
66
+ >>> # call the sign-in method with the auth object
67
+ >>> server.auth.sign_in(tableau_auth)
44
68
  """
45
- url = "{0}/{1}".format(self.baseurl, "signin")
69
+ url = f"{self.baseurl}/signin"
46
70
  signin_req = RequestFactory.Auth.signin_req(auth_req)
47
71
  server_response = self.parent_srv.session.post(
48
72
  url, data=signin_req, **self.parent_srv.http_options, allow_redirects=False
@@ -60,25 +84,29 @@ class Auth(Endpoint):
60
84
  self._check_status(server_response, url)
61
85
  parsed_response = fromstring(server_response.content)
62
86
  site_id = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("id", None)
87
+ site_url = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("contentUrl", None)
63
88
  user_id = parsed_response.find(".//t:user", namespaces=self.parent_srv.namespace).get("id", None)
64
89
  auth_token = parsed_response.find("t:credentials", namespaces=self.parent_srv.namespace).get("token", None)
65
- self.parent_srv._set_auth(site_id, user_id, auth_token)
66
- logger.info("Signed into {0} as user with id {1}".format(self.parent_srv.server_address, user_id))
90
+ self.parent_srv._set_auth(site_id, user_id, auth_token, site_url)
91
+ logger.info(f"Signed into {self.parent_srv.server_address} as user with id {user_id}")
67
92
  return Auth.contextmgr(self.sign_out)
68
93
 
69
94
  # We use the same request that username/password login uses for all auth types.
70
95
  # The distinct methods are mostly useful for explicitly showing api version support for each auth type
71
96
  @api(version="3.6")
72
97
  def sign_in_with_personal_access_token(self, auth_req: "Credentials") -> contextmgr:
98
+ """Passthrough to sign_in method"""
73
99
  return self.sign_in(auth_req)
74
100
 
75
101
  @api(version="3.17")
76
102
  def sign_in_with_json_web_token(self, auth_req: "Credentials") -> contextmgr:
103
+ """Passthrough to sign_in method"""
77
104
  return self.sign_in(auth_req)
78
105
 
79
106
  @api(version="2.0")
80
107
  def sign_out(self) -> None:
81
- url = "{0}/{1}".format(self.baseurl, "signout")
108
+ """Sign out of current session."""
109
+ url = f"{self.baseurl}/signout"
82
110
  # If there are no auth tokens you're already signed out. No-op
83
111
  if not self.parent_srv.is_signed_in():
84
112
  return
@@ -88,7 +116,34 @@ class Auth(Endpoint):
88
116
 
89
117
  @api(version="2.6")
90
118
  def switch_site(self, site_item: "SiteItem") -> contextmgr:
91
- url = "{0}/{1}".format(self.baseurl, "switchSite")
119
+ """
120
+ Switch to a different site on the server. This will sign out of the
121
+ current site and sign in to the new site. If used as a context manager,
122
+ will sign out of the new site upon exit.
123
+
124
+ Parameters
125
+ ----------
126
+ site_item : SiteItem
127
+ The site to switch to.
128
+
129
+ Returns
130
+ -------
131
+ contextmgr
132
+ A context manager that will sign out of the new site upon exit.
133
+
134
+ Examples
135
+ --------
136
+ >>> import tableauserverclient as TSC
137
+
138
+ >>> # Find the site you want to switch to
139
+ >>> new_site = server.sites.get_by_id("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d")
140
+ >>> # switch to the new site
141
+ >>> with server.auth.switch_site(new_site):
142
+ >>> # do something on the new site
143
+ >>> pass
144
+
145
+ """
146
+ url = f"{self.baseurl}/switchSite"
92
147
  switch_req = RequestFactory.Auth.switch_req(site_item.content_url)
93
148
  try:
94
149
  server_response = self.post_request(url, switch_req)
@@ -101,14 +156,18 @@ class Auth(Endpoint):
101
156
  self._check_status(server_response, url)
102
157
  parsed_response = fromstring(server_response.content)
103
158
  site_id = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("id", None)
159
+ site_url = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("contentUrl", None)
104
160
  user_id = parsed_response.find(".//t:user", namespaces=self.parent_srv.namespace).get("id", None)
105
161
  auth_token = parsed_response.find("t:credentials", namespaces=self.parent_srv.namespace).get("token", None)
106
- self.parent_srv._set_auth(site_id, user_id, auth_token)
107
- logger.info("Signed into {0} as user with id {1}".format(self.parent_srv.server_address, user_id))
162
+ self.parent_srv._set_auth(site_id, user_id, auth_token, site_url)
163
+ logger.info(f"Signed into {self.parent_srv.server_address} as user with id {user_id}")
108
164
  return Auth.contextmgr(self.sign_out)
109
165
 
110
166
  @api(version="3.10")
111
167
  def revoke_all_server_admin_tokens(self) -> None:
112
- url = "{0}/{1}".format(self.baseurl, "revokeAllServerAdminTokens")
168
+ """
169
+ Revokes all personal access tokens for all server admins on the server.
170
+ """
171
+ url = f"{self.baseurl}/revokeAllServerAdminTokens"
113
172
  self.post_request(url, "")
114
173
  logger.info("Revoked all tokens for all server admins")