8000 Merge branch 'development' into jorwoods/wb_tags · Der-Henning/server-client-python@5d6e25c · GitHub
[go: up one dir, main page]

Skip to content

Commit 5d6e25c

Browse files
authored
Merge branch 'development' into jorwoods/wb_tags
2 parents cf7bce7 + a3028d7 commit 5d6e25c

15 files changed

+798
-6
lines changed

tableauserverclient/server/endpoint/custom_views_endpoint.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import io
12
import logging
2-
from typing import List, Optional, Tuple
3-
4-
from .endpoint import QuerysetEndpoint, api
5-
from .exceptions import MissingRequiredFieldError
3+
import os
4+
from pathlib import Path
5+
from typing import List, Optional, Tuple, Union
6+
7+
from tableauserverclient.config import BYTES_PER_MB, FILESIZE_LIMIT_MB
8+
from tableauserverclient.filesys_helpers import get_file_object_size
9+
from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api
10+
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
611
from tableauserverclient.models import CustomViewItem, PaginationItem
712
from tableauserverclient.server import RequestFactory, RequestOptions, ImageRequestOptions
813

@@ -16,6 +21,15 @@
1621
update the name or owner of a custom view.
1722
"""
1823

24+
FilePath = Union[str, os.PathLike]
25+
FileObject = Union[io.BufferedReader, io.BytesIO]
26+
FileObjectR = Union[io.BufferedReader, io.BytesIO]
27+
FileObjectW = Union[io.BufferedWriter, io.BytesIO]
28+
PathOrFileR = Union[FilePath, FileObjectR]
29+
PathOrFileW = Union[FilePath, FileObjectW]
30+
io_types_r = (io.BufferedReader, io.BytesIO)
31+
io_types_w = (io.BufferedWriter, io.BytesIO)
32+
1933

2034
class CustomViews(QuerysetEndpoint[CustomViewItem]):
2135
def __init__(self, parent_srv):
@@ -25,6 +39,10 @@ def __init__(self, parent_srv):
2539
def baseurl(self) -> str:
2640
return "{0}/sites/{1}/customviews".format(self.parent_srv.baseurl, self.parent_srv.site_id)
2741

42+
@property
43+
def expurl(self) -> str:
44+
return f"{self.parent_srv._server_address}/api/exp/sites/{self.parent_srv.site_id}/customviews"
45+
2846
"""
2947
If the request has no filter parameters: Administrators will see all custom views.
3048
Other users will see only custom views that they own.
@@ -102,3 +120,46 @@ def delete(self, view_id: str) -> None:
102120
url = "{0}/{1}".format(self.baseurl, view_id)
103121
self.delete_request(url)
104122
logger.info("Deleted single custom view (ID: {0})".format(view_id))
123+
124+
@api(version="3.21")
125+
def download(self, view_item: CustomViewItem, file: PathOrFileW) -> PathOrFileW:
126+
url = f"{self.expurl}/{view_item.id}/content"
127+
server_response = self.get_request(url)
128+
if isinstance(file, io_types_w):
129+
file.write(server_response.content)
130+
return file
131+
132+
with open(file, "wb") as f:
133+
f.write(server_response.content)
134+
135+
return file
136+
137+
@api(version="3.21")
138+
def publish(self, view_item: CustomViewItem, file: PathOrFileR) -> Optional[CustomViewItem]:
139+
url = self.expurl
140+
if isinstance(file, io_types_r):
141+
size = get_file_object_size(file)
142+
elif isinstance(file, (str, Path)) and (p := Path(file)).is_file():
143+
size = p.stat().st_size
144+
else:
145+
raise ValueError("File path or file object required for publishing custom view.")
146+
147+
if size >= FILESIZE_LIMIT_MB * BYTES_PER_MB:
148+
upload_session_id = self.parent_srv.fileuploads.upload(file)
149+
url = f"{url}?uploadSessionId={upload_session_id}"
150+
xml_request, content_type = RequestFactory.CustomView.publish_req_chunked(view_item)
151+
else:
152+
if isinstance(file, io_types_r):
153+
file.seek(0)
154+
contents = file.read()
155+
if view_item.name is None:
156+
raise MissingRequiredFieldError("Custom view item missing name.")
157+
filename = view_item.name
158+
elif isinstance(file, (str, Path)):
159+
filename = Path(file).name
160+
contents = Path(file).read_bytes()
161+
162+
xml_request, content_type = RequestFactory.CustomView.publish_req(view_item, filename, contents)
163+
164+
server_response = self.post_request(url, xml_request, content_type)
165+
return CustomViewItem.from_response(server_response.content, self.parent_srv.namespace)

tableauserverclient/server/endpoint/datasources_endpoint.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import Iterable, List, Mapping, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union
1010

1111
from tableauserverclient.helpers.headers import fix_filename
12+
from tableauserverclient.server.query import QuerySet
1213

1314
if TYPE_CHECKING:
1415
from tableauserverclient.server import Server
@@ -459,6 +460,7 @@ def schedule_extract_refresh(
459460
) -> List["AddResponse"]: # actually should return a task
460461
return self.parent_srv.schedules.add_to_schedule(schedule_id, datasource=item)
461462

463+
462464
@api(version="1.0")
463465
def add_tags(self, item: Union[DatasourceItem, str], tags: Union[Iterable[str], str]) -> Set[str]:
464466
return super().add_tags(item, tags)
@@ -470,3 +472,87 @@ def delete_tags(self, item: Union[DatasourceItem, str], tags: Union[Iterable[str
470472
@api(version="1.0")
471473
def update_tags(self, item: DatasourceItem) -> None:
472474
return super().update_tags(item)
475+
476+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[DatasourceItem]:
477+
"""
478+
Queries the Tableau Server for items using the specified filters. Page
479+
size can be specified to limit the number of items returned in a single
480+
request. If not specified, the default page size is 100. Page size can
481+
be an integer between 1 and 1000.
482+
483+
No positional arguments are allowed. All filters must be specified as
484+
keyword arguments. If you use the equality operator, you can specify it
485+
through <field_name>=<value>. If you want to use a different operator,
486+
you can specify it through <field_name>__<operator>=<value>. Field
487+
names can either be in snake_case or camelCase.
488+
489+
This endpoint supports the following fields and operators:
490+
491+
492+
authentication_type=...
493+
authentication_type__in=...
494+
connected_workbook_type=...
495+
connected_workbook_type__gt=...
496+
connected_workbook_type__gte=...
497+
connected_workbook_type__lt=...
498+
connected_workbook_type__lte=...
499+
connection_to=...
500+
connection_to__in=...
501+
connection_type=...
502+
connection_type__in=...
503+
content_url=...
504+
content_url__in=...
505+
created_at=...
506+
created_at__gt=...
507+
created_at__gte=...
508+
created_at__lt=...
509+
created_at__lte=...
510+
database_name=...
511+
database_name__in=...
512+
database_user_name=...
513+
database_user_name__in=...
514+
description=...
515+
description__in=...
516+
favorites_total=...
517+
favorites_total__gt=...
518+
favorites_total__gte=...
519+
favorites_total__lt=...
520+
favorites_total__lte=...
521+
has_alert=...
522+
has_embedded_password=...
523+
has_extracts=...
524+
is_certified=...
525+
is_connectable=...
526+
is_default_port=...
527+
is_hierarchical=...
528+
is_published=...
529+
name=...
530+
name__in=...
531+
owner_domain=...
532+
owner_domain__in=...
533+
owner_email=...
534+
owner_name=...
535+
owner_name__in=...
536+
project_name=...
537+
project_name__in=...
538+
server_name=...
539+
server_name__in=...
540+
server_port=...
541+
size=...
542+
size__gt=...
543+
size__gte=...
544+
size__lt=...
545+
size__lte=...
546+
table_name=...
547+
table_name__in=...
548+
tags=...
549+
tags__in=...
550+
type=...
551+
updated_at=...
552+
updated_at__gt=...
553+
updated_at__gte=...
554+
updated_at__lt=...
555+
updated_at__lte=...
556+
"""
557+
558+
return super().filter(*invalid, page_size=page_size, **kwargs)

tableauserverclient/server/endpoint/flow_runs_endpoint.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from tableauserverclient.exponential_backoff import ExponentialBackoffTimer
88

99
from tableauserverclient.helpers.logging import logger
10+
from tableauserverclient.server.query import QuerySet
1011

1112
if TYPE_CHECKING:
1213
from tableauserverclient.server.server import Server
@@ -78,3 +79,42 @@ def wait_for_job(self, flow_run_id: str, *, timeout: Optional[int] = None) -> Fl
7879
raise FlowRunCancelledException(flow_run)
7980
else:
8081
raise AssertionError("Unexpected status in flow_run", flow_run)
82+
83+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[FlowRunItem]:
84+
"""
85+
Queries the Tableau Server for items using the specified filters. Page
86+
size can be specified to limit the number of items returned in a single
87+
request. If not specified, the default page size is 100. Page size can
88+
be an integer between 1 and 1000.
89+
90+
No positional arguments are allowed. All filters must be specified as
91+
keyword arguments. If you use the equality operator, you can specify it
92+
through <field_name>=<value>. If you want to use a different operator,
93+
you can specify it through <field_name>__<operator>=<value>. Field
94+
names can either be in snake_case or camelCase.
95+
96+
This endpoint supports the following fields and operators:
97+
98+
99+
complete_at=...
100+
complete_at__gt=...
101+
complete_at__gte=...
102+
complete_at__lt=...
103+
complete_at__lte=...
104+
flow_id=...
105+
flow_id__in=...
106+
progress=...
107+
progress__gt=...
108+
progress__gte=...
109+
progress__lt=...
110+
progress__lte=...
111+
started_at=...
112+
started_at__gt=...
113+
started_at__gte=...
114+
started_at__lt=...
115+
started_at__lte=...
116+
user_id=...
117+
user_id__in=...
118+
"""
119+
120+
return super().filter(*invalid, page_size=page_size, **kwargs)

tableauserverclient/server/endpoint/flows_endpoint.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
get_file_type,
2323
get_file_object_size,
2424
)
25+
from tableauserverclient.server.query import QuerySet
2526

2627
io_types_r = (io.BytesIO, io.BufferedReader)
2728
io_types_w = (io.BytesIO, io.BufferedWriter)
@@ -295,3 +296,39 @@ def schedule_flow_run(
295296
self, schedule_id: str, item: FlowItem
296297
) -> List["AddResponse"]: # actually should return a task
297298
return self.parent_srv.schedules.add_to_schedule(schedule_id, flow=item)
299+
300+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[FlowItem]:
301+
"""
302+
Queries the Tableau Server for items using the specified filters. Page
303+
size can be specified to limit the number of items returned in a single
304+
request. If not specified, the default page size is 100. Page size can
305+
be an integer between 1 and 1000.
306+
307+
No positional arguments are allowed. All filters must be specified as
308+
keyword arguments. If you use the equality operator, you can specify it
309+
through <field_name>=<value>. If you want to use a different operator,
310+
you can specify it through <field_name>__<operator>=<value>. Field
311+
names can either be in snake_case or camelCase.
312+
313+
This endpoint supports the following fields and operators:
314+
315+
316+
created_at=...
317+
created_at__gt=...
318+
created_at__gte=...
319+
created_at__lt=...
320+
created_at__lte=...
321+
name=...
322+
name__in=...
323+
owner_name=...
324+
project_id=...
325+
project_name=...
326+
project_name__in=...
327+
updated=...
328+
updated__gt=...
329+
updated__gte=...
330+
updated__lt=...
331+
updated__lte=...
332+
"""
333+
334+
return super().filter(*invalid, page_size=page_size, **kwargs)

tableauserverclient/server/endpoint/groups_endpoint.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
from typing import Iterable, List, Optional, TYPE_CHECKING, Tuple, Union
1212

13+
from tableauserverclient.server.query import QuerySet
14+
1315
if TYPE_CHECKING:
1416
from tableauserverclient.server.request_options import RequestOptions
1517

@@ -162,3 +164,42 @@ def add_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]
162164
users = UserItem.from_response(server_response.content, self.parent_srv.namespace)
163165
logger.info("Added users to group (ID: {0})".format(group_item.id))
164166
return users
167+
168+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[GroupItem]:
169+
"""
170+
Queries the Tableau Server for items using the specified filters. Page
171+
size can be specified to limit the number of items returned in a single
172+
request. If not specified, the default page size is 100. Page size can
173+
be an integer between 1 and 1000.
174+
175+
No positional arguments are allowed. All filters must be specified as
176+
keyword arguments. If you use the equality operator, you can specify it
177+
through <field_name>=<value>. If you want to use a different operator,
178+
you can specify it through <field_name>__<operator>=<value>. Field
179+
names can either be in snake_case or camelCase.
180+
181+
This endpoint supports the following fields and operators:
182+
183+
184+
domain_name=...
185+
domain_name__in=...
186+
domain_nickname=...
187+
domain_nickname__in=...
188+
is_external_user_enabled=...
189+
is_local=...
190+
luid=...
191+
luid__in=...
192+
minimum_site_role=...
193+
minimum_site_role__in=...
194+
name__cieq=...
195+
name=...
196+
name__in=...
197+
name__like=...
198+
user_count=...
199+
user_count__gt=...
200+
user_count__gte=...
201+
user_count__lt=...
202+
user_count__lte=...
203+
"""
204+
205+
return super().filter(*invalid, page_size=page_size, **kwargs)

tableauserverclient/server/endpoint/groupsets_endpoint.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from tableauserverclient.models.groupset_item import GroupSetItem
66
from tableauserverclient.models.pagination_item import PaginationItem
77
from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint
8+
from tableauserverclient.server.query import QuerySet
89
from tableauserverclient.server.request_options import RequestOptions
910
from tableauserverclient.server.request_factory import RequestFactory
1011
from tableauserverclient.server.endpoint.endpoint import api
@@ -85,3 +86,42 @@ def update(self, groupset: GroupSetItem) -> GroupSetItem:
8586
server_response = self.put_request(url, request)
8687
updated_groupset = GroupSetItem.from_response(server_response.content, self.parent_srv.namespace)
8788
return updated_groupset[0]
89+
90+
def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[GroupSetItem]:
91+
"""
92+
Queries the Tableau Server for items using the specified filters. Page
93+
size can be specified to limit the number of items returned in a single
94+
request. If not specified, the default page size is 100. Page size can
95+
be an integer between 1 and 1000.
96+
97+
No positional arguments are allowed. All filters must be specified as
98+
keyword arguments. If you use the equality operator, you can specify it
99+
through <field_name>=<value>. If you want to use a different operator,
100+
you can specify it through <field_name>__<operator>=<value>. Field
101+
names can either be in snake_case or camelCase.
102+
103+
This endpoint supports the following fields and operators:
104+
105+
106+
domain_name=...
107+
domain_name__in=...
108+
domain_nickname=...
109+
domain_nickname__in=...
110+
is_external_user_enabled=...
111+
is_local=...
112+
luid=...
113+
luid__in=...
114+
minimum_site_role=...
115+
minimum_site_role__in=...
116+
name__cieq=...
117+
name=...
118+
name__in=...
119+
name__like=...
120+
user_count=...
121+
user_count__gt=...
122+
user_count__gte=...
123+
user_count__lt=...
124+
user_count__lte=...
125+
"""
126+
127+
return super().filter(*invalid, page_size=page_size, **kwargs)

0 commit comments

Comments
 (0)
0