Skip to content

Commit ba716b9

Browse files
authored
fix: remove vizHeight and vizWidth from ImageRequestOptions (#1565)
feat: properly support request option filters Many filters and RequestOptions added in 3.23. Adds explicit support for them and checks for prior versions. Co-authored-by: Jordan Woods <[email protected]>
1 parent e39dbcb commit ba716b9

File tree

8 files changed

+156
-13
lines changed

8 files changed

+156
-13
lines changed

Diff for: tableauserverclient/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
ExcelRequestOptions,
5757
ImageRequestOptions,
5858
PDFRequestOptions,
59+
PPTXRequestOptions,
5960
RequestOptions,
6061
MissingRequiredFieldError,
6162
FailedSignInError,
@@ -107,6 +108,7 @@
107108
"Pager",
108109
"PaginationItem",
109110
"PDFRequestOptions",
111+
"PPTXRequestOptions",
110112
"Permission",
111113
"PermissionsRule",
112114
"PersonalAccessTokenAuth",

Diff for: tableauserverclient/server/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
ExcelRequestOptions,
66
ImageRequestOptions,
77
PDFRequestOptions,
8+
PPTXRequestOptions,
89
RequestOptions,
910
)
1011
from tableauserverclient.server.filter import Filter
@@ -52,6 +53,7 @@
5253
"ExcelRequestOptions",
5354
"ImageRequestOptions",
5455
"PDFRequestOptions",
56+
"PPTXRequestOptions",
5557
"RequestOptions",
5658
"Filter",
5759
"Sort",

Diff for: tableauserverclient/server/endpoint/exceptions.py

+4
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,7 @@ def __str__(self):
113113

114114
class FlowRunCancelledException(FlowRunFailedException):
115115
pass
116+
117+
118+
class UnsupportedAttributeError(TableauError):
119+
pass

Diff for: tableauserverclient/server/endpoint/views_endpoint.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from tableauserverclient.models.permissions_item import PermissionsRule
55
from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api
6-
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError
6+
from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError, UnsupportedAttributeError
77
from tableauserverclient.server.endpoint.permissions_endpoint import _PermissionsEndpoint
88
from tableauserverclient.server.endpoint.resource_tagger import TaggingMixin
99
from tableauserverclient.server.query import QuerySet
@@ -171,6 +171,10 @@ def populate_image(self, view_item: ViewItem, req_options: Optional["ImageReques
171171
def image_fetcher():
172172
return self._get_view_image(view_item, req_options)
173173

174+
if not self.parent_srv.check_at_least_version("3.23") and req_options is not None:
175+
if req_options.viz_height or req_options.viz_width:
176+
raise UnsupportedAttributeError("viz_height and viz_width are only supported in 3.23+")
177+
174178
view_item._set_image(image_fetcher)
175179
logger.info(f"Populated image for view (ID: {view_item.id})")
176180

Diff for: tableauserverclient/server/endpoint/workbooks_endpoint.py

+23-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from tableauserverclient.server.query import QuerySet
1212

1313
from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api, parameter_added_in
14-
from tableauserverclient.server.endpoint.exceptions import InternalServerError, MissingRequiredFieldError
14+
from tableauserverclient.server.endpoint.exceptions import (
15+
InternalServerError,
16+
MissingRequiredFieldError,
17+
UnsupportedAttributeError,
18+
)
1519
from tableauserverclient.server.endpoint.permissions_endpoint import _PermissionsEndpoint
1620
from tableauserverclient.server.endpoint.resource_tagger import TaggingMixin
1721

@@ -34,7 +38,7 @@
3438

3539
if TYPE_CHECKING:
3640
from tableauserverclient.server import Server
37-
from tableauserverclient.server.request_options import RequestOptions
41+
from tableauserverclient.server.request_options import RequestOptions, PDFRequestOptions, PPTXRequestOptions
3842
from tableauserverclient.models import DatasourceItem
3943
from tableauserverclient.server.endpoint.schedules_endpoint import AddResponse
4044

@@ -472,11 +476,12 @@ def _get_workbook_connections(
472476
connections = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)
473477
return connections
474478

475-
# Get the pdf of the entire workbook if its tabs are enabled, pdf of the default view if its tabs are disabled
476479
@api(version="3.4")
477-
def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None:
480+
def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["PDFRequestOptions"] = None) -> None:
478481
"""
479-
Populates the PDF for the specified workbook item.
482+
Populates the PDF for the specified workbook item. Get the pdf of the
483+
entire workbook if its tabs are enabled, pdf of the default view if its
484+
tabs are disabled.
480485
481486
This method populates a PDF with image(s) of the workbook view(s) you
482487
specify.
@@ -488,7 +493,7 @@ def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["Reque
488493
workbook_item : WorkbookItem
489494
The workbook item to populate the PDF for.
490495
491-
req_options : RequestOptions, optional
496+
req_options : PDFRequestOptions, optional
492497
(Optional) You can pass in request options to specify the page type
493498
and orientation of the PDF content, as well as the maximum age of
494499
the PDF rendered on the server. See PDFRequestOptions class for more
@@ -510,17 +515,26 @@ def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["Reque
510515
def pdf_fetcher() -> bytes:
511516
return self._get_wb_pdf(workbook_item, req_options)
512517

518+
if not self.parent_srv.check_at_least_version("3.23") and req_options is not None:
519+
if req_options.view_filters or req_options.view_parameters:
520+
raise UnsupportedAttributeError("view_filters and view_parameters are only supported in 3.23+")
521+
522+
if req_options.viz_height or req_options.viz_width:
523+
raise UnsupportedAttributeError("viz_height and viz_width are only supported in 3.23+")
524+
513525
workbook_item._set_pdf(pdf_fetcher)
514526
logger.info(f"Populated pdf for workbook (ID: {workbook_item.id})")
515527

516-
def _get_wb_pdf(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"]) -> bytes:
528+
def _get_wb_pdf(self, workbook_item: WorkbookItem, req_options: Optional["PDFRequestOptions"]) -> bytes:
517529
url = f"{self.baseurl}/{workbook_item.id}/pdf"
518530
server_response = self.get_request(url, req_options)
519531
pdf = server_response.content
520532
return pdf
521533

522534
@api(version="3.8")
523-
def populate_powerpoint(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None:
535+
def populate_powerpoint(
536+
self, workbook_item: WorkbookItem, req_options: Optional["PPTXRequestOptions"] = None
537+
) -> None:
524538
"""
525539
Populates the PowerPoint for the specified workbook item.
526540
@@ -561,7 +575,7 @@ def pptx_fetcher() -> bytes:
561575
workbook_item._set_powerpoint(pptx_fetcher)
562576
logger.info(f"Populated powerpoint for workbook (ID: {workbook_item.id})")
563577

564-
def _get_wb_pptx(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"]) -> bytes:
578+
def _get_wb_pptx(self, workbook_item: WorkbookItem, req_options: Optional["PPTXRequestOptions"]) -> bytes:
565579
url = f"{self.baseurl}/{workbook_item.id}/powerpoint"
566580
server_response = self.get_request(url, req_options)
567581
pptx = server_response.content

Diff for: tableauserverclient/server/request_options.py

+34
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ class PDFRequestOptions(_ImagePDFCommonExportOptions):
385385
Options that can be used when exporting a view to PDF. Set the maxage to control the age of the data exported.
386386
Filters to the underlying data can be applied using the `vf` and `parameter` methods.
387387
388+
vf and parameter filters are only supported in API version 3.23 and later.
389+
388390
Parameters
389391
----------
390392
page_type: str, optional
@@ -438,3 +440,35 @@ def get_query_params(self) -> dict:
438440
params["orientation"] = self.orientation
439441

440442
return params
443+
444+
445+
class PPTXRequestOptions(RequestOptionsBase):
446+
"""
447+
Options that can be used when exporting a view to PPTX. Set the maxage to control the age of the data exported.
448+
449+
Parameters
450+
----------
451+
maxage: int, optional
452+
The maximum age of the data to export. Shortest possible duration is 1
453+
minute. No upper limit. Default is -1, which means no limit.
454+
"""
455+
456+
def __init__(self, maxage=-1):
457+
super().__init__()
458+
self.max_age = maxage
459+
460+
@property
461+
def max_age(self) -> int:
462+
return self._max_age
463+
464+
@max_age.setter
465+
@property_is_int(range=(0, 240), allowed=[-1])
466+
def max_age(self, value):
467+
self._max_age = value
468+
469+
def get_query_params(self):
470+
params = {}
471+
if self.max_age != -1:
472+
params["maxAge"] = self.max_age
473+
474+
return params

Diff for: test/test_view.py

+38
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import tableauserverclient as TSC
77
from tableauserverclient import UserItem, GroupItem, PermissionsRule
88
from tableauserverclient.datetime_helpers import format_datetime
9+
from tableauserverclient.server.endpoint.exceptions import UnsupportedAttributeError
910

1011
TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), "assets")
1112

@@ -177,6 +178,43 @@ def test_populate_image(self) -> None:
177178
self.server.views.populate_image(single_view)
178179
self.assertEqual(response, single_view.image)
179180

181+
def test_populate_image_unsupported(self) -> None:
182+
self.server.version = "3.8"
183+
with open(POPULATE_PREVIEW_IMAGE, "rb") as f:
184+
response = f.read()
185+
with requests_mock.mock() as m:
186+
m.get(
187+
self.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?vizWidth=1920&vizHeight=1080",
188+
content=response,
189+
)
190+
single_view = TSC.ViewItem()
191+
single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
192+
193+
req_option = TSC.ImageRequestOptions(viz_width=1920, viz_height=1080)
194+
195+
with self.assertRaises(UnsupportedAttributeError):
196+
self.server.views.populate_image(single_view, req_option)
197+
198+
def test_populate_image_viz_dimensions(self) -> None:
199+
self.server.version = "3.23"
200+
self.baseurl = self.server.views.baseurl
201+
with open(POPULATE_PREVIEW_IMAGE, "rb") as f:
202+
response = f.read()
203+
with requests_mock.mock() as m:
204+
m.get(
205+
self.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?vizWidth=1920&vizHeight=1080",
206+
content=response,
207+
)
208+
single_view = TSC.ViewItem()
209+
single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
210+
211+
req_option = TSC.ImageRequestOptions(viz_width=1920, viz_height=1080)
212+
213+
self.server.views.populate_image(single_view, req_option)
214+
self.assertEqual(response, single_view.image)
215+
216+
history = m.request_history
217+
180218
def test_populate_image_with_options(self) -> None:
181219
with open(POPULATE_PREVIEW_IMAGE, "rb") as f:
182220
response = f.read()

Diff for: test/test_workbook.py

+48-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import tableauserverclient as TSC
1313
from tableauserverclient.datetime_helpers import format_datetime
1414
from tableauserverclient.models import UserItem, GroupItem, PermissionsRule
15-
from tableauserverclient.server.endpoint.exceptions import InternalServerError
15+
from tableauserverclient.server.endpoint.exceptions import InternalServerError, UnsupportedAttributeError
1616
from tableauserverclient.server.request_factory import RequestFactory
1717
from ._utils import asset
1818

@@ -450,20 +450,65 @@ def test_populate_pdf(self) -> None:
450450
self.server.workbooks.populate_pdf(single_workbook, req_option)
451451
self.assertEqual(response, single_workbook.pdf)
452452

453+
def test_populate_pdf_unsupported(self) -> None:
454+
self.server.version = "3.4"
455+
self.baseurl = self.server.workbooks.baseurl
456+
with requests_mock.mock() as m:
457+
m.get(
458+
self.baseurl + "/1f951daf-4061-451a-9df1-69a8062664f2/pdf?type=a5&orientation=landscape",
459+
content=b"",
460+
)
461+
single_workbook = TSC.WorkbookItem("test")
462+
single_workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2"
463+
464+
type = TSC.PDFRequestOptions.PageType.A5
465+
orientation = TSC.PDFRequestOptions.Orientation.Landscape
466+
req_option = TSC.PDFRequestOptions(type, orientation)
467+
req_option.vf("Region", "West")
468+
469+
with self.assertRaises(UnsupportedAttributeError):
470+
self.server.workbooks.populate_pdf(single_workbook, req_option)
471+
472+
def test_populate_pdf_vf_dims(self) -> None:
473+
self.server.version = "3.23"
474+
self.baseurl = self.server.workbooks.baseurl
475+
with open(POPULATE_PDF, "rb") as f:
476+
response = f.read()
477+
with requests_mock.mock() as m:
478+
m.get(
479+
self.baseurl
480+
+ "/1f951daf-4061-451a-9df1-69a8062664f2/pdf?type=a5&orientation=landscape&vf_Region=West&vizWidth=1920&vizHeight=1080",
481+
content=response,
482+
)
483+
single_workbook = TSC.WorkbookItem("test")
484+
single_workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2"
485+
486+
type = TSC.PDFRequestOptions.PageType.A5
487+
orientation = TSC.PDFRequestOptions.Orientation.Landscape
488+
req_option = TSC.PDFRequestOptions(type, orientation)
489+
req_option.vf("Region", "West")
490+
req_option.viz_width = 1920
491+
req_option.viz_height = 1080
492+
493+
self.server.workbooks.populate_pdf(single_workbook, req_option)
494+
self.assertEqual(response, single_workbook.pdf)
495+
453496
def test_populate_powerpoint(self) -> None:
454497
self.server.version = "3.8"
455498
self.baseurl = self.server.workbooks.baseurl
456499
with open(POPULATE_POWERPOINT, "rb") as f:
457500
response = f.read()
458501
with requests_mock.mock() as m:
459502
m.get(
460-
self.baseurl + "/1f951daf-4061-451a-9df1-69a8062664f2/powerpoint",
503+
self.baseurl + "/1f951daf-4061-451a-9df1-69a8062664f2/powerpoint?maxAge=1",
461504
content=response,
462505
)
463506
single_workbook = TSC.WorkbookItem("test")
464507
single_workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2"
465508

466-
self.server.workbooks.populate_powerpoint(single_workbook)
509+
ro = TSC.PPTXRequestOptions(maxage=1)
510+
511+
self.server.workbooks.populate_powerpoint(single_workbook, ro)
467512
self.assertEqual(response, single_workbook.powerpoint)
468513

469514
def test_populate_preview_image(self) -> None:

0 commit comments

Comments
 (0)