Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions tableauserverclient/models/property_decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import re
from functools import wraps
from typing import Any, Container, Optional, Tuple

from tableauserverclient.datetime_helpers import parse_datetime

Expand Down Expand Up @@ -65,7 +66,7 @@ def wrapper(self, value):
return wrapper


def property_is_int(range, allowed=None):
def property_is_int(range: Tuple[int, int], allowed: Optional[Container[Any]] = None):
"""Takes a range of ints and a list of exemptions to check against
when setting a property on a model. The range is a tuple of (min, max) and the
allowed list (empty by default) allows values outside that range.
Expand All @@ -89,8 +90,10 @@ def wrapper(self, value):
raise ValueError(error)

min, max = range
if value in allowed:
return func(self, value)

if (value < min or value > max) and (value not in allowed):
if value < min or value > max:
raise ValueError(error)

return func(self, value)
Expand Down
34 changes: 33 additions & 1 deletion tableauserverclient/server/request_options.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

from tableauserverclient.models.property_decorators import property_is_int
import logging

Expand Down Expand Up @@ -261,11 +263,13 @@ class Orientation:
Portrait = "portrait"
Landscape = "landscape"

def __init__(self, page_type=None, orientation=None, maxage=-1):
def __init__(self, page_type=None, orientation=None, maxage=-1, viz_height=None, viz_width=None):
super(PDFRequestOptions, self).__init__()
self.page_type = page_type
self.orientation = orientation
self.max_age = maxage
self.viz_height = viz_height
self.viz_width = viz_width

@property
def max_age(self):
Expand All @@ -276,6 +280,24 @@ def max_age(self):
def max_age(self, value):
self._max_age = value

@property
def viz_height(self):
return self._viz_height

@viz_height.setter
@property_is_int(range=(0, sys.maxsize), allowed=(None,))
def viz_height(self, value):
self._viz_height = value

@property
def viz_width(self):
return self._viz_width

@viz_width.setter
@property_is_int(range=(0, sys.maxsize), allowed=(None,))
def viz_width(self, value):
self._viz_width = value

def get_query_params(self):
params = {}
if self.page_type:
Expand All @@ -287,6 +309,16 @@ def get_query_params(self):
if self.max_age != -1:
params["maxAge"] = self.max_age

# XOR. Either both are None or both are not None.
if (self.viz_height is None) ^ (self.viz_width is None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this operator is unusual enough that a comment would be helpful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment.

raise ValueError("viz_height and viz_width must be specified together")

if self.viz_height is not None:
params["vizHeight"] = self.viz_height

if self.viz_width is not None:
params["vizWidth"] = self.viz_width

self._append_view_filters(params)

return params
29 changes: 29 additions & 0 deletions test/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,32 @@ def test_filter_excel(self) -> None:

excel_file = b"".join(single_view.excel)
self.assertEqual(response, excel_file)

def test_pdf_height(self) -> None:
self.server.version = "3.8"
self.baseurl = self.server.views.baseurl
with open(POPULATE_PDF, "rb") as f:
response = f.read()
with requests_mock.mock() as m:
m.get(
self.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/pdf?vizHeight=1080&vizWidth=1920",
content=response,
)
single_view = TSC.ViewItem()
single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"

req_option = TSC.PDFRequestOptions(
viz_height=1080,
viz_width=1920,
)

self.server.views.populate_pdf(single_view, req_option)
self.assertEqual(response, single_view.pdf)

def test_pdf_errors(self) -> None:
req_option = TSC.PDFRequestOptions(viz_height=1080)
with self.assertRaises(ValueError):
req_option.get_query_params()
req_option = TSC.PDFRequestOptions(viz_width=1920)
with self.assertRaises(ValueError):
req_option.get_query_params()