tableauserverclient 0.32__py3-none-any.whl → 0.34__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 (96) hide show
  1. tableauserverclient/__init__.py +34 -18
  2. tableauserverclient/_version.py +3 -3
  3. tableauserverclient/config.py +20 -6
  4. tableauserverclient/models/__init__.py +12 -0
  5. tableauserverclient/models/column_item.py +1 -1
  6. tableauserverclient/models/connection_credentials.py +1 -1
  7. tableauserverclient/models/connection_item.py +10 -8
  8. tableauserverclient/models/custom_view_item.py +29 -6
  9. tableauserverclient/models/data_acceleration_report_item.py +2 -2
  10. tableauserverclient/models/data_alert_item.py +5 -5
  11. tableauserverclient/models/data_freshness_policy_item.py +6 -6
  12. tableauserverclient/models/database_item.py +8 -2
  13. tableauserverclient/models/datasource_item.py +10 -10
  14. tableauserverclient/models/dqw_item.py +1 -1
  15. tableauserverclient/models/favorites_item.py +5 -6
  16. tableauserverclient/models/fileupload_item.py +1 -1
  17. tableauserverclient/models/flow_item.py +12 -12
  18. tableauserverclient/models/flow_run_item.py +3 -3
  19. tableauserverclient/models/group_item.py +4 -4
  20. tableauserverclient/models/groupset_item.py +53 -0
  21. tableauserverclient/models/interval_item.py +36 -23
  22. tableauserverclient/models/job_item.py +26 -10
  23. tableauserverclient/models/linked_tasks_item.py +102 -0
  24. tableauserverclient/models/metric_item.py +5 -5
  25. tableauserverclient/models/pagination_item.py +1 -1
  26. tableauserverclient/models/permissions_item.py +19 -14
  27. tableauserverclient/models/project_item.py +35 -19
  28. tableauserverclient/models/property_decorators.py +12 -11
  29. tableauserverclient/models/reference_item.py +2 -2
  30. tableauserverclient/models/revision_item.py +3 -3
  31. tableauserverclient/models/schedule_item.py +2 -2
  32. tableauserverclient/models/server_info_item.py +26 -6
  33. tableauserverclient/models/site_item.py +69 -3
  34. tableauserverclient/models/subscription_item.py +3 -3
  35. tableauserverclient/models/table_item.py +1 -1
  36. tableauserverclient/models/tableau_auth.py +115 -5
  37. tableauserverclient/models/tableau_types.py +11 -9
  38. tableauserverclient/models/tag_item.py +3 -4
  39. tableauserverclient/models/task_item.py +4 -4
  40. tableauserverclient/models/user_item.py +47 -17
  41. tableauserverclient/models/view_item.py +11 -10
  42. tableauserverclient/models/virtual_connection_item.py +78 -0
  43. tableauserverclient/models/webhook_item.py +6 -6
  44. tableauserverclient/models/workbook_item.py +90 -12
  45. tableauserverclient/namespace.py +1 -1
  46. tableauserverclient/server/__init__.py +2 -1
  47. tableauserverclient/server/endpoint/__init__.py +8 -0
  48. tableauserverclient/server/endpoint/auth_endpoint.py +68 -11
  49. tableauserverclient/server/endpoint/custom_views_endpoint.py +124 -19
  50. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +2 -2
  51. tableauserverclient/server/endpoint/data_alert_endpoint.py +14 -14
  52. tableauserverclient/server/endpoint/databases_endpoint.py +32 -17
  53. tableauserverclient/server/endpoint/datasources_endpoint.py +150 -59
  54. tableauserverclient/server/endpoint/default_permissions_endpoint.py +19 -18
  55. tableauserverclient/server/endpoint/dqw_endpoint.py +9 -9
  56. tableauserverclient/server/endpoint/endpoint.py +47 -31
  57. tableauserverclient/server/endpoint/exceptions.py +23 -7
  58. tableauserverclient/server/endpoint/favorites_endpoint.py +31 -31
  59. tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -13
  60. tableauserverclient/server/endpoint/flow_runs_endpoint.py +59 -17
  61. tableauserverclient/server/endpoint/flow_task_endpoint.py +2 -2
  62. tableauserverclient/server/endpoint/flows_endpoint.py +73 -35
  63. tableauserverclient/server/endpoint/groups_endpoint.py +96 -27
  64. tableauserverclient/server/endpoint/groupsets_endpoint.py +127 -0
  65. tableauserverclient/server/endpoint/jobs_endpoint.py +79 -12
  66. tableauserverclient/server/endpoint/linked_tasks_endpoint.py +45 -0
  67. tableauserverclient/server/endpoint/metadata_endpoint.py +2 -2
  68. tableauserverclient/server/endpoint/metrics_endpoint.py +10 -10
  69. tableauserverclient/server/endpoint/permissions_endpoint.py +13 -15
  70. tableauserverclient/server/endpoint/projects_endpoint.py +124 -30
  71. tableauserverclient/server/endpoint/resource_tagger.py +139 -6
  72. tableauserverclient/server/endpoint/schedules_endpoint.py +17 -18
  73. tableauserverclient/server/endpoint/server_info_endpoint.py +40 -5
  74. tableauserverclient/server/endpoint/sites_endpoint.py +282 -17
  75. tableauserverclient/server/endpoint/subscriptions_endpoint.py +10 -10
  76. tableauserverclient/server/endpoint/tables_endpoint.py +33 -19
  77. tableauserverclient/server/endpoint/tasks_endpoint.py +8 -8
  78. tableauserverclient/server/endpoint/users_endpoint.py +405 -19
  79. tableauserverclient/server/endpoint/views_endpoint.py +111 -25
  80. tableauserverclient/server/endpoint/virtual_connections_endpoint.py +174 -0
  81. tableauserverclient/server/endpoint/webhooks_endpoint.py +11 -11
  82. tableauserverclient/server/endpoint/workbooks_endpoint.py +735 -68
  83. tableauserverclient/server/filter.py +2 -2
  84. tableauserverclient/server/pager.py +8 -10
  85. tableauserverclient/server/query.py +70 -20
  86. tableauserverclient/server/request_factory.py +213 -41
  87. tableauserverclient/server/request_options.py +125 -145
  88. tableauserverclient/server/server.py +73 -9
  89. tableauserverclient/server/sort.py +2 -2
  90. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/METADATA +17 -17
  91. tableauserverclient-0.34.dist-info/RECORD +106 -0
  92. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/WHEEL +1 -1
  93. tableauserverclient-0.32.dist-info/RECORD +0 -100
  94. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE +0 -0
  95. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/LICENSE.versioneer +0 -0
  96. {tableauserverclient-0.32.dist-info → tableauserverclient-0.34.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,38 @@
1
1
  import logging
2
+ from typing_extensions import Self, overload
3
+
2
4
 
3
- from .endpoint import QuerysetEndpoint, api
4
- from .exceptions import JobCancelledException, JobFailedException
5
5
  from tableauserverclient.models import JobItem, BackgroundJobItem, PaginationItem
6
- from ..request_options import RequestOptionsBase
6
+ from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api
7
+ from tableauserverclient.server.endpoint.exceptions import JobCancelledException, JobFailedException
8
+ from tableauserverclient.server.query import QuerySet
9
+ from tableauserverclient.server.request_options import RequestOptionsBase
7
10
  from tableauserverclient.exponential_backoff import ExponentialBackoffTimer
8
11
 
9
12
  from tableauserverclient.helpers.logging import logger
10
13
 
11
- from typing import List, Optional, Tuple, Union
14
+ from typing import Optional, Union
12
15
 
13
16
 
14
- class Jobs(QuerysetEndpoint[JobItem]):
17
+ class Jobs(QuerysetEndpoint[BackgroundJobItem]):
15
18
  @property
16
19
  def baseurl(self):
17
- return "{0}/sites/{1}/jobs".format(self.parent_srv.baseurl, self.parent_srv.site_id)
20
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/jobs"
21
+
22
+ @overload # type: ignore[override]
23
+ def get(self: Self, job_id: str, req_options: Optional[RequestOptionsBase] = None) -> JobItem: # type: ignore[override]
24
+ ...
25
+
26
+ @overload # type: ignore[override]
27
+ def get(self: Self, job_id: RequestOptionsBase, req_options: None) -> tuple[list[BackgroundJobItem], PaginationItem]: # type: ignore[override]
28
+ ...
29
+
30
+ @overload # type: ignore[override]
31
+ def get(self: Self, job_id: None, req_options: Optional[RequestOptionsBase]) -> tuple[list[BackgroundJobItem], PaginationItem]: # type: ignore[override]
32
+ ...
18
33
 
19
34
  @api(version="2.6")
20
- def get(
21
- self, job_id: Optional[str] = None, req_options: Optional[RequestOptionsBase] = None
22
- ) -> Tuple[List[BackgroundJobItem], PaginationItem]:
35
+ def get(self, job_id=None, req_options=None):
23
36
  # Backwards Compatibility fix until we rev the major version
24
37
  if job_id is not None and isinstance(job_id, str):
25
38
  import warnings
@@ -40,13 +53,13 @@ class Jobs(QuerysetEndpoint[JobItem]):
40
53
  if isinstance(job_id, JobItem):
41
54
  job_id = job_id.id
42
55
  assert isinstance(job_id, str)
43
- url = "{0}/{1}".format(self.baseurl, job_id)
56
+ url = f"{self.baseurl}/{job_id}"
44
57
  return self.put_request(url)
45
58
 
46
59
  @api(version="2.6")
47
60
  def get_by_id(self, job_id: str) -> JobItem:
48
61
  logger.info("Query for information about job " + job_id)
49
- url = "{0}/{1}".format(self.baseurl, job_id)
62
+ url = f"{self.baseurl}/{job_id}"
50
63
  server_response = self.get_request(url)
51
64
  new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
52
65
  return new_job
@@ -64,7 +77,7 @@ class Jobs(QuerysetEndpoint[JobItem]):
64
77
  job = self.get_by_id(job_id)
65
78
  logger.debug(f"\tJob {job_id} progress={job.progress}")
66
79
 
67
- logger.info("Job {} Completed: Finish Code: {} - Notes:{}".format(job_id, job.finish_code, job.notes))
80
+ logger.info(f"Job {job_id} Completed: Finish Code: {job.finish_code} - Notes:{job.notes}")
68
81
 
69
82
  if job.finish_code == JobItem.FinishCode.Success:
70
83
  return job
@@ -74,3 +87,57 @@ class Jobs(QuerysetEndpoint[JobItem]):
74
87
  raise JobCancelledException(job)
75
88
  else:
76
89
  raise AssertionError("Unexpected finish_code in job", job)
90
+
91
+ def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[BackgroundJobItem]:
92
+ """
93
+ Queries the Tableau Server for items using the specified filters. Page
94
+ size can be specified to limit the number of items returned in a single
95
+ request. If not specified, the default page size is 100. Page size can
96
+ be an integer between 1 and 1000.
97
+
98
+ No positional arguments are allowed. All filters must be specified as
99
+ keyword arguments. If you use the equality operator, you can specify it
100
+ through <field_name>=<value>. If you want to use a different operator,
101
+ you can specify it through <field_name>__<operator>=<value>. Field
102
+ names can either be in snake_case or camelCase.
103
+
104
+ This endpoint supports the following fields and operators:
105
+
106
+
107
+ args__has=...
108
+ completed_at=...
109
+ completed_at__gt=...
110
+ completed_at__gte=...
111
+ completed_at__lt=...
112
+ completed_at__lte=...
113
+ created_at=...
114
+ created_at__gt=...
115
+ created_at__gte=...
116
+ created_at__lt=...
117
+ created_at__lte=...
118
+ job_type=...
119
+ job_type__in=...
120
+ notes__has=...
121
+ priority=...
122
+ priority__gt=...
123
+ priority__gte=...
124
+ priority__lt=...
125
+ priority__lte=...
126
+ progress=...
127
+ progress__gt=...
128
+ progress__gte=...
129
+ progress__lt=...
130
+ progress__lte=...
131
+ started_at=...
132
+ started_at__gt=...
133
+ started_at__gte=...
134
+ started_at__lt=...
135
+ started_at__lte=...
136
+ status=...
137
+ subtitle=...
138
+ subtitle__has=...
139
+ title=...
140
+ title__has=...
141
+ """
142
+
143
+ return super().filter(*invalid, page_size=page_size, **kwargs)
@@ -0,0 +1,45 @@
1
+ from typing import Optional, Union
2
+
3
+ from tableauserverclient.helpers.logging import logger
4
+ from tableauserverclient.models.linked_tasks_item import LinkedTaskItem, LinkedTaskJobItem
5
+ from tableauserverclient.models.pagination_item import PaginationItem
6
+ from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api
7
+ from tableauserverclient.server.request_factory import RequestFactory
8
+ from tableauserverclient.server.request_options import RequestOptions
9
+
10
+
11
+ class LinkedTasks(QuerysetEndpoint[LinkedTaskItem]):
12
+ def __init__(self, parent_srv):
13
+ super().__init__(parent_srv)
14
+ self._parent_srv = parent_srv
15
+
16
+ @property
17
+ def baseurl(self) -> str:
18
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/tasks/linked"
19
+
20
+ @api(version="3.15")
21
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[LinkedTaskItem], PaginationItem]:
22
+ logger.info("Querying all linked tasks on site")
23
+ url = self.baseurl
24
+ server_response = self.get_request(url, req_options)
25
+ pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace)
26
+ all_group_items = LinkedTaskItem.from_response(server_response.content, self.parent_srv.namespace)
27
+ return all_group_items, pagination_item
28
+
29
+ @api(version="3.15")
30
+ def get_by_id(self, linked_task: Union[LinkedTaskItem, str]) -> LinkedTaskItem:
31
+ task_id = getattr(linked_task, "id", linked_task)
32
+ logger.info("Querying all linked tasks on site")
33
+ url = f"{self.baseurl}/{task_id}"
34
+ server_response = self.get_request(url)
35
+ all_group_items = LinkedTaskItem.from_response(server_response.content, self.parent_srv.namespace)
36
+ return all_group_items[0]
37
+
38
+ @api(version="3.15")
39
+ def run_now(self, linked_task: Union[LinkedTaskItem, str]) -> LinkedTaskJobItem:
40
+ task_id = getattr(linked_task, "id", linked_task)
41
+ logger.info(f"Running linked task {task_id} now")
42
+ url = f"{self.baseurl}/{task_id}/runNow"
43
+ empty_req = RequestFactory.Empty.empty_req()
44
+ server_response = self.post_request(url, empty_req)
45
+ return LinkedTaskJobItem.from_response(server_response.content, self.parent_srv.namespace)
@@ -50,11 +50,11 @@ def get_page_info(result):
50
50
  class Metadata(Endpoint):
51
51
  @property
52
52
  def baseurl(self):
53
- return "{0}/api/metadata/graphql".format(self.parent_srv.server_address)
53
+ return f"{self.parent_srv.server_address}/api/metadata/graphql"
54
54
 
55
55
  @property
56
56
  def control_baseurl(self):
57
- return "{0}/api/metadata/v1/control".format(self.parent_srv.server_address)
57
+ return f"{self.parent_srv.server_address}/api/metadata/v1/control"
58
58
 
59
59
  @api("3.5")
60
60
  def query(self, query, variables=None, abort_on_error=False, parameters=None):
@@ -8,7 +8,7 @@ from tableauserverclient.models import MetricItem, PaginationItem
8
8
 
9
9
  import logging
10
10
 
11
- from typing import List, Optional, TYPE_CHECKING, Tuple
11
+ from typing import Optional, TYPE_CHECKING
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from ..request_options import RequestOptions
@@ -20,18 +20,18 @@ from tableauserverclient.helpers.logging import logger
20
20
 
21
21
  class Metrics(QuerysetEndpoint[MetricItem]):
22
22
  def __init__(self, parent_srv: "Server") -> None:
23
- super(Metrics, self).__init__(parent_srv)
23
+ super().__init__(parent_srv)
24
24
  self._resource_tagger = _ResourceTagger(parent_srv)
25
25
  self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl)
26
26
  self._data_quality_warnings = _DataQualityWarningEndpoint(self.parent_srv, "metric")
27
27
 
28
28
  @property
29
29
  def baseurl(self) -> str:
30
- return "{0}/sites/{1}/metrics".format(self.parent_srv.baseurl, self.parent_srv.site_id)
30
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/metrics"
31
31
 
32
32
  # Get all metrics
33
33
  @api(version="3.9")
34
- def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[MetricItem], PaginationItem]:
34
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[MetricItem], PaginationItem]:
35
35
  logger.info("Querying all metrics on site")
36
36
  url = self.baseurl
37
37
  server_response = self.get_request(url, req_options)
@@ -45,8 +45,8 @@ class Metrics(QuerysetEndpoint[MetricItem]):
45
45
  if not metric_id:
46
46
  error = "Metric ID undefined."
47
47
  raise ValueError(error)
48
- logger.info("Querying single metric (ID: {0})".format(metric_id))
49
- url = "{0}/{1}".format(self.baseurl, metric_id)
48
+ logger.info(f"Querying single metric (ID: {metric_id})")
49
+ url = f"{self.baseurl}/{metric_id}"
50
50
  server_response = self.get_request(url)
51
51
  return MetricItem.from_response(server_response.content, self.parent_srv.namespace)[0]
52
52
 
@@ -56,9 +56,9 @@ class Metrics(QuerysetEndpoint[MetricItem]):
56
56
  if not metric_id:
57
57
  error = "Metric ID undefined."
58
58
  raise ValueError(error)
59
- url = "{0}/{1}".format(self.baseurl, metric_id)
59
+ url = f"{self.baseurl}/{metric_id}"
60
60
  self.delete_request(url)
61
- logger.info("Deleted single metric (ID: {0})".format(metric_id))
61
+ logger.info(f"Deleted single metric (ID: {metric_id})")
62
62
 
63
63
  # Update metric
64
64
  @api(version="3.9")
@@ -70,8 +70,8 @@ class Metrics(QuerysetEndpoint[MetricItem]):
70
70
  self._resource_tagger.update_tags(self.baseurl, metric_item)
71
71
 
72
72
  # Update the metric itself
73
- url = "{0}/{1}".format(self.baseurl, metric_item.id)
73
+ url = f"{self.baseurl}/{metric_item.id}"
74
74
  update_req = RequestFactory.Metric.update_req(metric_item)
75
75
  server_response = self.put_request(url, update_req)
76
- logger.info("Updated metric item (ID: {0})".format(metric_item.id))
76
+ logger.info(f"Updated metric item (ID: {metric_item.id})")
77
77
  return MetricItem.from_response(server_response.content, self.parent_srv.namespace)[0]
@@ -6,7 +6,7 @@ from tableauserverclient.models import TableauItem, PermissionsRule
6
6
  from .endpoint import Endpoint
7
7
  from .exceptions import MissingRequiredFieldError
8
8
 
9
- from typing import Callable, TYPE_CHECKING, List, Optional, Union
9
+ from typing import Callable, TYPE_CHECKING, Optional, Union
10
10
 
11
11
  from tableauserverclient.helpers.logging import logger
12
12
 
@@ -25,7 +25,7 @@ class _PermissionsEndpoint(Endpoint):
25
25
  """
26
26
 
27
27
  def __init__(self, parent_srv: "Server", owner_baseurl: Callable[[], str]) -> None:
28
- super(_PermissionsEndpoint, self).__init__(parent_srv)
28
+ super().__init__(parent_srv)
29
29
 
30
30
  # owner_baseurl is the baseurl of the parent. The MUST be a lambda
31
31
  # since we don't know the full site URL until we sign in. If
@@ -33,18 +33,18 @@ class _PermissionsEndpoint(Endpoint):
33
33
  self.owner_baseurl = owner_baseurl
34
34
 
35
35
  def __str__(self):
36
- return "<PermissionsEndpoint baseurl={}>".format(self.owner_baseurl)
36
+ return f"<PermissionsEndpoint baseurl={self.owner_baseurl}>"
37
37
 
38
- def update(self, resource: TableauItem, permissions: List[PermissionsRule]) -> List[PermissionsRule]:
39
- url = "{0}/{1}/permissions".format(self.owner_baseurl(), resource.id)
38
+ def update(self, resource: TableauItem, permissions: list[PermissionsRule]) -> list[PermissionsRule]:
39
+ url = f"{self.owner_baseurl()}/{resource.id}/permissions"
40
40
  update_req = RequestFactory.Permission.add_req(permissions)
41
41
  response = self.put_request(url, update_req)
42
42
  permissions = PermissionsRule.from_response(response.content, self.parent_srv.namespace)
43
- logger.info("Updated permissions for resource {0}: {1}".format(resource.id, permissions))
43
+ logger.info(f"Updated permissions for resource {resource.id}: {permissions}")
44
44
 
45
45
  return permissions
46
46
 
47
- def delete(self, resource: TableauItem, rules: Union[PermissionsRule, List[PermissionsRule]]):
47
+ def delete(self, resource: TableauItem, rules: Union[PermissionsRule, list[PermissionsRule]]):
48
48
  # Delete is the only endpoint that doesn't take a list of rules
49
49
  # so let's fake it to keep it consistent
50
50
  # TODO that means we need error handling around the call
@@ -54,7 +54,7 @@ class _PermissionsEndpoint(Endpoint):
54
54
  for rule in rules:
55
55
  for capability, mode in rule.capabilities.items():
56
56
  "/permissions/groups/group-id/capability-name/capability-mode"
57
- url = "{0}/{1}/permissions/{2}/{3}/{4}/{5}".format(
57
+ url = "{}/{}/permissions/{}/{}/{}/{}".format(
58
58
  self.owner_baseurl(),
59
59
  resource.id,
60
60
  rule.grantee.tag_name + "s",
@@ -63,13 +63,11 @@ class _PermissionsEndpoint(Endpoint):
63
63
  mode,
64
64
  )
65
65
 
66
- logger.debug("Removing {0} permission for capability {1}".format(mode, capability))
66
+ logger.debug(f"Removing {mode} permission for capability {capability}")
67
67
 
68
68
  self.delete_request(url)
69
69
 
70
- logger.info(
71
- "Deleted permission for {0} {1} item {2}".format(rule.grantee.tag_name, rule.grantee.id, resource.id)
72
- )
70
+ logger.info(f"Deleted permission for {rule.grantee.tag_name} {rule.grantee.id} item {resource.id}")
73
71
 
74
72
  def populate(self, item: TableauItem):
75
73
  if not item.id:
@@ -80,12 +78,12 @@ class _PermissionsEndpoint(Endpoint):
80
78
  return self._get_permissions(item)
81
79
 
82
80
  item._set_permissions(permission_fetcher)
83
- logger.info("Populated permissions for item (ID: {0})".format(item.id))
81
+ logger.info(f"Populated permissions for item (ID: {item.id})")
84
82
 
85
83
  def _get_permissions(self, item: TableauItem, req_options: Optional["RequestOptions"] = None):
86
- url = "{0}/{1}/permissions".format(self.owner_baseurl(), item.id)
84
+ url = f"{self.owner_baseurl()}/{item.id}/permissions"
87
85
  server_response = self.get_request(url, req_options)
88
86
  permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace)
89
- logger.info("Permissions for resource {0}: {1}".format(item.id, permissions))
87
+ logger.info(f"Permissions for resource {item.id}: {permissions}")
90
88
 
91
89
  return permissions
@@ -5,9 +5,12 @@ from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api,
5
5
  from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
6
6
  from tableauserverclient.server.endpoint.permissions_endpoint import _PermissionsEndpoint
7
7
  from tableauserverclient.server import RequestFactory, RequestOptions
8
+ from tableauserverclient.models.permissions_item import PermissionsRule
8
9
  from tableauserverclient.models import ProjectItem, PaginationItem, Resource
9
10
 
10
- from typing import List, Optional, Tuple, TYPE_CHECKING
11
+ from typing import Optional, TYPE_CHECKING
12
+
13
+ from tableauserverclient.server.query import QuerySet
11
14
 
12
15
  if TYPE_CHECKING:
13
16
  from tableauserverclient.server.server import Server
@@ -18,17 +21,17 @@ from tableauserverclient.helpers.logging import logger
18
21
 
19
22
  class Projects(QuerysetEndpoint[ProjectItem]):
20
23
  def __init__(self, parent_srv: "Server") -> None:
21
- super(Projects, self).__init__(parent_srv)
24
+ super().__init__(parent_srv)
22
25
 
23
26
  self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl)
24
27
  self._default_permissions = _DefaultPermissionsEndpoint(parent_srv, lambda: self.baseurl)
25
28
 
26
29
  @property
27
30
  def baseurl(self) -> str:
28
- return "{0}/sites/{1}/projects".format(self.parent_srv.baseurl, self.parent_srv.site_id)
31
+ return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/projects"
29
32
 
30
33
  @api(version="2.0")
31
- def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[ProjectItem], PaginationItem]:
34
+ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[ProjectItem], PaginationItem]:
32
35
  logger.info("Querying all projects on site")
33
36
  url = self.baseurl
34
37
  server_response = self.get_request(url, req_options)
@@ -41,9 +44,9 @@ class Projects(QuerysetEndpoint[ProjectItem]):
41
44
  if not project_id:
42
45
  error = "Project ID undefined."
43
46
  raise ValueError(error)
44
- url = "{0}/{1}".format(self.baseurl, project_id)
47
+ url = f"{self.baseurl}/{project_id}"
45
48
  self.delete_request(url)
46
- logger.info("Deleted single project (ID: {0})".format(project_id))
49
+ logger.info(f"Deleted single project (ID: {project_id})")
47
50
 
48
51
  @api(version="2.0")
49
52
  def update(self, project_item: ProjectItem, samples: bool = False) -> ProjectItem:
@@ -52,10 +55,10 @@ class Projects(QuerysetEndpoint[ProjectItem]):
52
55
  raise MissingRequiredFieldError(error)
53
56
 
54
57
  params = {"params": {RequestOptions.Field.PublishSamples: samples}}
55
- url = "{0}/{1}".format(self.baseurl, project_item.id)
58
+ url = f"{self.baseurl}/{project_item.id}"
56
59
  update_req = RequestFactory.Project.update_req(project_item)
57
60
  server_response = self.put_request(url, update_req, XML_CONTENT_TYPE, params)
58
- logger.info("Updated project item (ID: {0})".format(project_item.id))
61
+ logger.info(f"Updated project item (ID: {project_item.id})")
59
62
  updated_project = ProjectItem.from_response(server_response.content, self.parent_srv.namespace)[0]
60
63
  return updated_project
61
64
 
@@ -64,11 +67,11 @@ class Projects(QuerysetEndpoint[ProjectItem]):
64
67
  params = {"params": {RequestOptions.Field.PublishSamples: samples}}
65
68
  url = self.baseurl
66
69
  if project_item._samples:
67
- url = "{0}?publishSamples={1}".format(self.baseurl, project_item._samples)
70
+ url = f"{self.baseurl}?publishSamples={project_item._samples}"
68
71
  create_req = RequestFactory.Project.create_req(project_item)
69
72
  server_response = self.post_request(url, create_req, XML_CONTENT_TYPE, params)
70
73
  new_project = ProjectItem.from_response(server_response.content, self.parent_srv.namespace)[0]
71
- logger.info("Created new project (ID: {0})".format(new_project.id))
74
+ logger.info(f"Created new project (ID: {new_project.id})")
72
75
  return new_project
73
76
 
74
77
  @api(version="2.0")
@@ -76,81 +79,172 @@ class Projects(QuerysetEndpoint[ProjectItem]):
76
79
  self._permissions.populate(item)
77
80
 
78
81
  @api(version="2.0")
79
- def update_permissions(self, item, rules):
82
+ def update_permissions(self, item: ProjectItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
80
83
  return self._permissions.update(item, rules)
81
84
 
82
85
  @api(version="2.0")
83
- def delete_permission(self, item, rules):
86
+ def delete_permission(self, item: ProjectItem, rules: list[PermissionsRule]) -> None:
84
87
  self._permissions.delete(item, rules)
85
88
 
86
89
  @api(version="2.1")
87
- def populate_workbook_default_permissions(self, item):
90
+ def populate_workbook_default_permissions(self, item: ProjectItem) -> None:
88
91
  self._default_permissions.populate_default_permissions(item, Resource.Workbook)
89
92
 
90
93
  @api(version="2.1")
91
- def populate_datasource_default_permissions(self, item):
94
+ def populate_datasource_default_permissions(self, item: ProjectItem) -> None:
92
95
  self._default_permissions.populate_default_permissions(item, Resource.Datasource)
93
96
 
94
97
  @api(version="3.2")
95
- def populate_metric_default_permissions(self, item):
98
+ def populate_metric_default_permissions(self, item: ProjectItem) -> None:
96
99
  self._default_permissions.populate_default_permissions(item, Resource.Metric)
97
100
 
98
101
  @api(version="3.4")
99
- def populate_datarole_default_permissions(self, item):
102
+ def populate_datarole_default_permissions(self, item: ProjectItem) -> None:
100
103
  self._default_permissions.populate_default_permissions(item, Resource.Datarole)
101
104
 
102
105
  @api(version="3.4")
103
- def populate_flow_default_permissions(self, item):
106
+ def populate_flow_default_permissions(self, item: ProjectItem) -> None:
104
107
  self._default_permissions.populate_default_permissions(item, Resource.Flow)
105
108
 
106
109
  @api(version="3.4")
107
- def populate_lens_default_permissions(self, item):
110
+ def populate_lens_default_permissions(self, item: ProjectItem) -> None:
108
111
  self._default_permissions.populate_default_permissions(item, Resource.Lens)
109
112
 
113
+ @api(version="3.23")
114
+ def populate_virtualconnection_default_permissions(self, item: ProjectItem) -> None:
115
+ self._default_permissions.populate_default_permissions(item, Resource.VirtualConnection)
116
+
117
+ @api(version="3.23")
118
+ def populate_database_default_permissions(self, item: ProjectItem) -> None:
119
+ self._default_permissions.populate_default_permissions(item, Resource.Database)
120
+
121
+ @api(version="3.23")
122
+ def populate_table_default_permissions(self, item: ProjectItem) -> None:
123
+ self._default_permissions.populate_default_permissions(item, Resource.Table)
124
+
110
125
  @api(version="2.1")
111
- def update_workbook_default_permissions(self, item, rules):
126
+ def update_workbook_default_permissions(
127
+ self, item: ProjectItem, rules: list[PermissionsRule]
128
+ ) -> list[PermissionsRule]:
112
129
  return self._default_permissions.update_default_permissions(item, rules, Resource.Workbook)
113
130
 
114
131
  @api(version="2.1")
115
- def update_datasource_default_permissions(self, item, rules):
132
+ def update_datasource_default_permissions(
133
+ self, item: ProjectItem, rules: list[PermissionsRule]
134
+ ) -> list[PermissionsRule]:
116
135
  return self._default_permissions.update_default_permissions(item, rules, Resource.Datasource)
117
136
 
118
137
  @api(version="3.2")
119
- def update_metric_default_permissions(self, item, rules):
138
+ def update_metric_default_permissions(
139
+ self, item: ProjectItem, rules: list[PermissionsRule]
140
+ ) -> list[PermissionsRule]:
120
141
  return self._default_permissions.update_default_permissions(item, rules, Resource.Metric)
121
142
 
122
143
  @api(version="3.4")
123
- def update_datarole_default_permissions(self, item, rules):
144
+ def update_datarole_default_permissions(
145
+ self, item: ProjectItem, rules: list[PermissionsRule]
146
+ ) -> list[PermissionsRule]:
124
147
  return self._default_permissions.update_default_permissions(item, rules, Resource.Datarole)
125
148
 
126
149
  @api(version="3.4")
127
- def update_flow_default_permissions(self, item, rules):
150
+ def update_flow_default_permissions(self, item: ProjectItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
128
151
  return self._default_permissions.update_default_permissions(item, rules, Resource.Flow)
129
152
 
130
153
  @api(version="3.4")
131
- def update_lens_default_permissions(self, item, rules):
154
+ def update_lens_default_permissions(self, item: ProjectItem, rules: list[PermissionsRule]) -> list[PermissionsRule]:
132
155
  return self._default_permissions.update_default_permissions(item, rules, Resource.Lens)
133
156
 
157
+ @api(version="3.23")
158
+ def update_virtualconnection_default_permissions(
159
+ self, item: ProjectItem, rules: list[PermissionsRule]
160
+ ) -> list[PermissionsRule]:
161
+ return self._default_permissions.update_default_permissions(item, rules, Resource.VirtualConnection)
162
+
163
+ @api(version="3.23")
164
+ def update_database_default_permissions(
165
+ self, item: ProjectItem, rules: list[PermissionsRule]
166
+ ) -> list[PermissionsRule]:
167
+ return self._default_permissions.update_default_permissions(item, rules, Resource.Database)
168
+
169
+ @api(version="3.23")
170
+ def update_table_default_permissions(
171
+ self, item: ProjectItem, rules: list[PermissionsRule]
172
+ ) -> list[PermissionsRule]:
173
+ return self._default_permissions.update_default_permissions(item, rules, Resource.Table)
174
+
134
175
  @api(version="2.1")
135
- def delete_workbook_default_permissions(self, item, rule):
176
+ def delete_workbook_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
136
177
  self._default_permissions.delete_default_permission(item, rule, Resource.Workbook)
137
178
 
138
179
  @api(version="2.1")
139
- def delete_datasource_default_permissions(self, item, rule):
180
+ def delete_datasource_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
140
181
  self._default_permissions.delete_default_permission(item, rule, Resource.Datasource)
141
182
 
142
183
  @api(version="3.2")
143
- def delete_metric_default_permissions(self, item, rule):
184
+ def delete_metric_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
144
185
  self._default_permissions.delete_default_permission(item, rule, Resource.Metric)
145
186
 
146
187
  @api(version="3.4")
147
- def delete_datarole_default_permissions(self, item, rule):
188
+ def delete_datarole_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
148
189
  self._default_permissions.delete_default_permission(item, rule, Resource.Datarole)
149
190
 
150
191
  @api(version="3.4")
151
- def delete_flow_default_permissions(self, item, rule):
192
+ def delete_flow_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
152
193
  self._default_permissions.delete_default_permission(item, rule, Resource.Flow)
153
194
 
154
195
  @api(version="3.4")
155
- def delete_lens_default_permissions(self, item, rule):
196
+ def delete_lens_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
156
197
  self._default_permissions.delete_default_permission(item, rule, Resource.Lens)
198
+
199
+ @api(version="3.23")
200
+ def delete_virtualconnection_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
201
+ self._default_permissions.delete_default_permission(item, rule, Resource.VirtualConnection)
202
+
203
+ @api(version="3.23")
204
+ def delete_database_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
205
+ self._default_permissions.delete_default_permission(item, rule, Resource.Database)
206
+
207
+ @api(version="3.23")
208
+ def delete_table_default_permissions(self, item: ProjectItem, rule: PermissionsRule) -> None:
209
+ self._default_permissions.delete_default_permission(item, rule, Resource.Table)
210
+
211
+ def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[ProjectItem]:
212
+ """
213
+ Queries the Tableau Server for items using the specified filters. Page
214
+ size can be specified to limit the number of items returned in a single
215
+ request. If not specified, the default page size is 100. Page size can
216
+ be an integer between 1 and 1000.
217
+
218
+ No positional arguments are allowed. All filters must be specified as
219
+ keyword arguments. If you use the equality operator, you can specify it
220
+ through <field_name>=<value>. If you want to use a different operator,
221
+ you can specify it through <field_name>__<operator>=<value>. Field
222
+ names can either be in snake_case or camelCase.
223
+
224
+ This endpoint supports the following fields and operators:
225
+
226
+
227
+ created_at=...
228
+ created_at__gt=...
229
+ created_at__gte=...
230
+ created_at__lt=...
231
+ created_at__lte=...
232
+ name=...
233
+ name__in=...
234
+ owner_domain=...
235
+ owner_domain__in=...
236
+ owner_email=...
237
+ owner_email__in=...
238
+ owner_name=...
239
+ owner_name__in=...
240
+ parent_project_id=...
241
+ parent_project_id__in=...
242
+ top_level_project=...
243
+ updated_at=...
244
+ updated_at__gt=...
245
+ updated_at__gte=...
246
+ updated_at__lt=...
247
+ updated_at__lte=...
248
+ """
249
+
250
+ return super().filter(*invalid, page_size=page_size, **kwargs)