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,6 +1,7 @@
1
1
  import abc
2
2
  import copy
3
- from typing import Generic, Iterable, Optional, Protocol, Set, TypeVar, Union, TYPE_CHECKING, runtime_checkable
3
+ from typing import Generic, Optional, Protocol, TypeVar, Union, TYPE_CHECKING, runtime_checkable
4
+ from collections.abc import Iterable
4
5
  import urllib.parse
5
6
 
6
7
  from tableauserverclient.server.endpoint.endpoint import Endpoint, api
@@ -24,7 +25,7 @@ if TYPE_CHECKING:
24
25
  class _ResourceTagger(Endpoint):
25
26
  # Add new tags to resource
26
27
  def _add_tags(self, baseurl, resource_id, tag_set):
27
- url = "{0}/{1}/tags".format(baseurl, resource_id)
28
+ url = f"{baseurl}/{resource_id}/tags"
28
29
  add_req = RequestFactory.Tag.add_req(tag_set)
29
30
 
30
31
  try:
@@ -39,7 +40,7 @@ class _ResourceTagger(Endpoint):
39
40
  # Delete a resource's tag by name
40
41
  def _delete_tag(self, baseurl, resource_id, tag_name):
41
42
  encoded_tag_name = urllib.parse.quote(tag_name)
42
- url = "{0}/{1}/tags/{2}".format(baseurl, resource_id, encoded_tag_name)
43
+ url = f"{baseurl}/{resource_id}/tags/{encoded_tag_name}"
43
44
 
44
45
  try:
45
46
  self.delete_request(url)
@@ -59,7 +60,7 @@ class _ResourceTagger(Endpoint):
59
60
  if add_set:
60
61
  resource_item.tags = self._add_tags(baseurl, resource_item.id, add_set)
61
62
  resource_item._initial_tags = copy.copy(resource_item.tags)
62
- logger.info("Updated tags to {0}".format(resource_item.tags))
63
+ logger.info(f"Updated tags to {resource_item.tags}")
63
64
 
64
65
 
65
66
  class Response(Protocol):
@@ -68,8 +69,8 @@ class Response(Protocol):
68
69
 
69
70
  @runtime_checkable
70
71
  class Taggable(Protocol):
71
- tags: Set[str]
72
- _initial_tags: Set[str]
72
+ tags: set[str]
73
+ _initial_tags: set[str]
73
74
 
74
75
  @property
75
76
  def id(self) -> Optional[str]:
@@ -95,14 +96,14 @@ class TaggingMixin(abc.ABC, Generic[T]):
95
96
  def delete_request(self, url) -> None:
96
97
  pass
97
98
 
98
- def add_tags(self, item: Union[T, str], tags: Union[Iterable[str], str]) -> Set[str]:
99
+ def add_tags(self, item: Union[T, str], tags: Union[Iterable[str], str]) -> set[str]:
99
100
  item_id = getattr(item, "id", item)
100
101
 
101
102
  if not isinstance(item_id, str):
102
103
  raise ValueError("ID not found.")
103
104
 
104
105
  if isinstance(tags, str):
105
- tag_set = set([tags])
106
+ tag_set = {tags}
106
107
  else:
107
108
  tag_set = set(tags)
108
109
 
@@ -118,7 +119,7 @@ class TaggingMixin(abc.ABC, Generic[T]):
118
119
  raise ValueError("ID not found.")
119
120
 
120
121
  if isinstance(tags, str):
121
- tag_set = set([tags])
122
+ tag_set = {tags}
122
123
  else:
123
124
  tag_set = set(tags)
124
125
 
@@ -158,9 +159,9 @@ class Tags(Endpoint):
158
159
  return f"{self.parent_srv.baseurl}/tags"
159
160
 
160
161
  @api(version="3.9")
161
- def batch_add(self, tags: Union[Iterable[str], str], content: content) -> Set[str]:
162
+ def batch_add(self, tags: Union[Iterable[str], str], content: content) -> set[str]:
162
163
  if isinstance(tags, str):
163
- tag_set = set([tags])
164
+ tag_set = {tags}
164
165
  else:
165
166
  tag_set = set(tags)
166
167
 
@@ -170,9 +171,9 @@ class Tags(Endpoint):
170
171
  return TagItem.from_response(server_response.content, self.parent_srv.namespace)
171
172
 
172
173
  @api(version="3.9")
173
- def batch_delete(self, tags: Union[Iterable[str], str], content: content) -> Set[str]:
174
+ def batch_delete(self, tags: Union[Iterable[str], str], content: content) -> set[str]:
174
175
  if isinstance(tags, str):
175
- tag_set = set([tags])
176
+ tag_set = {tags}
176
177
  else:
177
178
  tag_set = set(tags)
178
179
 
@@ -2,7 +2,7 @@ import copy
2
2
  import logging
3
3
  import warnings
4
4
  from collections import namedtuple
5
- from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union
5
+ from typing import TYPE_CHECKING, Callable, Optional, Union
6
6
 
7
7
  from .endpoint import Endpoint, api, parameter_added_in
8
8
  from .exceptions import MissingRequiredFieldError
@@ -22,14 +22,14 @@ if TYPE_CHECKING:
22
22
  class Schedules(Endpoint):
23
23
  @property
24
24
  def baseurl(self) -> str:
25
- return "{0}/schedules".format(self.parent_srv.baseurl)
25
+ return f"{self.parent_srv.baseurl}/schedules"
26
26
 
27
27
  @property
28
28
  def siteurl(self) -> str:
29
- return "{0}/sites/{1}/schedules".format(self.parent_srv.baseurl, self.parent_srv.site_id)
29
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/schedules"
30
30
 
31
31
  @api(version="2.3")
32
- def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[ScheduleItem], PaginationItem]:
32
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[ScheduleItem], PaginationItem]:
33
33
  logger.info("Querying all schedules")
34
34
  url = self.baseurl
35
35
  server_response = self.get_request(url, req_options)
@@ -42,8 +42,8 @@ class Schedules(Endpoint):
42
42
  if not schedule_id:
43
43
  error = "No Schedule ID provided"
44
44
  raise ValueError(error)
45
- logger.info("Querying a single schedule by id ({})".format(schedule_id))
46
- url = "{0}/{1}".format(self.baseurl, schedule_id)
45
+ logger.info(f"Querying a single schedule by id ({schedule_id})")
46
+ url = f"{self.baseurl}/{schedule_id}"
47
47
  server_response = self.get_request(url)
48
48
  return ScheduleItem.from_response(server_response.content, self.parent_srv.namespace)[0]
49
49
 
@@ -52,9 +52,9 @@ class Schedules(Endpoint):
52
52
  if not schedule_id:
53
53
  error = "Schedule ID undefined"
54
54
  raise ValueError(error)
55
- url = "{0}/{1}".format(self.baseurl, schedule_id)
55
+ url = f"{self.baseurl}/{schedule_id}"
56
56
  self.delete_request(url)
57
- logger.info("Deleted single schedule (ID: {0})".format(schedule_id))
57
+ logger.info(f"Deleted single schedule (ID: {schedule_id})")
58
58
 
59
59
  @api(version="2.3")
60
60
  def update(self, schedule_item: ScheduleItem) -> ScheduleItem:
@@ -62,10 +62,10 @@ class Schedules(Endpoint):
62
62
  error = "Schedule item missing ID."
63
63
  raise MissingRequiredFieldError(error)
64
64
 
65
- url = "{0}/{1}".format(self.baseurl, schedule_item.id)
65
+ url = f"{self.baseurl}/{schedule_item.id}"
66
66
  update_req = RequestFactory.Schedule.update_req(schedule_item)
67
67
  server_response = self.put_request(url, update_req)
68
- logger.info("Updated schedule item (ID: {})".format(schedule_item.id))
68
+ logger.info(f"Updated schedule item (ID: {schedule_item.id})")
69
69
  updated_schedule = copy.copy(schedule_item)
70
70
  return updated_schedule._parse_common_tags(server_response.content, self.parent_srv.namespace)
71
71
 
@@ -79,7 +79,7 @@ class Schedules(Endpoint):
79
79
  create_req = RequestFactory.Schedule.create_req(schedule_item)
80
80
  server_response = self.post_request(url, create_req)
81
81
  new_schedule = ScheduleItem.from_response(server_response.content, self.parent_srv.namespace)[0]
82
- logger.info("Created new schedule (ID: {})".format(new_schedule.id))
82
+ logger.info(f"Created new schedule (ID: {new_schedule.id})")
83
83
  return new_schedule
84
84
 
85
85
  @api(version="2.8")
@@ -91,12 +91,12 @@ class Schedules(Endpoint):
91
91
  datasource: Optional["DatasourceItem"] = None,
92
92
  flow: Optional["FlowItem"] = None,
93
93
  task_type: Optional[str] = None,
94
- ) -> List[AddResponse]:
94
+ ) -> list[AddResponse]:
95
95
  # There doesn't seem to be a good reason to allow one item of each type?
96
96
  if workbook and datasource:
97
97
  warnings.warn("Passing in multiple items for add_to_schedule will be deprecated", PendingDeprecationWarning)
98
- items: List[
99
- Tuple[str, Union[WorkbookItem, FlowItem, DatasourceItem], str, Callable[[Optional[str], str], bytes], str]
98
+ items: list[
99
+ tuple[str, Union[WorkbookItem, FlowItem, DatasourceItem], str, Callable[[Optional[str], str], bytes], str]
100
100
  ] = []
101
101
 
102
102
  if workbook is not None:
@@ -115,8 +115,7 @@ class Schedules(Endpoint):
115
115
  ) # type:ignore[arg-type]
116
116
 
117
117
  results = (self._add_to(*x) for x in items)
118
- # list() is needed for python 3.x compatibility
119
- return list(filter(lambda x: not x.result, results)) # type:ignore[arg-type]
118
+ return [x for x in results if not x.result]
120
119
 
121
120
  def _add_to(
122
121
  self,
@@ -133,13 +132,13 @@ class Schedules(Endpoint):
133
132
  item_task_type,
134
133
  ) -> AddResponse:
135
134
  id_ = resource.id
136
- url = "{0}/{1}/{2}s".format(self.siteurl, schedule_id, type_)
135
+ url = f"{self.siteurl}/{schedule_id}/{type_}s"
137
136
  add_req = req_factory(id_, task_type=item_task_type) # type: ignore[call-arg, arg-type]
138
137
  response = self.put_request(url, add_req)
139
138
 
140
139
  error, warnings, task_created = ScheduleItem.parse_add_to_schedule_response(response, self.parent_srv.namespace)
141
140
  if task_created:
142
- logger.info("Added {} to {} to schedule {}".format(type_, id_, schedule_id))
141
+ logger.info(f"Added {type_} to {id_} to schedule {schedule_id}")
143
142
 
144
143
  if error is not None or warnings is not None:
145
144
  return AddResponse(
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from typing import Union
2
3
 
3
4
  from .endpoint import Endpoint, api
4
5
  from .exceptions import ServerResponseError
@@ -21,15 +22,49 @@ class ServerInfo(Endpoint):
21
22
  return self._info
22
23
 
23
24
  def __repr__(self):
24
- return "<Endpoint {}>".format(self.serverInfo)
25
+ return f"<Endpoint {self.serverInfo}>"
25
26
 
26
27
  @property
27
- def baseurl(self):
28
- return "{0}/serverInfo".format(self.parent_srv.baseurl)
28
+ def baseurl(self) -> str:
29
+ return f"{self.parent_srv.baseurl}/serverInfo"
29
30
 
30
31
  @api(version="2.4")
31
- def get(self):
32
- """Retrieve the server info for the server. This is an unauthenticated call"""
32
+ def get(self) -> Union[ServerInfoItem, None]:
33
+ """
34
+ Retrieve the build and version information for the server.
35
+
36
+ This method makes an unauthenticated call, so no sign in or
37
+ authentication token is required.
38
+
39
+ Returns
40
+ -------
41
+ :class:`~tableauserverclient.models.ServerInfoItem`
42
+
43
+ Raises
44
+ ------
45
+ :class:`~tableauserverclient.exceptions.ServerInfoEndpointNotFoundError`
46
+ Raised when the server info endpoint is not found.
47
+
48
+ :class:`~tableauserverclient.exceptions.EndpointUnavailableError`
49
+ Raised when the server info endpoint is not available.
50
+
51
+ Examples
52
+ --------
53
+ >>> import tableauserverclient as TSC
54
+
55
+ >>> # create a instance of server
56
+ >>> server = TSC.Server('https://MY-SERVER')
57
+
58
+ >>> # set the version number > 2.3
59
+ >>> # the server_info.get() method works in 2.4 and later
60
+ >>> server.version = '2.5'
61
+
62
+ >>> s_info = server.server_info.get()
63
+ >>> print("\nServer info:")
64
+ >>> print("\tProduct version: {0}".format(s_info.product_version))
65
+ >>> print("\tREST API version: {0}".format(s_info.rest_api_version))
66
+ >>> print("\tBuild number: {0}".format(s_info.build_number))
67
+ """
33
68
  try:
34
69
  server_response = self.get_unauthenticated_request(self.baseurl)
35
70
  except ServerResponseError as e:
@@ -8,20 +8,49 @@ from tableauserverclient.models import SiteItem, PaginationItem
8
8
 
9
9
  from tableauserverclient.helpers.logging import logger
10
10
 
11
- from typing import TYPE_CHECKING, List, Optional, Tuple
11
+ from typing import TYPE_CHECKING, Optional
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from ..request_options import RequestOptions
15
15
 
16
16
 
17
17
  class Sites(Endpoint):
18
+ """
19
+ Using the site methods of the Tableau Server REST API you can:
20
+
21
+ List sites on a server or get details of a specific site
22
+ Create, update, or delete a site
23
+ List views in a site
24
+ Encrypt, decrypt, or reencrypt extracts on a site
25
+
26
+ """
27
+
18
28
  @property
19
29
  def baseurl(self) -> str:
20
- return "{0}/sites".format(self.parent_srv.baseurl)
30
+ return f"{self.parent_srv.baseurl}/sites"
21
31
 
22
32
  # Gets all sites
23
33
  @api(version="2.0")
24
- def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[SiteItem], PaginationItem]:
34
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[SiteItem], PaginationItem]:
35
+ """
36
+ Query all sites on the server. This method requires server admin
37
+ permissions. This endpoint is paginated, meaning that the server will
38
+ only return a subset of the data at a time. The response will contain
39
+ information about the total number of sites and the number of sites
40
+ returned in the current response. Use the PaginationItem object to
41
+ request more data.
42
+
43
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_sites
44
+
45
+ Parameters
46
+ ----------
47
+ req_options : RequestOptions, optional
48
+ Filtering options for the request.
49
+
50
+ Returns
51
+ -------
52
+ tuple[list[SiteItem], PaginationItem]
53
+ """
25
54
  logger.info("Querying all sites on site")
26
55
  logger.info("Requires Server Admin permissions")
27
56
  url = self.baseurl
@@ -33,6 +62,33 @@ class Sites(Endpoint):
33
62
  # Gets 1 site by id
34
63
  @api(version="2.0")
35
64
  def get_by_id(self, site_id: str) -> SiteItem:
65
+ """
66
+ Query a single site on the server. You can only retrieve the site that
67
+ you are currently authenticated for.
68
+
69
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
70
+
71
+ Parameters
72
+ ----------
73
+ site_id : str
74
+ The site ID.
75
+
76
+ Returns
77
+ -------
78
+ SiteItem
79
+
80
+ Raises
81
+ ------
82
+ ValueError
83
+ If the site ID is not defined.
84
+
85
+ ValueError
86
+ If the site ID does not match the site for which you are currently authenticated.
87
+
88
+ Examples
89
+ --------
90
+ >>> site = server.sites.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
91
+ """
36
92
  if not site_id:
37
93
  error = "Site ID undefined."
38
94
  raise ValueError(error)
@@ -40,20 +96,45 @@ class Sites(Endpoint):
40
96
  error = "You can only retrieve the site for which you are currently authenticated."
41
97
  raise ValueError(error)
42
98
 
43
- logger.info("Querying single site (ID: {0})".format(site_id))
44
- url = "{0}/{1}".format(self.baseurl, site_id)
99
+ logger.info(f"Querying single site (ID: {site_id})")
100
+ url = f"{self.baseurl}/{site_id}"
45
101
  server_response = self.get_request(url)
46
102
  return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
47
103
 
48
104
  # Gets 1 site by name
49
105
  @api(version="2.0")
50
106
  def get_by_name(self, site_name: str) -> SiteItem:
107
+ """
108
+ Query a single site on the server. You can only retrieve the site that
109
+ you are currently authenticated for.
110
+
111
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
112
+
113
+ Parameters
114
+ ----------
115
+ site_name : str
116
+ The site name.
117
+
118
+ Returns
119
+ -------
120
+ SiteItem
121
+
122
+ Raises
123
+ ------
124
+ ValueError
125
+ If the site name is not defined.
126
+
127
+ Examples
128
+ --------
129
+ >>> site = server.sites.get_by_name('Tableau')
130
+
131
+ """
51
132
  if not site_name:
52
133
  error = "Site Name undefined."
53
134
  raise ValueError(error)
54
135
  print("Note: You can only work with the site for which you are currently authenticated")
55
- logger.info("Querying single site (Name: {0})".format(site_name))
56
- url = "{0}/{1}?key=name".format(self.baseurl, site_name)
136
+ logger.info(f"Querying single site (Name: {site_name})")
137
+ url = f"{self.baseurl}/{site_name}?key=name"
57
138
  print(self.baseurl, url)
58
139
  server_response = self.get_request(url)
59
140
  return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
@@ -61,6 +142,31 @@ class Sites(Endpoint):
61
142
  # Gets 1 site by content url
62
143
  @api(version="2.0")
63
144
  def get_by_content_url(self, content_url: str) -> SiteItem:
145
+ """
146
+ Query a single site on the server. You can only retrieve the site that
147
+ you are currently authenticated for.
148
+
149
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_site
150
+
151
+ Parameters
152
+ ----------
153
+ content_url : str
154
+ The content URL.
155
+
156
+ Returns
157
+ -------
158
+ SiteItem
159
+
160
+ Raises
161
+ ------
162
+ ValueError
163
+ If the site name is not defined.
164
+
165
+ Examples
166
+ --------
167
+ >>> site = server.sites.get_by_name('Tableau')
168
+
169
+ """
64
170
  if content_url is None:
65
171
  error = "Content URL undefined."
66
172
  raise ValueError(error)
@@ -68,15 +174,51 @@ class Sites(Endpoint):
68
174
  error = "You can only work with the site you are currently authenticated for"
69
175
  raise ValueError(error)
70
176
 
71
- logger.info("Querying single site (Content URL: {0})".format(content_url))
177
+ logger.info(f"Querying single site (Content URL: {content_url})")
72
178
  logger.debug("Querying other sites requires Server Admin permissions")
73
- url = "{0}/{1}?key=contentUrl".format(self.baseurl, content_url)
179
+ url = f"{self.baseurl}/{content_url}?key=contentUrl"
74
180
  server_response = self.get_request(url)
75
181
  return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
76
182
 
77
183
  # Update site
78
184
  @api(version="2.0")
79
185
  def update(self, site_item: SiteItem) -> SiteItem:
186
+ """
187
+ Modifies the settings for site.
188
+
189
+ The site item object must include the site ID and overrides all other settings.
190
+
191
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_site
192
+
193
+ Parameters
194
+ ----------
195
+ site_item : SiteItem
196
+ The site item that you want to update. The settings specified in the
197
+ site item override the current site settings.
198
+
199
+ Returns
200
+ -------
201
+ SiteItem
202
+ The site item object that was updated.
203
+
204
+ Raises
205
+ ------
206
+ MissingRequiredFieldError
207
+ If the site item is missing an ID.
208
+
209
+ ValueError
210
+ If the site ID does not match the site for which you are currently authenticated.
211
+
212
+ ValueError
213
+ If the site admin mode is set to ContentOnly and a user quota is also set.
214
+
215
+ Examples
216
+ --------
217
+ >>> ...
218
+ >>> site_item.name = 'New Name'
219
+ >>> updated_site = server.sites.update(site_item)
220
+
221
+ """
80
222
  if not site_item.id:
81
223
  error = "Site item missing ID."
82
224
  raise MissingRequiredFieldError(error)
@@ -90,30 +232,94 @@ class Sites(Endpoint):
90
232
  error = "You cannot set admin_mode to ContentOnly and also set a user quota"
91
233
  raise ValueError(error)
92
234
 
93
- url = "{0}/{1}".format(self.baseurl, site_item.id)
235
+ url = f"{self.baseurl}/{site_item.id}"
94
236
  update_req = RequestFactory.Site.update_req(site_item, self.parent_srv)
95
237
  server_response = self.put_request(url, update_req)
96
- logger.info("Updated site item (ID: {0})".format(site_item.id))
238
+ logger.info(f"Updated site item (ID: {site_item.id})")
97
239
  update_site = copy.copy(site_item)
98
240
  return update_site._parse_common_tags(server_response.content, self.parent_srv.namespace)
99
241
 
100
242
  # Delete 1 site object
101
243
  @api(version="2.0")
102
244
  def delete(self, site_id: str) -> None:
245
+ """
246
+ Deletes the specified site from the server. You can only delete the site
247
+ if you are a Server Admin.
248
+
249
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#delete_site
250
+
251
+ Parameters
252
+ ----------
253
+ site_id : str
254
+ The site ID.
255
+
256
+ Raises
257
+ ------
258
+ ValueError
259
+ If the site ID is not defined.
260
+
261
+ ValueError
262
+ If the site ID does not match the site for which you are currently authenticated.
263
+
264
+ Examples
265
+ --------
266
+ >>> server.sites.delete('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
267
+ """
103
268
  if not site_id:
104
269
  error = "Site ID undefined."
105
270
  raise ValueError(error)
106
- url = "{0}/{1}".format(self.baseurl, site_id)
271
+ url = f"{self.baseurl}/{site_id}"
107
272
  if not site_id == self.parent_srv.site_id:
108
273
  error = "You can only delete the site you are currently authenticated for"
109
274
  raise ValueError(error)
110
275
  self.delete_request(url)
111
276
  self.parent_srv._clear_auth()
112
- logger.info("Deleted single site (ID: {0}) and signed out".format(site_id))
277
+ logger.info(f"Deleted single site (ID: {site_id}) and signed out")
113
278
 
114
279
  # Create new site
115
280
  @api(version="2.0")
116
281
  def create(self, site_item: SiteItem) -> SiteItem:
282
+ """
283
+ Creates a new site on the server for the specified site item object.
284
+
285
+ Tableau Server only.
286
+
287
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#create_site
288
+
289
+ Parameters
290
+ ----------
291
+ site_item : SiteItem
292
+ The settings for the site that you want to create. You need to
293
+ create an instance of SiteItem and pass it to the create method.
294
+
295
+ Returns
296
+ -------
297
+ SiteItem
298
+ The site item object that was created.
299
+
300
+ Raises
301
+ ------
302
+ ValueError
303
+ If the site admin mode is set to ContentOnly and a user quota is also set.
304
+
305
+ Examples
306
+ --------
307
+ >>> import tableauserverclient as TSC
308
+
309
+ >>> # create an instance of server
310
+ >>> server = TSC.Server('https://MY-SERVER')
311
+
312
+ >>> # create shortcut for admin mode
313
+ >>> content_users=TSC.SiteItem.AdminMode.ContentAndUsers
314
+
315
+ >>> # create a new SiteItem
316
+ >>> new_site = TSC.SiteItem(name='Tableau', content_url='tableau', admin_mode=content_users, user_quota=15, storage_quota=1000, disable_subscriptions=True)
317
+
318
+ >>> # call the sites create method with the SiteItem
319
+ >>> new_site = server.sites.create(new_site)
320
+
321
+
322
+ """
117
323
  if site_item.admin_mode:
118
324
  if site_item.admin_mode == SiteItem.AdminMode.ContentOnly and site_item.user_quota:
119
325
  error = "You cannot set admin_mode to ContentOnly and also set a user quota"
@@ -123,33 +329,92 @@ class Sites(Endpoint):
123
329
  create_req = RequestFactory.Site.create_req(site_item, self.parent_srv)
124
330
  server_response = self.post_request(url, create_req)
125
331
  new_site = SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
126
- logger.info("Created new site (ID: {0})".format(new_site.id))
332
+ logger.info(f"Created new site (ID: {new_site.id})")
127
333
  return new_site
128
334
 
129
335
  @api(version="3.5")
130
336
  def encrypt_extracts(self, site_id: str) -> None:
337
+ """
338
+ Encrypts all extracts on the site.
339
+
340
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#encrypt_extracts
341
+
342
+ Parameters
343
+ ----------
344
+ site_id : str
345
+ The site ID.
346
+
347
+ Raises
348
+ ------
349
+ ValueError
350
+ If the site ID is not defined.
351
+
352
+ Examples
353
+ --------
354
+ >>> server.sites.encrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
355
+ """
131
356
  if not site_id:
132
357
  error = "Site ID undefined."
133
358
  raise ValueError(error)
134
- url = "{0}/{1}/encrypt-extracts".format(self.baseurl, site_id)
359
+ url = f"{self.baseurl}/{site_id}/encrypt-extracts"
135
360
  empty_req = RequestFactory.Empty.empty_req()
136
361
  self.post_request(url, empty_req)
137
362
 
138
363
  @api(version="3.5")
139
364
  def decrypt_extracts(self, site_id: str) -> None:
365
+ """
366
+ Decrypts all extracts on the site.
367
+
368
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#decrypt_extracts
369
+
370
+ Parameters
371
+ ----------
372
+ site_id : str
373
+ The site ID.
374
+
375
+ Raises
376
+ ------
377
+ ValueError
378
+ If the site ID is not defined.
379
+
380
+ Examples
381
+ --------
382
+ >>> server.sites.decrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
383
+ """
140
384
  if not site_id:
141
385
  error = "Site ID undefined."
142
386
  raise ValueError(error)
143
- url = "{0}/{1}/decrypt-extracts".format(self.baseurl, site_id)
387
+ url = f"{self.baseurl}/{site_id}/decrypt-extracts"
144
388
  empty_req = RequestFactory.Empty.empty_req()
145
389
  self.post_request(url, empty_req)
146
390
 
147
391
  @api(version="3.5")
148
392
  def re_encrypt_extracts(self, site_id: str) -> None:
393
+ """
394
+ Reencrypt all extracts on a site with new encryption keys. If no site is
395
+ specified, extracts on the default site will be reencrypted.
396
+
397
+ REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm#reencrypt_extracts
398
+
399
+ Parameters
400
+ ----------
401
+ site_id : str
402
+ The site ID.
403
+
404
+ Raises
405
+ ------
406
+ ValueError
407
+ If the site ID is not defined.
408
+
409
+ Examples
410
+ --------
411
+ >>> server.sites.re_encrypt_extracts('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p')
412
+
413
+ """
149
414
  if not site_id:
150
415
  error = "Site ID undefined."
151
416
  raise ValueError(error)
152
- url = "{0}/{1}/reencrypt-extracts".format(self.baseurl, site_id)
417
+ url = f"{self.baseurl}/{site_id}/reencrypt-extracts"
153
418
 
154
419
  empty_req = RequestFactory.Empty.empty_req()
155
420
  self.post_request(url, empty_req)