tableauserverclient 0.25__py3-none-any.whl → 0.27.post0.dev1__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 (77) hide show
  1. tableauserverclient/__init__.py +42 -1
  2. tableauserverclient/_version.py +4 -4
  3. tableauserverclient/config.py +13 -0
  4. tableauserverclient/datetime_helpers.py +4 -0
  5. tableauserverclient/helpers/logging.py +4 -0
  6. tableauserverclient/models/__init__.py +1 -1
  7. tableauserverclient/models/column_item.py +3 -0
  8. tableauserverclient/models/connection_credentials.py +7 -0
  9. tableauserverclient/models/connection_item.py +1 -1
  10. tableauserverclient/models/custom_view_item.py +5 -0
  11. tableauserverclient/models/data_acceleration_report_item.py +3 -0
  12. tableauserverclient/models/datasource_item.py +10 -54
  13. tableauserverclient/models/favorites_item.py +56 -40
  14. tableauserverclient/models/fileupload_item.py +2 -2
  15. tableauserverclient/models/flow_item.py +30 -25
  16. tableauserverclient/models/group_item.py +1 -4
  17. tableauserverclient/models/interval_item.py +12 -0
  18. tableauserverclient/models/job_item.py +10 -1
  19. tableauserverclient/models/metric_item.py +36 -29
  20. tableauserverclient/models/pagination_item.py +3 -0
  21. tableauserverclient/models/permissions_item.py +8 -5
  22. tableauserverclient/models/project_item.py +11 -13
  23. tableauserverclient/models/schedule_item.py +6 -7
  24. tableauserverclient/models/server_info_item.py +2 -2
  25. tableauserverclient/models/site_item.py +3 -0
  26. tableauserverclient/models/subscription_item.py +8 -0
  27. tableauserverclient/models/table_item.py +6 -0
  28. tableauserverclient/models/tableau_auth.py +41 -6
  29. tableauserverclient/models/tableau_types.py +4 -2
  30. tableauserverclient/models/user_item.py +5 -1
  31. tableauserverclient/models/view_item.py +39 -36
  32. tableauserverclient/models/workbook_item.py +14 -43
  33. tableauserverclient/server/__init__.py +1 -3
  34. tableauserverclient/server/endpoint/__init__.py +1 -5
  35. tableauserverclient/server/endpoint/auth_endpoint.py +29 -8
  36. tableauserverclient/server/endpoint/custom_views_endpoint.py +1 -1
  37. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +1 -1
  38. tableauserverclient/server/endpoint/data_alert_endpoint.py +1 -1
  39. tableauserverclient/server/endpoint/databases_endpoint.py +1 -1
  40. tableauserverclient/server/endpoint/datasources_endpoint.py +21 -15
  41. tableauserverclient/server/endpoint/default_permissions_endpoint.py +1 -1
  42. tableauserverclient/server/endpoint/dqw_endpoint.py +1 -1
  43. tableauserverclient/server/endpoint/endpoint.py +98 -11
  44. tableauserverclient/server/endpoint/exceptions.py +1 -5
  45. tableauserverclient/server/endpoint/favorites_endpoint.py +71 -29
  46. tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -10
  47. tableauserverclient/server/endpoint/flow_runs_endpoint.py +1 -1
  48. tableauserverclient/server/endpoint/flows_endpoint.py +5 -5
  49. tableauserverclient/server/endpoint/groups_endpoint.py +5 -2
  50. tableauserverclient/server/endpoint/jobs_endpoint.py +1 -1
  51. tableauserverclient/server/endpoint/metadata_endpoint.py +1 -1
  52. tableauserverclient/server/endpoint/metrics_endpoint.py +1 -1
  53. tableauserverclient/server/endpoint/permissions_endpoint.py +1 -1
  54. tableauserverclient/server/endpoint/projects_endpoint.py +3 -1
  55. tableauserverclient/server/endpoint/resource_tagger.py +3 -3
  56. tableauserverclient/server/endpoint/schedules_endpoint.py +2 -1
  57. tableauserverclient/server/endpoint/server_info_endpoint.py +2 -4
  58. tableauserverclient/server/endpoint/sites_endpoint.py +1 -1
  59. tableauserverclient/server/endpoint/subscriptions_endpoint.py +1 -1
  60. tableauserverclient/server/endpoint/tables_endpoint.py +1 -1
  61. tableauserverclient/server/endpoint/tasks_endpoint.py +12 -1
  62. tableauserverclient/server/endpoint/users_endpoint.py +1 -1
  63. tableauserverclient/server/endpoint/views_endpoint.py +1 -1
  64. tableauserverclient/server/endpoint/webhooks_endpoint.py +1 -1
  65. tableauserverclient/server/endpoint/workbooks_endpoint.py +4 -2
  66. tableauserverclient/server/exceptions.py +8 -1
  67. tableauserverclient/server/filter.py +5 -1
  68. tableauserverclient/server/request_factory.py +56 -12
  69. tableauserverclient/server/request_options.py +4 -2
  70. tableauserverclient/server/server.py +12 -13
  71. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/METADATA +12 -10
  72. tableauserverclient-0.27.post0.dev1.dist-info/RECORD +97 -0
  73. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/WHEEL +1 -1
  74. tableauserverclient-0.25.dist-info/RECORD +0 -95
  75. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/LICENSE +0 -0
  76. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/LICENSE.versioneer +0 -0
  77. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,20 @@
1
- import logging
2
-
3
1
  from .endpoint import Endpoint, api
4
- from tableauserverclient.server import RequestFactory
5
- from tableauserverclient.models import FavoriteItem
6
-
7
- from typing import Optional, TYPE_CHECKING
8
-
9
- if TYPE_CHECKING:
10
- from ...models import DatasourceItem, FlowItem, ProjectItem, UserItem, ViewItem, WorkbookItem
11
- from ..request_options import RequestOptions
12
-
13
- logger = logging.getLogger("tableau.endpoint.favorites")
2
+ from requests import Response
3
+ from tableauserverclient.helpers.logging import logger
4
+ from tableauserverclient.models import (
5
+ DatasourceItem,
6
+ FavoriteItem,
7
+ FlowItem,
8
+ MetricItem,
9
+ ProjectItem,
10
+ Resource,
11
+ TableauItem,
12
+ UserItem,
13
+ ViewItem,
14
+ WorkbookItem,
15
+ )
16
+ from tableauserverclient.server import RequestFactory, RequestOptions
17
+ from typing import Optional
14
18
 
15
19
 
16
20
  class Favorites(Endpoint):
@@ -20,74 +24,112 @@ class Favorites(Endpoint):
20
24
 
21
25
  # Gets all favorites
22
26
  @api(version="2.5")
23
- def get(self, user_item: "UserItem", req_options: Optional["RequestOptions"] = None) -> None:
27
+ def get(self, user_item: UserItem, req_options: Optional[RequestOptions] = None) -> None:
24
28
  logger.info("Querying all favorites for user {0}".format(user_item.name))
25
29
  url = "{0}/{1}".format(self.baseurl, user_item.id)
26
30
  server_response = self.get_request(url, req_options)
27
-
28
31
  user_item._favorites = FavoriteItem.from_response(server_response.content, self.parent_srv.namespace)
29
32
 
33
+ # ---------add to favorites
34
+
35
+ @api(version="3.15")
36
+ def add_favorite(self, user_item: UserItem, content_type: str, item: TableauItem) -> "Response":
37
+ url = "{0}/{1}".format(self.baseurl, user_item.id)
38
+ add_req = RequestFactory.Favorite.add_request(item.id, content_type, item.name)
39
+ server_response = self.put_request(url, add_req)
40
+ logger.info("Favorited {0} for user (ID: {1})".format(item.name, user_item.id))
41
+ return server_response
42
+
30
43
  @api(version="2.0")
31
- def add_favorite_workbook(self, user_item: "UserItem", workbook_item: "WorkbookItem") -> None:
44
+ def add_favorite_workbook(self, user_item: UserItem, workbook_item: WorkbookItem) -> None:
32
45
  url = "{0}/{1}".format(self.baseurl, user_item.id)
33
46
  add_req = RequestFactory.Favorite.add_workbook_req(workbook_item.id, workbook_item.name)
34
47
  server_response = self.put_request(url, add_req)
35
48
  logger.info("Favorited {0} for user (ID: {1})".format(workbook_item.name, user_item.id))
36
49
 
37
50
  @api(version="2.0")
38
- def add_favorite_view(self, user_item: "UserItem", view_item: "ViewItem") -> None:
51
+ def add_favorite_view(self, user_item: UserItem, view_item: ViewItem) -> None:
39
52
  url = "{0}/{1}".format(self.baseurl, user_item.id)
40
53
  add_req = RequestFactory.Favorite.add_view_req(view_item.id, view_item.name)
41
54
  server_response = self.put_request(url, add_req)
42
55
  logger.info("Favorited {0} for user (ID: {1})".format(view_item.name, user_item.id))
43
56
 
44
57
  @api(version="2.3")
45
- def add_favorite_datasource(self, user_item: "UserItem", datasource_item: "DatasourceItem") -> None:
58
+ def add_favorite_datasource(self, user_item: UserItem, datasource_item: DatasourceItem) -> None:
46
59
  url = "{0}/{1}".format(self.baseurl, user_item.id)
47
60
  add_req = RequestFactory.Favorite.add_datasource_req(datasource_item.id, datasource_item.name)
48
61
  server_response = self.put_request(url, add_req)
49
62
  logger.info("Favorited {0} for user (ID: {1})".format(datasource_item.name, user_item.id))
50
63
 
51
64
  @api(version="3.1")
52
- def add_favorite_project(self, user_item: "UserItem", project_item: "ProjectItem") -> None:
65
+ def add_favorite_project(self, user_item: UserItem, project_item: ProjectItem) -> None:
53
66
  url = "{0}/{1}".format(self.baseurl, user_item.id)
54
67
  add_req = RequestFactory.Favorite.add_project_req(project_item.id, project_item.name)
55
68
  server_response = self.put_request(url, add_req)
56
69
  logger.info("Favorited {0} for user (ID: {1})".format(project_item.name, user_item.id))
57
70
 
58
71
  @api(version="3.3")
59
- def add_favorite_flow(self, user_item: "UserItem", flow_item: "FlowItem") -> None:
72
+ def add_favorite_flow(self, user_item: UserItem, flow_item: FlowItem) -> None:
60
73
  url = "{0}/{1}".format(self.baseurl, user_item.id)
61
74
  add_req = RequestFactory.Favorite.add_flow_req(flow_item.id, flow_item.name)
62
75
  server_response = self.put_request(url, add_req)
63
76
  logger.info("Favorited {0} for user (ID: {1})".format(flow_item.name, user_item.id))
64
77
 
78
+ @api(version="3.3")
79
+ def add_favorite_metric(self, user_item: UserItem, metric_item: MetricItem) -> None:
80
+ url = "{0}/{1}".format(self.baseurl, user_item.id)
81
+ add_req = RequestFactory.Favorite.add_request(metric_item.id, Resource.Metric, metric_item.name)
82
+ server_response = self.put_request(url, add_req)
83
+ logger.info("Favorited metric {0} for user (ID: {1})".format(metric_item.name, user_item.id))
84
+
85
+ # ------- delete from favorites
86
+ # Response:
87
+ """
88
+ <tsResponse>
89
+ <favorites>
90
+ <favorite label="favorite-label">
91
+ </favorites>
92
+ </tsResponse>
93
+ """
94
+
95
+ @api(version="3.15")
96
+ def delete_favorite(self, user_item: UserItem, content_type: Resource, item: TableauItem) -> None:
97
+ url = "{0}/{1}/{2}/{3}".format(self.baseurl, user_item.id, content_type, item.id)
98
+ logger.info("Removing favorite {0}({1}) for user (ID: {2})".format(content_type, item.id, user_item.id))
99
+ self.delete_request(url)
100
+
65
101
  @api(version="2.0")
66
- def delete_favorite_workbook(self, user_item: "UserItem", workbook_item: "WorkbookItem") -> None:
102
+ def delete_favorite_workbook(self, user_item: UserItem, workbook_item: WorkbookItem) -> None:
67
103
  url = "{0}/{1}/workbooks/{2}".format(self.baseurl, user_item.id, workbook_item.id)
68
- logger.info("Removing favorite {0} for user (ID: {1})".format(workbook_item.id, user_item.id))
104
+ logger.info("Removing favorite workbook {0} for user (ID: {1})".format(workbook_item.id, user_item.id))
69
105
  self.delete_request(url)
70
106
 
71
107
  @api(version="2.0")
72
- def delete_favorite_view(self, user_item: "UserItem", view_item: "ViewItem") -> None:
108
+ def delete_favorite_view(self, user_item: UserItem, view_item: ViewItem) -> None:
73
109
  url = "{0}/{1}/views/{2}".format(self.baseurl, user_item.id, view_item.id)
74
- logger.info("Removing favorite {0} for user (ID: {1})".format(view_item.id, user_item.id))
110
+ logger.info("Removing favorite view {0} for user (ID: {1})".format(view_item.id, user_item.id))
75
111
  self.delete_request(url)
76
112
 
77
113
  @api(version="2.3")
78
- def delete_favorite_datasource(self, user_item: "UserItem", datasource_item: "DatasourceItem") -> None:
114
+ def delete_favorite_datasource(self, user_item: UserItem, datasource_item: DatasourceItem) -> None:
79
115
  url = "{0}/{1}/datasources/{2}".format(self.baseurl, user_item.id, datasource_item.id)
80
116
  logger.info("Removing favorite {0} for user (ID: {1})".format(datasource_item.id, user_item.id))
81
117
  self.delete_request(url)
82
118
 
83
119
  @api(version="3.1")
84
- def delete_favorite_project(self, user_item: "UserItem", project_item: "ProjectItem") -> None:
120
+ def delete_favorite_project(self, user_item: UserItem, project_item: ProjectItem) -> None:
85
121
  url = "{0}/{1}/projects/{2}".format(self.baseurl, user_item.id, project_item.id)
86
- logger.info("Removing favorite {0} for user (ID: {1})".format(project_item.id, user_item.id))
122
+ logger.info("Removing favorite project {0} for user (ID: {1})".format(project_item.id, user_item.id))
87
123
  self.delete_request(url)
88
124
 
89
125
  @api(version="3.3")
90
- def delete_favorite_flow(self, user_item: "UserItem", flow_item: "FlowItem") -> None:
91
- url = "{0}/{1}/projects/{2}".format(self.baseurl, user_item.id, flow_item.id)
92
- logger.info("Removing favorite {0} for user (ID: {1})".format(flow_item.id, user_item.id))
126
+ def delete_favorite_flow(self, user_item: UserItem, flow_item: FlowItem) -> None:
127
+ url = "{0}/{1}/flows/{2}".format(self.baseurl, user_item.id, flow_item.id)
128
+ logger.info("Removing favorite flow {0} for user (ID: {1})".format(flow_item.id, user_item.id))
129
+ self.delete_request(url)
130
+
131
+ @api(version="3.15")
132
+ def delete_favorite_metric(self, user_item: UserItem, metric_item: MetricItem) -> None:
133
+ url = "{0}/{1}/metrics/{2}".format(self.baseurl, user_item.id, metric_item.id)
134
+ logger.info("Removing favorite metric {0} for user (ID: {1})".format(metric_item.id, user_item.id))
93
135
  self.delete_request(url)
@@ -1,13 +1,10 @@
1
- import logging
2
-
3
1
  from .endpoint import Endpoint, api
4
- from tableauserverclient.server import RequestFactory
5
- from tableauserverclient.models import FileuploadItem
2
+ from tableauserverclient import datetime_helpers as datetime
3
+ from tableauserverclient.helpers.logging import logger
6
4
 
7
- # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
8
- CHUNK_SIZE = 1024 * 1024 * 5 # 5MB
9
-
10
- logger = logging.getLogger("tableau.endpoint.fileuploads")
5
+ from tableauserverclient.config import BYTES_PER_MB, CHUNK_SIZE_MB
6
+ from tableauserverclient.models import FileuploadItem
7
+ from tableauserverclient.server import RequestFactory
11
8
 
12
9
 
13
10
  class Fileuploads(Endpoint):
@@ -44,7 +41,7 @@ class Fileuploads(Endpoint):
44
41
 
45
42
  try:
46
43
  while True:
47
- chunked_content = file_content.read(CHUNK_SIZE)
44
+ chunked_content = file_content.read(CHUNK_SIZE_MB * BYTES_PER_MB)
48
45
  if not chunked_content:
49
46
  break
50
47
  yield chunked_content
@@ -55,8 +52,12 @@ class Fileuploads(Endpoint):
55
52
  def upload(self, file):
56
53
  upload_id = self.initiate()
57
54
  for chunk in self._read_chunks(file):
55
+ logger.debug("{} processing chunk...".format(datetime.timestamp()))
58
56
  request, content_type = RequestFactory.Fileupload.chunk_req(chunk)
57
+ logger.debug("{} created chunk request".format(datetime.timestamp()))
59
58
  fileupload_item = self.append(upload_id, request, content_type)
60
- logger.info("\tPublished {0}MB".format(fileupload_item.file_size))
59
+ logger.info(
60
+ "\t{0} Published {1}MB".format(datetime.timestamp(), (fileupload_item.file_size / BYTES_PER_MB))
61
+ )
61
62
  logger.info("File upload finished (ID: {0})".format(upload_id))
62
63
  return upload_id
@@ -6,7 +6,7 @@ from .exceptions import FlowRunFailedException, FlowRunCancelledException
6
6
  from tableauserverclient.models import FlowRunItem, PaginationItem
7
7
  from tableauserverclient.exponential_backoff import ExponentialBackoffTimer
8
8
 
9
- logger = logging.getLogger("tableau.endpoint.flowruns")
9
+ from tableauserverclient.helpers.logging import logger
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from ..server import Server
@@ -32,13 +32,13 @@ FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB
32
32
 
33
33
  ALLOWED_FILE_EXTENSIONS = ["tfl", "tflx"]
34
34
 
35
- logger = logging.getLogger("tableau.endpoint.flows")
35
+ from tableauserverclient.helpers.logging import logger
36
36
 
37
37
  if TYPE_CHECKING:
38
- from .. import DQWItem
39
- from ..request_options import RequestOptions
40
- from ...models.permissions_item import PermissionsRule
41
- from .schedules_endpoint import AddResponse
38
+ from tableauserverclient.models import DQWItem
39
+ from tableauserverclient.models.permissions_item import PermissionsRule
40
+ from tableauserverclient.server.request_options import RequestOptions
41
+ from tableauserverclient.server.endpoint.schedules_endpoint import AddResponse
42
42
 
43
43
 
44
44
  FilePath = Union[str, os.PathLike]
@@ -6,7 +6,7 @@ from tableauserverclient.server import RequestFactory
6
6
  from tableauserverclient.models import GroupItem, UserItem, PaginationItem, JobItem
7
7
  from ..pager import Pager
8
8
 
9
- logger = logging.getLogger("tableau.endpoint.groups")
9
+ from tableauserverclient.helpers.logging import logger
10
10
 
11
11
  from typing import List, Optional, TYPE_CHECKING, Tuple, Union
12
12
 
@@ -82,14 +82,17 @@ class Groups(QuerysetEndpoint):
82
82
  )
83
83
  group_item.minimum_site_role = default_site_role
84
84
 
85
+ url = "{0}/{1}".format(self.baseurl, group_item.id)
86
+
85
87
  if not group_item.id:
86
88
  error = "Group item missing ID."
87
89
  raise MissingRequiredFieldError(error)
88
90
  if as_job and (group_item.domain_name is None or group_item.domain_name == "local"):
89
91
  error = "Local groups cannot be updated asynchronously."
90
92
  raise ValueError(error)
93
+ elif as_job:
94
+ url = "?".join([url, "asJob=True"])
91
95
 
92
- url = "{0}/{1}".format(self.baseurl, group_item.id)
93
96
  update_req = RequestFactory.Group.update_req(group_item, None)
94
97
  server_response = self.put_request(url, update_req)
95
98
  logger.info("Updated group item (ID: {0})".format(group_item.id))
@@ -6,7 +6,7 @@ from tableauserverclient.models import JobItem, BackgroundJobItem, PaginationIte
6
6
  from ..request_options import RequestOptionsBase
7
7
  from tableauserverclient.exponential_backoff import ExponentialBackoffTimer
8
8
 
9
- logger = logging.getLogger("tableau.endpoint.jobs")
9
+ from tableauserverclient.helpers.logging import logger
10
10
 
11
11
  from typing import List, Optional, Tuple, Union
12
12
 
@@ -4,7 +4,7 @@ import logging
4
4
  from .endpoint import Endpoint, api
5
5
  from .exceptions import GraphQLError, InvalidGraphQLQuery
6
6
 
7
- logger = logging.getLogger("tableau.endpoint.metadata")
7
+ from tableauserverclient.helpers.logging import logger
8
8
 
9
9
 
10
10
  def is_valid_paged_query(parsed_query):
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
15
15
  from ...server import Server
16
16
 
17
17
 
18
- logger = logging.getLogger("tableau.endpoint.metrics")
18
+ from tableauserverclient.helpers.logging import logger
19
19
 
20
20
 
21
21
  class Metrics(QuerysetEndpoint):
@@ -8,7 +8,7 @@ from .exceptions import MissingRequiredFieldError
8
8
 
9
9
  from typing import Callable, TYPE_CHECKING, List, Optional, Union
10
10
 
11
- logger = logging.getLogger(__name__)
11
+ from tableauserverclient.helpers.logging import logger
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from ..server import Server
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
13
13
  from ..server import Server
14
14
  from ..request_options import RequestOptions
15
15
 
16
- logger = logging.getLogger("tableau.endpoint.projects")
16
+ from tableauserverclient.helpers.logging import logger
17
17
 
18
18
 
19
19
  class Projects(QuerysetEndpoint):
@@ -63,6 +63,8 @@ class Projects(QuerysetEndpoint):
63
63
  def create(self, project_item: ProjectItem, samples: bool = False) -> ProjectItem:
64
64
  params = {"params": {RequestOptions.Field.PublishSamples: samples}}
65
65
  url = self.baseurl
66
+ if project_item._samples:
67
+ url = "{0}?publishSamples={1}".format(self.baseurl, project_item._samples)
66
68
  create_req = RequestFactory.Project.create_req(project_item)
67
69
  server_response = self.post_request(url, create_req, XML_CONTENT_TYPE, params)
68
70
  new_project = ProjectItem.from_response(server_response.content, self.parent_srv.namespace)[0]
@@ -1,13 +1,13 @@
1
1
  import copy
2
- import logging
3
2
  import urllib.parse
4
3
 
5
4
  from .endpoint import Endpoint
6
- from .exceptions import EndpointUnavailableError, ServerResponseError
5
+ from .exceptions import ServerResponseError
6
+ from ..exceptions import EndpointUnavailableError
7
7
  from tableauserverclient.server import RequestFactory
8
8
  from tableauserverclient.models import TagItem
9
9
 
10
- logger = logging.getLogger("tableau.endpoint.resource_tagger")
10
+ from tableauserverclient.helpers.logging import logger
11
11
 
12
12
 
13
13
  class _ResourceTagger(Endpoint):
@@ -9,7 +9,8 @@ from .exceptions import MissingRequiredFieldError
9
9
  from tableauserverclient.server import RequestFactory
10
10
  from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem
11
11
 
12
- logger = logging.getLogger("tableau.endpoint.schedules")
12
+ from tableauserverclient.helpers.logging import logger
13
+
13
14
  AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created"))
14
15
  OK = AddResponse(result=True, error=None, warnings=None, task_created=None)
15
16
 
@@ -1,15 +1,13 @@
1
1
  import logging
2
2
 
3
3
  from .endpoint import Endpoint, api
4
- from .exceptions import (
5
- ServerResponseError,
4
+ from .exceptions import ServerResponseError
5
+ from ..exceptions import (
6
6
  ServerInfoEndpointNotFoundError,
7
7
  EndpointUnavailableError,
8
8
  )
9
9
  from tableauserverclient.models import ServerInfoItem
10
10
 
11
- logger = logging.getLogger("tableau.endpoint.server_info")
12
-
13
11
 
14
12
  class ServerInfo(Endpoint):
15
13
  def __init__(self, server):
@@ -6,7 +6,7 @@ from .exceptions import MissingRequiredFieldError
6
6
  from tableauserverclient.server import RequestFactory
7
7
  from tableauserverclient.models import SiteItem, PaginationItem
8
8
 
9
- logger = logging.getLogger("tableau.endpoint.sites")
9
+ from tableauserverclient.helpers.logging import logger
10
10
 
11
11
  from typing import TYPE_CHECKING, List, Optional, Tuple
12
12
 
@@ -5,7 +5,7 @@ from .exceptions import MissingRequiredFieldError
5
5
  from tableauserverclient.server import RequestFactory
6
6
  from tableauserverclient.models import SubscriptionItem, PaginationItem
7
7
 
8
- logger = logging.getLogger("tableau.endpoint.subscriptions")
8
+ from tableauserverclient.helpers.logging import logger
9
9
 
10
10
  from typing import List, Optional, TYPE_CHECKING, Tuple
11
11
 
@@ -8,7 +8,7 @@ from tableauserverclient.server import RequestFactory
8
8
  from tableauserverclient.models import TableItem, ColumnItem, PaginationItem
9
9
  from ..pager import Pager
10
10
 
11
- logger = logging.getLogger("tableau.endpoint.tables")
11
+ from tableauserverclient.helpers.logging import logger
12
12
 
13
13
 
14
14
  class Tables(Endpoint):
@@ -5,7 +5,7 @@ from .exceptions import MissingRequiredFieldError
5
5
  from tableauserverclient.models import TaskItem, PaginationItem
6
6
  from tableauserverclient.server import RequestFactory
7
7
 
8
- logger = logging.getLogger("tableau.endpoint.tasks")
8
+ from tableauserverclient.helpers.logging import logger
9
9
 
10
10
 
11
11
  class Tasks(Endpoint):
@@ -51,6 +51,17 @@ class Tasks(Endpoint):
51
51
  server_response = self.get_request(url)
52
52
  return TaskItem.from_response(server_response.content, self.parent_srv.namespace)[0]
53
53
 
54
+ @api(version="3.19")
55
+ def create(self, extract_item: TaskItem) -> TaskItem:
56
+ if not extract_item:
57
+ error = "No extract refresh provided"
58
+ raise ValueError(error)
59
+ logger.info("Creating an extract refresh ({})".format(extract_item))
60
+ url = "{0}/{1}".format(self.baseurl, self.__normalize_task_type(TaskItem.Type.ExtractRefresh))
61
+ create_req = RequestFactory.Task.create_extract_req(extract_item)
62
+ server_response = self.post_request(url, create_req)
63
+ return server_response.content
64
+
54
65
  @api(version="2.6")
55
66
  def run(self, task_item):
56
67
  if not task_item.id:
@@ -8,7 +8,7 @@ from tableauserverclient.server import RequestFactory, RequestOptions
8
8
  from tableauserverclient.models import UserItem, WorkbookItem, PaginationItem, GroupItem
9
9
  from ..pager import Pager
10
10
 
11
- logger = logging.getLogger("tableau.endpoint.users")
11
+ from tableauserverclient.helpers.logging import logger
12
12
 
13
13
 
14
14
  class Users(QuerysetEndpoint):
@@ -7,7 +7,7 @@ from .permissions_endpoint import _PermissionsEndpoint
7
7
  from .resource_tagger import _ResourceTagger
8
8
  from tableauserverclient.models import ViewItem, PaginationItem
9
9
 
10
- logger = logging.getLogger("tableau.endpoint.views")
10
+ from tableauserverclient.helpers.logging import logger
11
11
 
12
12
  from typing import Iterator, List, Optional, Tuple, TYPE_CHECKING
13
13
 
@@ -4,7 +4,7 @@ from .endpoint import Endpoint, api
4
4
  from tableauserverclient.server import RequestFactory
5
5
  from tableauserverclient.models import WebhookItem, PaginationItem
6
6
 
7
- logger = logging.getLogger("tableau.endpoint.webhooks")
7
+ from tableauserverclient.helpers.logging import logger
8
8
 
9
9
  from typing import List, Optional, TYPE_CHECKING, Tuple
10
10
 
@@ -44,7 +44,8 @@ FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB
44
44
 
45
45
  ALLOWED_FILE_EXTENSIONS = ["twb", "twbx"]
46
46
 
47
- logger = logging.getLogger("tableau.endpoint.workbooks")
47
+ from tableauserverclient.helpers.logging import logger
48
+
48
49
  FilePath = Union[str, os.PathLike]
49
50
  FileObject = Union[io.BufferedReader, io.BytesIO]
50
51
  FileObjectR = Union[io.BufferedReader, io.BytesIO]
@@ -309,6 +310,7 @@ class Workbooks(QuerysetEndpoint):
309
310
  as_job: bool = False,
310
311
  hidden_views: Optional[Sequence[str]] = None,
311
312
  skip_connection_check: bool = False,
313
+ parameters=None,
312
314
  ):
313
315
  if connection_credentials is not None:
314
316
  import warnings
@@ -412,7 +414,7 @@ class Workbooks(QuerysetEndpoint):
412
414
 
413
415
  # Send the publishing request to server
414
416
  try:
415
- server_response = self.post_request(url, xml_request, content_type)
417
+ server_response = self.post_request(url, xml_request, content_type, parameters)
416
418
  except InternalServerError as err:
417
419
  if err.code == 504 and not as_job:
418
420
  err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts."
@@ -1,2 +1,9 @@
1
- class NotSignedInError(Exception):
1
+ # These errors can be thrown without even talking to Tableau Server
2
+
3
+
4
+ class ServerInfoEndpointNotFoundError(Exception):
5
+ pass
6
+
7
+
8
+ class EndpointUnavailableError(Exception):
2
9
  pass
@@ -11,7 +11,11 @@ class Filter(object):
11
11
  def __str__(self):
12
12
  value_string = str(self._value)
13
13
  if isinstance(self._value, list):
14
- value_string = value_string.replace(" ", "").replace("'", "")
14
+ # this should turn the string representation of the list
15
+ # from ['<string1>', '<string2>', ...]
16
+ # to [<string1>,<string2>]
17
+ # so effectively, remove any spaces between "," and "'" and then remove all "'"
18
+ value_string = value_string.replace(", '", ",'").replace("'", "")
15
19
  return "{0}:{1}:{2}".format(self.field, self.operator, value_string)
16
20
 
17
21
  @property