diff --git a/tableauserverclient/server/endpoint/custom_views_endpoint.py b/tableauserverclient/server/endpoint/custom_views_endpoint.py
index 8d78dca7..a82f1fa6 100644
--- a/tableauserverclient/server/endpoint/custom_views_endpoint.py
+++ b/tableauserverclient/server/endpoint/custom_views_endpoint.py
@@ -121,7 +121,7 @@ def populate_image(self, view_item: CustomViewItem, req_options: Optional["Image
view_item : CustomViewItem
req_options : ImageRequestOptions, optional
- Options to customize the image returned, by default None
+ Options to customize the image returned, including format (PNG or SVG), by default None
Returns
-------
@@ -139,6 +139,13 @@ def populate_image(self, view_item: CustomViewItem, req_options: Optional["Image
def image_fetcher():
return self._get_view_image(view_item, req_options)
+ if req_options is not None:
+ if not self.parent_srv.check_at_least_version("3.29"):
+ if req_options.format:
+ from tableauserverclient.server.endpoint.exceptions import UnsupportedAttributeError
+
+ raise UnsupportedAttributeError("format parameter is only supported in 3.29+")
+
view_item._set_image(image_fetcher)
logger.info(f"Populated image for custom view (ID: {view_item.id})")
diff --git a/tableauserverclient/server/endpoint/views_endpoint.py b/tableauserverclient/server/endpoint/views_endpoint.py
index 162c0410..b95f3be0 100644
--- a/tableauserverclient/server/endpoint/views_endpoint.py
+++ b/tableauserverclient/server/endpoint/views_endpoint.py
@@ -158,7 +158,7 @@ def populate_image(self, view_item: ViewItem, req_options: Optional["ImageReques
req_options: Optional[ImageRequestOptions], default None
Optional request options for the request. These options can include
- parameters such as image resolution and max age.
+ parameters such as image resolution, max age, and format (PNG or SVG).
Returns
-------
@@ -171,9 +171,13 @@ def populate_image(self, view_item: ViewItem, req_options: Optional["ImageReques
def image_fetcher():
return self._get_view_image(view_item, req_options)
- if not self.parent_srv.check_at_least_version("3.23") and req_options is not None:
- if req_options.viz_height or req_options.viz_width:
- raise UnsupportedAttributeError("viz_height and viz_width are only supported in 3.23+")
+ if req_options is not None:
+ if not self.parent_srv.check_at_least_version("3.23"):
+ if req_options.viz_height or req_options.viz_width:
+ raise UnsupportedAttributeError("viz_height and viz_width are only supported in 3.23+")
+ if not self.parent_srv.check_at_least_version("3.29"):
+ if req_options.format:
+ raise UnsupportedAttributeError("format parameter is only supported in 3.29+")
view_item._set_image(image_fetcher)
logger.info(f"Populated image for view (ID: {view_item.id})")
diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py
index 70c85d14..870435eb 100644
--- a/tableauserverclient/server/request_options.py
+++ b/tableauserverclient/server/request_options.py
@@ -497,6 +497,10 @@ class ImageRequestOptions(_ImagePDFCommonExportOptions):
viz_width: int, optional
The width of the viz in pixels. If specified, viz_height must also be specified.
+ format: str, optional
+ The format of the image to export. Use Format.PNG, Format.SVG, Format.png, or Format.svg.
+ Default is "PNG". Available in API version 3.29+.
+
"""
extension = "png"
@@ -505,14 +509,21 @@ class ImageRequestOptions(_ImagePDFCommonExportOptions):
class Resolution:
High = "high"
- def __init__(self, imageresolution=None, maxage=-1, viz_height=None, viz_width=None):
+ class Format:
+ PNG = "PNG"
+ SVG = "SVG"
+
+ def __init__(self, imageresolution=None, maxage=-1, viz_height=None, viz_width=None, format=None):
super().__init__(maxage=maxage, viz_height=viz_height, viz_width=viz_width)
self.image_resolution = imageresolution
+ self.format = format
def get_query_params(self):
params = super().get_query_params()
if self.image_resolution:
params["resolution"] = self.image_resolution
+ if self.format:
+ params["format"] = self.format
return params
diff --git a/test/test_custom_view.py b/test/test_custom_view.py
index 2a393272..6cbe4b45 100644
--- a/test/test_custom_view.py
+++ b/test/test_custom_view.py
@@ -116,6 +116,54 @@ def test_populate_image_with_options(server: TSC.Server) -> None:
assert response == single_view.image
+def test_populate_image_svg_format(server: TSC.Server) -> None:
+ server.version = "3.29"
+ response = b""
+ with requests_mock.mock() as m:
+ m.get(
+ server.custom_views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=SVG",
+ content=response,
+ )
+ single_view = TSC.CustomViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.SVG)
+ server.custom_views.populate_image(single_view, req_option)
+ assert response == single_view.image
+
+
+def test_populate_image_png_format(server: TSC.Server) -> None:
+ server.version = "3.29"
+ response = POPULATE_PREVIEW_IMAGE.read_bytes()
+ with requests_mock.mock() as m:
+ m.get(
+ server.custom_views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=PNG",
+ content=response,
+ )
+ single_view = TSC.CustomViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.PNG)
+ server.custom_views.populate_image(single_view, req_option)
+ assert response == single_view.image
+
+
+def test_populate_image_format_unsupported_version(server: TSC.Server) -> None:
+ from tableauserverclient.server.endpoint.exceptions import UnsupportedAttributeError
+
+ server.version = "3.28"
+ response = POPULATE_PREVIEW_IMAGE.read_bytes()
+ with requests_mock.mock() as m:
+ m.get(
+ server.custom_views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=SVG",
+ content=response,
+ )
+ single_view = TSC.CustomViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.SVG)
+
+ with pytest.raises(UnsupportedAttributeError):
+ server.custom_views.populate_image(single_view, req_option)
+
+
def test_populate_image_missing_id(server: TSC.Server) -> None:
single_view = TSC.CustomViewItem()
single_view._id = None
diff --git a/test/test_view.py b/test/test_view.py
index b16f47c7..a940e1d1 100644
--- a/test/test_view.py
+++ b/test/test_view.py
@@ -238,6 +238,52 @@ def test_populate_image_with_options(server: TSC.Server) -> None:
assert response == single_view.image
+def test_populate_image_svg_format(server: TSC.Server) -> None:
+ server.version = "3.29"
+ response = b""
+ with requests_mock.mock() as m:
+ m.get(
+ server.views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=SVG",
+ content=response,
+ )
+ single_view = TSC.ViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.SVG)
+ server.views.populate_image(single_view, req_option)
+ assert response == single_view.image
+
+
+def test_populate_image_png_format(server: TSC.Server) -> None:
+ server.version = "3.29"
+ response = POPULATE_PREVIEW_IMAGE.read_bytes()
+ with requests_mock.mock() as m:
+ m.get(
+ server.views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=PNG",
+ content=response,
+ )
+ single_view = TSC.ViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.PNG)
+ server.views.populate_image(single_view, req_option)
+ assert response == single_view.image
+
+
+def test_populate_image_format_unsupported_version(server: TSC.Server) -> None:
+ server.version = "3.28"
+ response = POPULATE_PREVIEW_IMAGE.read_bytes()
+ with requests_mock.mock() as m:
+ m.get(
+ server.views.baseurl + "/d79634e1-6063-4ec9-95ff-50acbf609ff5/image?format=SVG",
+ content=response,
+ )
+ single_view = TSC.ViewItem()
+ single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
+ req_option = TSC.ImageRequestOptions(format=TSC.ImageRequestOptions.Format.SVG)
+
+ with pytest.raises(UnsupportedAttributeError):
+ server.views.populate_image(single_view, req_option)
+
+
def test_populate_pdf(server: TSC.Server) -> None:
response = POPULATE_PDF.read_bytes()
with requests_mock.mock() as m: